|
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 |