MCPcopy Index your code
hub / github.com/python/mypy / ModuleInspect

Class ModuleInspect

mypy/moduleinspect.py:106–184  ·  view source on GitHub ↗

Perform runtime introspection of modules in a separate process. Reuse the process for multiple modules for efficiency. However, if there is an error, retry using a fresh process to avoid cross-contamination of state between modules. We use a separate process to isolate us from many

Source from the content-addressed store, hash-verified

104
105
106class ModuleInspect:
107 """Perform runtime introspection of modules in a separate process.
108
109 Reuse the process for multiple modules for efficiency. However, if there is an
110 error, retry using a fresh process to avoid cross-contamination of state between
111 modules.
112
113 We use a separate process to isolate us from many side effects. For example, the
114 import of a module may kill the current process, and we want to recover from that.
115
116 Always use in a with statement for proper clean-up:
117
118 with ModuleInspect() as m:
119 p = m.get_package_properties('urllib.parse')
120 """
121
122 def __init__(self) -> None:
123 self._start()
124
125 def _start(self) -> None:
126 if sys.platform == "linux":
127 ctx = get_context("forkserver")
128 else:
129 ctx = get_context("spawn")
130 self.tasks: Queue[str] = ctx.Queue()
131 self.results: Queue[ModuleProperties | str] = ctx.Queue()
132 self.proc = ctx.Process(target=worker, args=(self.tasks, self.results, sys.path))
133 self.proc.start()
134 self.counter = 0 # Number of successful roundtrips
135
136 def close(self) -> None:
137 """Free any resources used."""
138 self.proc.terminate()
139
140 def get_package_properties(self, package_id: str) -> ModuleProperties:
141 """Return some properties of a module/package using runtime introspection.
142
143 Raise InspectError if the target couldn't be imported.
144 """
145 self.tasks.put(package_id)
146 res = self._get_from_queue()
147 if res is None:
148 # The process died; recover and report error.
149 self._start()
150 raise InspectError(f"Process died when importing {package_id!r}")
151 if isinstance(res, str):
152 # Error importing module
153 if self.counter > 0:
154 # Also try with a fresh process. Maybe one of the previous imports has
155 # corrupted some global state.
156 self.close()
157 self._start()
158 return self.get_package_properties(package_id)
159 raise InspectError(res)
160 self.counter += 1
161 return res
162
163 def _get_from_queue(self) -> ModuleProperties | str | None:

Callers 6

test_walk_packagesMethod · 0.90
test_python_moduleMethod · 0.90
test_python_packageMethod · 0.90
test_c_moduleMethod · 0.90
test_non_existentMethod · 0.90

Calls

no outgoing calls

Tested by 5

test_walk_packagesMethod · 0.72
test_python_moduleMethod · 0.72
test_python_packageMethod · 0.72
test_c_moduleMethod · 0.72
test_non_existentMethod · 0.72

Used in the wild real call sites across dependent graphs

searching dependent graphs…