Home | History | Annotate | Download | only in Lib
      1 """Drop-in replacement for the thread module.
      2 
      3 Meant to be used as a brain-dead substitute so that threaded code does
      4 not need to be rewritten for when the thread module is not present.
      5 
      6 Suggested usage is::
      7 
      8     try:
      9         import thread
     10     except ImportError:
     11         import dummy_thread as thread
     12 
     13 """
     14 # Exports only things specified by thread documentation;
     15 # skipping obsolete synonyms allocate(), start_new(), exit_thread().
     16 __all__ = ['error', 'start_new_thread', 'exit', 'get_ident', 'allocate_lock',
     17            'interrupt_main', 'LockType']
     18 
     19 import traceback as _traceback
     20 
     21 class error(Exception):
     22     """Dummy implementation of thread.error."""
     23 
     24     def __init__(self, *args):
     25         self.args = args
     26 
     27 def start_new_thread(function, args, kwargs={}):
     28     """Dummy implementation of thread.start_new_thread().
     29 
     30     Compatibility is maintained by making sure that ``args`` is a
     31     tuple and ``kwargs`` is a dictionary.  If an exception is raised
     32     and it is SystemExit (which can be done by thread.exit()) it is
     33     caught and nothing is done; all other exceptions are printed out
     34     by using traceback.print_exc().
     35 
     36     If the executed function calls interrupt_main the KeyboardInterrupt will be
     37     raised when the function returns.
     38 
     39     """
     40     if type(args) != type(tuple()):
     41         raise TypeError("2nd arg must be a tuple")
     42     if type(kwargs) != type(dict()):
     43         raise TypeError("3rd arg must be a dict")
     44     global _main
     45     _main = False
     46     try:
     47         function(*args, **kwargs)
     48     except SystemExit:
     49         pass
     50     except:
     51         _traceback.print_exc()
     52     _main = True
     53     global _interrupt
     54     if _interrupt:
     55         _interrupt = False
     56         raise KeyboardInterrupt
     57 
     58 def exit():
     59     """Dummy implementation of thread.exit()."""
     60     raise SystemExit
     61 
     62 def get_ident():
     63     """Dummy implementation of thread.get_ident().
     64 
     65     Since this module should only be used when threadmodule is not
     66     available, it is safe to assume that the current process is the
     67     only thread.  Thus a constant can be safely returned.
     68     """
     69     return -1
     70 
     71 def allocate_lock():
     72     """Dummy implementation of thread.allocate_lock()."""
     73     return LockType()
     74 
     75 def stack_size(size=None):
     76     """Dummy implementation of thread.stack_size()."""
     77     if size is not None:
     78         raise error("setting thread stack size not supported")
     79     return 0
     80 
     81 class LockType(object):
     82     """Class implementing dummy implementation of thread.LockType.
     83 
     84     Compatibility is maintained by maintaining self.locked_status
     85     which is a boolean that stores the state of the lock.  Pickling of
     86     the lock, though, should not be done since if the thread module is
     87     then used with an unpickled ``lock()`` from here problems could
     88     occur from this class not having atomic methods.
     89 
     90     """
     91 
     92     def __init__(self):
     93         self.locked_status = False
     94 
     95     def acquire(self, waitflag=None):
     96         """Dummy implementation of acquire().
     97 
     98         For blocking calls, self.locked_status is automatically set to
     99         True and returned appropriately based on value of
    100         ``waitflag``.  If it is non-blocking, then the value is
    101         actually checked and not set if it is already acquired.  This
    102         is all done so that threading.Condition's assert statements
    103         aren't triggered and throw a little fit.
    104 
    105         """
    106         if waitflag is None or waitflag:
    107             self.locked_status = True
    108             return True
    109         else:
    110             if not self.locked_status:
    111                 self.locked_status = True
    112                 return True
    113             else:
    114                 return False
    115 
    116     __enter__ = acquire
    117 
    118     def __exit__(self, typ, val, tb):
    119         self.release()
    120 
    121     def release(self):
    122         """Release the dummy lock."""
    123         # XXX Perhaps shouldn't actually bother to test?  Could lead
    124         #     to problems for complex, threaded code.
    125         if not self.locked_status:
    126             raise error
    127         self.locked_status = False
    128         return True
    129 
    130     def locked(self):
    131         return self.locked_status
    132 
    133 # Used to signal that interrupt_main was called in a "thread"
    134 _interrupt = False
    135 # True when not executing in a "thread"
    136 _main = True
    137 
    138 def interrupt_main():
    139     """Set _interrupt flag to True to have start_new_thread raise
    140     KeyboardInterrupt upon exiting."""
    141     if _main:
    142         raise KeyboardInterrupt
    143     else:
    144         global _interrupt
    145         _interrupt = True
    146