|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a function to patch multiprocessing.Process to support |
|
8 debugging of the process. |
|
9 """ |
|
10 |
|
11 import sys |
|
12 import traceback |
|
13 |
|
14 _debugClient = None |
|
15 _originalProcess = None |
|
16 _originalBootstrap = None |
|
17 |
|
18 |
|
19 |
|
20 def patchMultiprocessing(module, debugClient): |
|
21 """ |
|
22 Function to patch the multiprocessing module. |
|
23 |
|
24 @param module reference to the imported module to be patched |
|
25 @type module |
|
26 @param debugClient reference to the debug client object |
|
27 @type DebugClient |
|
28 """ # __IGNORE_WARNING_D234__ |
|
29 global _debugClient, _originalProcess, _originalBootstrap |
|
30 |
|
31 _debugClient = debugClient |
|
32 |
|
33 if sys.version_info >= (3, 4): |
|
34 _originalProcess = module.process.BaseProcess |
|
35 else: |
|
36 _originalProcess = module.Process |
|
37 _originalBootstrap = _originalProcess._bootstrap |
|
38 |
|
39 class ProcessWrapper(_originalProcess): |
|
40 """ |
|
41 Wrapper class for multiprocessing.Process. |
|
42 """ |
|
43 def _bootstrap(self, *args, **kwargs): |
|
44 """ |
|
45 Wrapper around _bootstrap to start debugger. |
|
46 |
|
47 @param args function arguments |
|
48 @type list |
|
49 @param kwargs keyword only arguments |
|
50 @type dict |
|
51 @return exit code of the process |
|
52 @rtype int |
|
53 """ |
|
54 if ( |
|
55 _debugClient.debugging and |
|
56 _debugClient.multiprocessSupport |
|
57 ): |
|
58 try: |
|
59 (wd, host, port, exceptions, tracePython, redirect, |
|
60 noencoding) = _debugClient.startOptions[:7] |
|
61 _debugClient.startDebugger( |
|
62 sys.argv[0], host=host, port=port, |
|
63 exceptions=exceptions, tracePython=tracePython, |
|
64 redirect=redirect, passive=False, |
|
65 multiprocessSupport=True |
|
66 ) |
|
67 except Exception: |
|
68 print("Exception during multiprocessing bootstrap init:") |
|
69 traceback.print_exc(file=sys.stdout) |
|
70 sys.stdout.flush() |
|
71 raise |
|
72 |
|
73 return _originalBootstrap(self, *args, **kwargs) |
|
74 |
|
75 if sys.version_info >= (3, 4): |
|
76 _originalProcess._bootstrap = ProcessWrapper._bootstrap |
|
77 else: |
|
78 module.Process = ProcessWrapper |
|
79 |
|
80 ## if sys.version_info >= (3, 4): |
|
81 ## _originalProcess = module.Process |
|
82 #### _originalProcess = module.process.BaseProcess |
|
83 ## else: |
|
84 ## _originalProcess = module.Process |
|
85 ## class ProcessWrapper(_originalProcess): |
|
86 ## def __init__(self, *args, **kwargs): |
|
87 ## super(ProcessWrapper, self).__init__(*args, **kwargs) |
|
88 ## self._run = self.run |
|
89 ## self.run = self._bootstrap_eric6 |
|
90 ## # Class attributes are not transfered to new process. Therefore make a |
|
91 ## # copy as instance attribute |
|
92 ## self._options = _debugClient.startOptions |
|
93 ## |
|
94 ## def _bootstrap_eric6(self): |
|
95 ## """ |
|
96 ## Bootstrap for threading, which reports exceptions correctly. |
|
97 ## |
|
98 ## @param run the run method of threading.Thread |
|
99 ## @type method pointer |
|
100 ## """ |
|
101 ## from DebugClient import DebugClient |
|
102 ## self.debugClient = DebugClient() |
|
103 ## |
|
104 ## (_wd, host, port, exceptions, tracePython, redirect, |
|
105 ## noencoding) = self._options[:7] |
|
106 ## |
|
107 ## args = sys.argv |
|
108 ## self.debugClient.name = self.name |
|
109 ## |
|
110 ## self.debugClient.startDebugger(args[0], host, port, |
|
111 ## exceptions=exceptions, |
|
112 ## tracePython=tracePython, |
|
113 ## redirect=redirect) |
|
114 ## |
|
115 ## try: |
|
116 ## self._run() |
|
117 ## except Exception: |
|
118 ## excinfo = sys.exc_info() |
|
119 ## self.debugClient.user_exception(excinfo, True) |
|
120 ## finally: |
|
121 ## sys.settrace(None) |
|
122 ## |
|
123 ## if sys.version_info >= (3, 4): |
|
124 ## module.Process = ProcessWrapper |
|
125 #### module.process.BaseProcess = ProcessWrapper |
|
126 ## else: |
|
127 ## module.Process = ProcessWrapper |