Patch #1731049: make threading.py use a proper "raise" when checking internal state, rather than assert statements (which get stripped out by -O).
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index 8614ecb..dced9cb 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -3,6 +3,7 @@
import test.test_support
from test.test_support import verbose
import random
+import sys
import threading
import thread
import time
@@ -201,8 +202,47 @@
t.join()
# else the thread is still running, and we have no way to kill it
+class ThreadingExceptionTests(unittest.TestCase):
+ # A RuntimeError should be raised if Thread.start() is called
+ # multiple times.
+ def test_start_thread_again(self):
+ thread = threading.Thread()
+ thread.start()
+ self.assertRaises(RuntimeError, thread.start)
+
+ def test_releasing_unacquired_rlock(self):
+ rlock = threading.RLock()
+ self.assertRaises(RuntimeError, rlock.release)
+
+ def test_waiting_on_unacquired_condition(self):
+ cond = threading.Condition()
+ self.assertRaises(RuntimeError, cond.wait)
+
+ def test_notify_on_unacquired_condition(self):
+ cond = threading.Condition()
+ self.assertRaises(RuntimeError, cond.notify)
+
+ def test_semaphore_with_negative_value(self):
+ self.assertRaises(ValueError, threading.Semaphore, value = -1)
+ self.assertRaises(ValueError, threading.Semaphore, value = -sys.maxint)
+
+ def test_joining_current_thread(self):
+ currentThread = threading.currentThread()
+ self.assertRaises(RuntimeError, currentThread.join);
+
+ def test_joining_inactive_thread(self):
+ thread = threading.Thread()
+ self.assertRaises(RuntimeError, thread.join)
+
+ def test_daemonize_active_thread(self):
+ thread = threading.Thread()
+ thread.start()
+ self.assertRaises(RuntimeError, thread.setDaemon, True)
+
+
def test_main():
- test.test_support.run_unittest(ThreadTests)
+ test.test_support.run_unittest(ThreadTests,
+ ThreadingExceptionTests)
if __name__ == "__main__":
test_main()
diff --git a/Lib/threading.py b/Lib/threading.py
index fecd3cc..a46090d 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -111,8 +111,8 @@
__enter__ = acquire
def release(self):
- me = currentThread()
- assert self.__owner is me, "release() of un-acquire()d lock"
+ if self.__owner is not currentThread():
+ raise RuntimeError("cannot release un-aquired lock")
self.__count = count = self.__count - 1
if not count:
self.__owner = None
@@ -204,7 +204,8 @@
return True
def wait(self, timeout=None):
- assert self._is_owned(), "wait() of un-acquire()d lock"
+ if not self._is_owned():
+ raise RuntimeError("cannot wait on un-aquired lock")
waiter = _allocate_lock()
waiter.acquire()
self.__waiters.append(waiter)
@@ -245,7 +246,8 @@
self._acquire_restore(saved_state)
def notify(self, n=1):
- assert self._is_owned(), "notify() of un-acquire()d lock"
+ if not self._is_owned():
+ raise RuntimeError("cannot notify on un-aquired lock")
__waiters = self.__waiters
waiters = __waiters[:n]
if not waiters:
@@ -273,7 +275,8 @@
# After Tim Peters' semaphore class, but not quite the same (no maximum)
def __init__(self, value=1, verbose=None):
- assert value >= 0, "Semaphore initial value must be >= 0"
+ if value < 0:
+ raise ValueError("semaphore initial value must be >= 0")
_Verbose.__init__(self, verbose)
self.__cond = Condition(Lock())
self.__value = value
@@ -424,8 +427,10 @@
return "<%s(%s, %s)>" % (self.__class__.__name__, self.__name, status)
def start(self):
- assert self.__initialized, "Thread.__init__() not called"
- assert not self.__started, "thread already started"
+ if not self.__initialized:
+ raise RuntimeError("thread.__init__() not called")
+ if self.__started:
+ raise RuntimeError("thread already started")
if __debug__:
self._note("%s.start(): starting thread", self)
_active_limbo_lock.acquire()
@@ -545,9 +550,13 @@
_active_limbo_lock.release()
def join(self, timeout=None):
- assert self.__initialized, "Thread.__init__() not called"
- assert self.__started, "cannot join thread before it is started"
- assert self is not currentThread(), "cannot join current thread"
+ if not self.__initialized:
+ raise RuntimeError("Thread.__init__() not called")
+ if not self.__started:
+ raise RuntimeError("cannot join thread before it is started")
+ if self is currentThread():
+ raise RuntimeError("cannot join current thread")
+
if __debug__:
if not self.__stopped:
self._note("%s.join(): waiting until thread stops", self)
@@ -590,8 +599,10 @@
return self.__daemonic
def setDaemon(self, daemonic):
- assert self.__initialized, "Thread.__init__() not called"
- assert not self.__started, "cannot set daemon status of active thread"
+ if not self.__initialized:
+ raise RuntimeError("Thread.__init__() not called")
+ if self.__started:
+ raise RuntimeError("cannot set daemon status of active thread");
self.__daemonic = daemonic
# The timer class was contributed by Itamar Shtull-Trauring