_dummy_thread32.py 4.9 KB

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