diff --git a/procrunner/__init__.py b/procrunner/__init__.py index 62cfb5d..8cf50dc 100644 --- a/procrunner/__init__.py +++ b/procrunner/__init__.py @@ -280,7 +280,8 @@ def run(command, timeout=None, debug=False, stdin=None, print_stdout=True, print_stderr=True, callback_stdout=None, callback_stderr=None, - environment=None, environment_override=None, win32resolve=True): + environment=None, environment_override=None, win32resolve=True, + working_directory=None): '''Run an external process. :param array command: Command line to be run, specified as array. @@ -296,9 +297,12 @@ :param dict environment: The full execution environment for the command. :param dict environment_override: Change environment variables from the current values for command execution. - :param win32resolve: If on Windows, find the appropriate executable first. - This allows running of .bat, .cmd, etc. files without - explicitly specifying their extension. + :param boolean win32resolve: If on Windows, find the appropriate executable + first. This allows running of .bat, .cmd, etc. + files without explicitly specifying their + extension. + :param string working_directory: If specified, run the executable from + within this working directory. :return: A dictionary containing stdout, stderr (both as bytestrings), runtime, exitcode, and more. ''' @@ -327,7 +331,8 @@ if win32resolve and sys.platform == 'win32': command = _windows_resolve(command) - p = subprocess.Popen(command, shell=False, stdin=stdin_pipe, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) + p = subprocess.Popen(command, shell=False, cwd=working_directory, env=env, + stdin=stdin_pipe, stdout=subprocess.PIPE, stderr=subprocess.PIPE) thread_pipe_pool = [] notifyee, notifier = Pipe(False) diff --git a/tests/test_procrunner.py b/tests/test_procrunner.py index ee390ef..f2bc299 100644 --- a/tests/test_procrunner.py +++ b/tests/test_procrunner.py @@ -51,14 +51,16 @@ 'runtime': mock.ANY, 'timeout': False, 'time_start': mock.ANY, - 'time_end': mock.ANY + 'time_end': mock.ANY, } actual = procrunner.run(command, 0.5, False, - callback_stdout=mock.sentinel.callback_stdout, callback_stderr=mock.sentinel.callback_stderr) + callback_stdout=mock.sentinel.callback_stdout, callback_stderr=mock.sentinel.callback_stderr, + working_directory=mock.sentinel.cwd) assert mock_subprocess.Popen.called assert mock_subprocess.Popen.call_args[1]['env'] == os.environ + assert mock_subprocess.Popen.call_args[1]['cwd'] == mock.sentinel.cwd mock_streamreader.assert_has_calls([mock.call(stream_stdout, output=mock.ANY, debug=mock.ANY, notify=mock.ANY, callback=mock.sentinel.callback_stdout), mock.call(stream_stderr, output=mock.ANY, debug=mock.ANY, notify=mock.ANY, callback=mock.sentinel.callback_stderr)], any_order=True)