@SuppressWarnings("resource") // Do not close stdin 
	protected ExecInPython execInPython(String script) throws IOException {
		ProcessBuilder pb = new ProcessBuilder(pythonPath.toString(), "-i");
		setPythonPath(pb);
		setWindbgPath(pb);

		// If commands come from file, Python will quit after EOF.
		Msg.info(this, "outFile: " + outFile);
		Msg.info(this, "errFile: " + errFile);

		//pb.inheritIO();
		pb.redirectInput(ProcessBuilder.Redirect.PIPE);
		if (SystemUtilities.isInTestingBatchMode()) {
			pb.redirectOutput(outFile.toFile());
			pb.redirectError(errFile.toFile());
		}
		else {
			pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
			pb.redirectError(ProcessBuilder.Redirect.PIPE);
		}
		Process pyproc = pb.start();

		if (!SystemUtilities.isInTestingBatchMode()) {
			pumpTee(pyproc.getInputStream(), outFile.toFile(), System.out);
			pumpTee(pyproc.getErrorStream(), errFile.toFile(), System.err);
		}

		OutputStream stdin = pyproc.getOutputStream();
		stdin.write(script.getBytes());
		stdin.flush();

		if (!SystemUtilities.isInTestingBatchMode()) {
			pump(System.in, stdin);
		}

		return new ExecInPython(pyproc, CompletableFuture.supplyAsync(() -> {
			try {
				if (!pyproc.waitFor(TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
					Msg.error(this, "Timed out waiting for Python");
					pyproc.destroyForcibly();
					pyproc.waitFor(TIMEOUT_SECONDS, TimeUnit.SECONDS);
					return new PythonResult(true, -1, Files.readString(outFile),
						Files.readString(errFile));
				}
				Msg.info(this, "Python exited with code " + pyproc.exitValue());
				return new PythonResult(false, pyproc.exitValue(), Files.readString(outFile),
					Files.readString(errFile));
			}
			catch (Exception e) {
				return ExceptionUtils.rethrow(e);
			}
			finally {
				pyproc.destroyForcibly();
			}
		}));
	}
Some snapshot likely to exceed the latest
Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/AbstractDbgEngTraceRmiTest.java