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