You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
4.3 KiB
146 lines
4.3 KiB
4 months ago
|
"""Drop-in replacement for the thread module.
|
||
|
|
||
|
Meant to be used as a brain-dead substitute so that threaded code does
|
||
|
not need to be rewritten for when the thread module is not present.
|
||
|
|
||
|
Suggested usage is::
|
||
|
|
||
|
try:
|
||
|
import thread
|
||
|
except ImportError:
|
||
|
import dummy_thread as thread
|
||
|
|
||
|
"""
|
||
|
# Exports only things specified by thread documentation;
|
||
|
# skipping obsolete synonyms allocate(), start_new(), exit_thread().
|
||
|
__all__ = ['error', 'start_new_thread', 'exit', 'get_ident', 'allocate_lock',
|
||
|
'interrupt_main', 'LockType']
|
||
|
|
||
|
import traceback as _traceback
|
||
|
|
||
|
class error(Exception):
|
||
|
"""Dummy implementation of thread.error."""
|
||
|
|
||
|
def __init__(self, *args):
|
||
|
self.args = args
|
||
|
|
||
|
def start_new_thread(function, args, kwargs={}):
|
||
|
"""Dummy implementation of thread.start_new_thread().
|
||
|
|
||
|
Compatibility is maintained by making sure that ``args`` is a
|
||
|
tuple and ``kwargs`` is a dictionary. If an exception is raised
|
||
|
and it is SystemExit (which can be done by thread.exit()) it is
|
||
|
caught and nothing is done; all other exceptions are printed out
|
||
|
by using traceback.print_exc().
|
||
|
|
||
|
If the executed function calls interrupt_main the KeyboardInterrupt will be
|
||
|
raised when the function returns.
|
||
|
|
||
|
"""
|
||
|
if type(args) != type(tuple()):
|
||
|
raise TypeError("2nd arg must be a tuple")
|
||
|
if type(kwargs) != type(dict()):
|
||
|
raise TypeError("3rd arg must be a dict")
|
||
|
global _main
|
||
|
_main = False
|
||
|
try:
|
||
|
function(*args, **kwargs)
|
||
|
except SystemExit:
|
||
|
pass
|
||
|
except:
|
||
|
_traceback.print_exc()
|
||
|
_main = True
|
||
|
global _interrupt
|
||
|
if _interrupt:
|
||
|
_interrupt = False
|
||
|
raise KeyboardInterrupt
|
||
|
|
||
|
def exit():
|
||
|
"""Dummy implementation of thread.exit()."""
|
||
|
raise SystemExit
|
||
|
|
||
|
def get_ident():
|
||
|
"""Dummy implementation of thread.get_ident().
|
||
|
|
||
|
Since this module should only be used when threadmodule is not
|
||
|
available, it is safe to assume that the current process is the
|
||
|
only thread. Thus a constant can be safely returned.
|
||
|
"""
|
||
|
return -1
|
||
|
|
||
|
def allocate_lock():
|
||
|
"""Dummy implementation of thread.allocate_lock()."""
|
||
|
return LockType()
|
||
|
|
||
|
def stack_size(size=None):
|
||
|
"""Dummy implementation of thread.stack_size()."""
|
||
|
if size is not None:
|
||
|
raise error("setting thread stack size not supported")
|
||
|
return 0
|
||
|
|
||
|
class LockType(object):
|
||
|
"""Class implementing dummy implementation of thread.LockType.
|
||
|
|
||
|
Compatibility is maintained by maintaining self.locked_status
|
||
|
which is a boolean that stores the state of the lock. Pickling of
|
||
|
the lock, though, should not be done since if the thread module is
|
||
|
then used with an unpickled ``lock()`` from here problems could
|
||
|
occur from this class not having atomic methods.
|
||
|
|
||
|
"""
|
||
|
|
||
|
def __init__(self):
|
||
|
self.locked_status = False
|
||
|
|
||
|
def acquire(self, waitflag=None):
|
||
|
"""Dummy implementation of acquire().
|
||
|
|
||
|
For blocking calls, self.locked_status is automatically set to
|
||
|
True and returned appropriately based on value of
|
||
|
``waitflag``. If it is non-blocking, then the value is
|
||
|
actually checked and not set if it is already acquired. This
|
||
|
is all done so that threading.Condition's assert statements
|
||
|
aren't triggered and throw a little fit.
|
||
|
|
||
|
"""
|
||
|
if waitflag is None or waitflag:
|
||
|
self.locked_status = True
|
||
|
return True
|
||
|
else:
|
||
|
if not self.locked_status:
|
||
|
self.locked_status = True
|
||
|
return True
|
||
|
else:
|
||
|
return False
|
||
|
|
||
|
__enter__ = acquire
|
||
|
|
||
|
def __exit__(self, typ, val, tb):
|
||
|
self.release()
|
||
|
|
||
|
def release(self):
|
||
|
"""Release the dummy lock."""
|
||
|
# XXX Perhaps shouldn't actually bother to test? Could lead
|
||
|
# to problems for complex, threaded code.
|
||
|
if not self.locked_status:
|
||
|
raise error
|
||
|
self.locked_status = False
|
||
|
return True
|
||
|
|
||
|
def locked(self):
|
||
|
return self.locked_status
|
||
|
|
||
|
# Used to signal that interrupt_main was called in a "thread"
|
||
|
_interrupt = False
|
||
|
# True when not executing in a "thread"
|
||
|
_main = True
|
||
|
|
||
|
def interrupt_main():
|
||
|
"""Set _interrupt flag to True to have start_new_thread raise
|
||
|
KeyboardInterrupt upon exiting."""
|
||
|
if _main:
|
||
|
raise KeyboardInterrupt
|
||
|
else:
|
||
|
global _interrupt
|
||
|
_interrupt = True
|