dummy_thread.py 4.3 KB

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