How to set working directory of QProcess

Running external programs from different folders using QProcess in PyQt5
Heads up! You've already completed this tutorial.

When using QProcess to run external programs from your PyQt5 application, you'll often need to launch a program that lives in a completely different folder from your Python script. Maybe the external program also depends on input files or configuration in its own directory. In that case, you need to tell QProcess both where the program is and what directory it should run in.

The problem

Suppose you have an external program at C:/program_folder/test.exe, and your PyQt5 application lives at C:/qt_source/test.py. The external program expects to find its input files in C:/program_folder/.

You might try something like this:

python
p = QProcess()
p.setWorkingDirectory('C:/program_folder/')
p.start('test.exe')

This looks reasonable, but it won't work. The issue is that setWorkingDirectory() sets the working directory for the process once it's running — it doesn't affect how Qt searches for the executable itself. When you pass just test.exe to start(), Qt doesn't know where to find it.

The solution

You need to provide the full path to the executable so Qt can locate it, and set the working directory so the process runs in the correct folder. The cleanest way to do this is with setProgram() and setWorkingDirectory() together, then call start() with no arguments:

python
p = QProcess()
p.setProgram('C:/program_folder/test.exe')
p.setWorkingDirectory('C:/program_folder')
p.start()

By using setProgram() with the full path, Qt knows exactly which executable to launch. And setWorkingDirectory() ensures that once the program is running, its current directory is C:/program_folder/ — so any relative file paths the program uses will resolve correctly.

Why does this happen?

In older versions of Qt, you could pass the program name and arguments as a single string to start():

python
p.start('test.exe')  # Deprecated approach

This form of start() is now deprecated. The current API expects you to either:

The complete guide to packaging Python GUI applications with PyInstaller.
[[ discount.discount_pc ]]% OFF for the next [[ discount.duration ]] [[discount.description ]] with the code [[ discount.coupon_code ]]

Purchasing Power Parity

Developers in [[ country ]] get [[ discount.discount_pc ]]% OFF on all books & courses with code [[ discount.coupon_code ]]

  1. Use setProgram() and (optionally) setArguments() before calling start(), or
  2. Pass the program and arguments separately to start():
python
p.start('C:/program_folder/test.exe', [])

The empty list [] represents the arguments — in this case, none. You must always pass arguments as a separate list.

Mixing the deprecated start('program') call with setWorkingDirectory() is what causes the confusion. For a deeper look at how QProcess works and how to handle external programs in your Qt applications, see our complete guide to QProcess.

A complete example

Here's a small working example that launches an external program from a specific directory, with a button to trigger the process. This example uses signals and slots to connect the process output to the UI:

python
import sys

from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QPushButton, QTextEdit, QVBoxLayout, QWidget,
)
from PyQt5.QtCore import QProcess


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QProcess Working Directory Example")

        self.text_output = QTextEdit()
        self.text_output.setReadOnly(True)

        self.button = QPushButton("Run External Program")
        self.button.clicked.connect(self.run_process)

        layout = QVBoxLayout()
        layout.addWidget(self.button)
        layout.addWidget(self.text_output)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

        self.process = None

    def run_process(self):
        if self.process is not None:
            return  # Already running

        self.process = QProcess()
        self.process.setProgram("C:/program_folder/test.exe")
        self.process.setWorkingDirectory("C:/program_folder")

        self.process.readyReadStandardOutput.connect(self.handle_stdout)
        self.process.readyReadStandardError.connect(self.handle_stderr)
        self.process.finished.connect(self.process_finished)

        self.process.start()

    def handle_stdout(self):
        data = self.process.readAllStandardOutput()
        text = bytes(data).decode("utf-8")
        self.text_output.append(text)

    def handle_stderr(self):
        data = self.process.readAllStandardError()
        text = bytes(data).decode("utf-8")
        self.text_output.append(text)

    def process_finished(self):
        self.text_output.append("Process finished.")
        self.process = None


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

Update the path in setProgram() and setWorkingDirectory() to match your actual program location, and you're good to go.

Passing arguments

If your external program needs command-line arguments, use setArguments() with a list:

python
p = QProcess()
p.setProgram("C:/program_folder/test.exe")
p.setArguments(["--input", "data.txt", "--verbose"])
p.setWorkingDirectory("C:/program_folder")
p.start()

Each argument is a separate string in the list. Qt handles the quoting and escaping for you, so you don't need to worry about spaces in filenames or other shell-related headaches. If you also need to handle command-line arguments passed to your own PyQt5 application, that's handled separately through QApplication.

Summary

When launching external programs with QProcess from a different directory:

  • Use setProgram() with the full path to the executable.
  • Use setWorkingDirectory() to set the directory the process should run in.
  • Call start() with no arguments.
  • If you need to pass arguments, use setArguments() with a list of strings.

This approach avoids the deprecated single-string form of start() and ensures the working directory is applied correctly every time. Once your application is ready for distribution, you can package it with PyInstaller to create a standalone executable.

Create GUI Applications with Python & Qt6 by Martin Fitzpatrick — (PyQt6 Edition) The hands-on guide to making apps with Python — Save time and build better with this book. Over 15K copies sold.

Get the book

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak
Leo Well

How to set working directory of QProcess was written by Leo Well.