| 149 | |
| 150 | @classmethod |
| 151 | def _get_pdb_wrapper_class(cls, pdb_cls, capman: Optional["CaptureManager"]): |
| 152 | import _pytest.config |
| 153 | |
| 154 | # Type ignored because mypy doesn't support "dynamic" |
| 155 | # inheritance like this. |
| 156 | class PytestPdbWrapper(pdb_cls): # type: ignore[valid-type,misc] |
| 157 | _pytest_capman = capman |
| 158 | _continued = False |
| 159 | |
| 160 | def do_debug(self, arg): |
| 161 | cls._recursive_debug += 1 |
| 162 | ret = super().do_debug(arg) |
| 163 | cls._recursive_debug -= 1 |
| 164 | return ret |
| 165 | |
| 166 | def do_continue(self, arg): |
| 167 | ret = super().do_continue(arg) |
| 168 | if cls._recursive_debug == 0: |
| 169 | assert cls._config is not None |
| 170 | tw = _pytest.config.create_terminal_writer(cls._config) |
| 171 | tw.line() |
| 172 | |
| 173 | capman = self._pytest_capman |
| 174 | capturing = pytestPDB._is_capturing(capman) |
| 175 | if capturing: |
| 176 | if capturing == "global": |
| 177 | tw.sep(">", "PDB continue (IO-capturing resumed)") |
| 178 | else: |
| 179 | tw.sep( |
| 180 | ">", |
| 181 | "PDB continue (IO-capturing resumed for %s)" |
| 182 | % capturing, |
| 183 | ) |
| 184 | assert capman is not None |
| 185 | capman.resume() |
| 186 | else: |
| 187 | tw.sep(">", "PDB continue") |
| 188 | assert cls._pluginmanager is not None |
| 189 | cls._pluginmanager.hook.pytest_leave_pdb(config=cls._config, pdb=self) |
| 190 | self._continued = True |
| 191 | return ret |
| 192 | |
| 193 | do_c = do_cont = do_continue |
| 194 | |
| 195 | def do_quit(self, arg): |
| 196 | """Raise Exit outcome when quit command is used in pdb. |
| 197 | |
| 198 | This is a bit of a hack - it would be better if BdbQuit |
| 199 | could be handled, but this would require to wrap the |
| 200 | whole pytest run, and adjust the report etc. |
| 201 | """ |
| 202 | ret = super().do_quit(arg) |
| 203 | |
| 204 | if cls._recursive_debug == 0: |
| 205 | outcomes.exit("Quitting debugger") |
| 206 | |
| 207 | return ret |
| 208 | |