Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 491b1e6

Browse files
committed
Recover from helper process death
1 parent 7c11297 commit 491b1e6

File tree

2 files changed

+43
-2
lines changed

2 files changed

+43
-2
lines changed

mypy/moduleinspect.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import inspect
88
import os
99
import pkgutil
10+
import queue
1011

1112

1213
ModuleProperties = NamedTuple('ModuleProperties', [
@@ -85,7 +86,10 @@ class ModuleInspect:
8586
8687
Reuse the process for multiple modules for efficiency. However, if there is an
8788
error, retry using a fresh process to avoid cross-contamination of state between
88-
modules (important for certain 3rd-party packages).
89+
modules.
90+
91+
We use a separate process to isolate us from many side effects. For example, the
92+
import of a module may kill the current process, and we want to recover from that.
8993
9094
Always use in a with statement for proper clean-up:
9195
@@ -113,7 +117,11 @@ def get_package_properties(self, package_id: str) -> ModuleProperties:
113117
Raise InspectError if the target couldn't be imported.
114118
"""
115119
self.q1.put(package_id)
116-
res = self.q2.get()
120+
res = self._get_from_queue()
121+
if res is None:
122+
# The process died; recover and report error.
123+
self._start()
124+
raise InspectError('Process died when importing %r' % package_id)
117125
if isinstance(res, str):
118126
# Error importing module
119127
if self.counter > 0:
@@ -126,6 +134,18 @@ def get_package_properties(self, package_id: str) -> ModuleProperties:
126134
self.counter += 1
127135
return res
128136

137+
def _get_from_queue(self) -> Union[ModuleProperties, str, None]:
138+
"""Get value from the queue.
139+
140+
Return the value read from the queue, or None if the process unexpectedly died.
141+
"""
142+
while True:
143+
try:
144+
return self.q2.get(timeout=0.05)
145+
except queue.Empty:
146+
if not self.proc.is_alive():
147+
return None
148+
129149
def __enter__(self) -> 'ModuleInspect':
130150
return self
131151

test-data/unit/stubgen.test

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,3 +1774,24 @@ def g() -> None: ...
17741774
<out/b.pyi was not generated>
17751775
# c.pyi
17761776
x: int
1777+
1778+
[case testImportedModuleHardExits_import]
1779+
# modules: a b c
1780+
1781+
[file a.py]
1782+
def g(): pass
1783+
1784+
[file b.py]
1785+
import os
1786+
def f(): pass
1787+
os._exit(1) # Kill process
1788+
1789+
[file c.py]
1790+
x = 0
1791+
1792+
[out]
1793+
# a.pyi
1794+
def g() -> None: ...
1795+
<out/b.pyi was not generated>
1796+
# c.pyi
1797+
x: int

0 commit comments

Comments
 (0)