Codebase list python-procrunner / a928b39
Make run() return ReturnObject() instances Markus Gerstel 4 years ago
3 changed file(s) with 57 addition(s) and 39 deletion(s). Raw diff Collapse all Expand all
346346
347347
348348 class ReturnObject(dict, _ReturnObjectParent):
349 """
350 A subprocess.CompletedProcess-like object containing the executed
351 command, stdout and stderr (both as bytestrings), and the exitcode.
352 Further values such as process runtime can be accessed as dictionary
353 values.
354 The check_returncode() function raises an exception if the process
355 exited with a non-zero exit code.
356 """
357
349358 def __init__(self, *arg, **kw):
350359 super(ReturnObject, self).__init__(*arg, **kw)
351360 self.args = self["command"]
393402 extension.
394403 :param string working_directory: If specified, run the executable from
395404 within this working directory.
396 :return: A dictionary containing stdout, stderr (both as bytestrings),
397 runtime, exitcode, and more.
405 :return: A ReturnObject() containing the executed command, stdout and stderr
406 (both as bytestrings), and the exitcode. Further values such as
407 process runtime can be accessed as dictionary values.
398408 """
399409
400410 time_start = time.strftime("%Y-%m-%d %H:%M:%S GMT", time.gmtime())
542552 stderr = stderr.get_output()
543553 time_end = time.strftime("%Y-%m-%d %H:%M:%S GMT", time.gmtime())
544554
545 result = {
546 "exitcode": p.returncode,
547 "command": command,
548 "stdout": stdout,
549 "stderr": stderr,
550 "timeout": timeout_encountered,
551 "runtime": runtime,
552 "time_start": time_start,
553 "time_end": time_end,
554 }
555 result = ReturnObject(
556 {
557 "exitcode": p.returncode,
558 "command": command,
559 "stdout": stdout,
560 "stderr": stderr,
561 "timeout": timeout_encountered,
562 "runtime": runtime,
563 "time_start": time_start,
564 "time_end": time_end,
565 }
566 )
555567 if stdin is not None:
556568 result.update(
557569 {
575587 time_start = time.strftime("%Y-%m-%d %H:%M:%S GMT", time.gmtime())
576588 logger.info("run_process is disabled. Requested command: %s", command)
577589
578 result = {
579 "exitcode": 0,
580 "command": command,
581 "stdout": "",
582 "stderr": "",
583 "timeout": False,
584 "runtime": 0,
585 "time_start": time_start,
586 "time_end": time_start,
587 }
590 result = ReturnObject(
591 {
592 "exitcode": 0,
593 "command": command,
594 "stdout": "",
595 "stderr": "",
596 "timeout": False,
597 "runtime": 0,
598 "time_start": time_start,
599 "time_end": time_start,
600 }
601 )
588602 if kwargs.get("stdin") is not None:
589603 result.update(
590604 {"stdin_bytes_sent": len(kwargs["stdin"]), "stdin_bytes_remain": 0}
9393 )
9494 assert not mock_process.terminate.called
9595 assert not mock_process.kill.called
96 assert actual == expected
96 for key in expected:
97 assert actual[key] == expected[key]
98 assert actual.args == tuple(command)
99 assert actual.returncode == mock_process.returncode
100 assert actual.stdout == mock.sentinel.proc_stdout
101 assert actual.stderr == mock.sentinel.proc_stderr
97102
98103
99104 @mock.patch("procrunner.subprocess")
1414
1515 result = procrunner.run(command)
1616
17 assert result["exitcode"] == 0
18 assert result["stdout"] == b"hello" + os.linesep.encode("utf-8")
19 assert result["stderr"] == b""
17 assert result.returncode == 0
18 assert result.stdout == b"hello" + os.linesep.encode("utf-8")
19 assert result.stderr == b""
2020
2121
2222 def test_decode_invalid_utf8_input(capsys):
2727 else:
2828 command = ["cat"]
2929 result = procrunner.run(command, stdin=test_string)
30 assert result["exitcode"] == 0
31 assert not result["stderr"]
30 assert result.returncode == 0
31 assert not result.stderr
3232 if os.name == "nt":
3333 # Windows modifies line endings
34 assert result["stdout"] == test_string[:-1] + b"\r\n"
34 assert result.stdout == test_string[:-1] + b"\r\n"
3535 else:
36 assert result["stdout"] == test_string
36 assert result.stdout == test_string
3737 out, err = capsys.readouterr()
3838 assert out == u"test\ufffdstring\n"
3939 assert err == u""
4848 if e.errno == 2:
4949 pytest.skip("wget not available")
5050 raise
51 assert result["exitcode"] == 0
52 assert b"http" in result["stderr"]
53 assert b"google" in result["stdout"]
51 assert result.returncode == 0
52 assert b"http" in result.stderr
53 assert b"google" in result.stdout
5454
5555
5656 def test_path_object_resolution(tmpdir):
57 sentinel_value = "sentinel"
57 sentinel_value = b"sentinel"
5858 tmpdir.join("tempfile").write(sentinel_value)
5959 tmpdir.join("reader.py").write("print(open('tempfile').read())")
60 command = [sys.executable, tmpdir.join("reader.py")]
6160 result = procrunner.run(
62 command,
61 [sys.executable, tmpdir.join("reader.py")],
6362 environment_override={"PYTHONHASHSEED": "random"},
6463 working_directory=tmpdir,
6564 )
66 assert result["exitcode"] == 0
67 assert not result["stderr"]
68 assert sentinel_value == result["stdout"].strip().decode()
65 assert result.returncode == 0
66 assert not result.stderr
67 assert sentinel_value == result.stdout.strip()