Skip to main content

PythonRunner

Namespace: UTILSLIB  ·  Library: Utilities Library

#include <utils/python_runner.h>

class UTILSLIB::PythonRunner

Standardized interface for launching Python scripts from C++.

Features:

  • Auto-discovers Python via PATH or explicit config.
  • Runs scripts with -u (unbuffered) by default for real-time output.
  • Streams stdout/stderr line-by-line through optional callbacks.
  • Parses a simple progress protocol: lines matching [progress] <float>% or [progress] <float>% <message>.
  • Integrates with MNE-CPP's logging (qDebug/qWarning).
  • Supports timeout, environment injection, and working directory.

No Python embedding or linkage is required.

Python script launcher with logging and progress support.

src/examples/ex_utils/main.cpp
PythonRunner python; // "python3" from PATH; a venv is configured via PythonRunnerConfig
QStringList progress;
python.setProgressCallback([&](float pct, const QString& msg) { progress << QString("%1 %2").arg(pct).arg(msg); });
const PythonRunnerResult run = python.runCode("import sys\nprint('[progress] 50% half')\nprint(sum(map(int, sys.argv[1:])))", {"2", "3"});

Inheritance​


Public Methods​

PythonRunner(pParent)​

Construct a PythonRunner with default configuration.

Parameters:

  • pParent : *QObject ** Parent QObject (optional).

PythonRunner(config, pParent)​

Construct a PythonRunner with explicit configuration.

Parameters:

  • config : const PythonRunnerConfig & Execution configuration.

  • pParent : *QObject ** Parent QObject (optional).


setConfig(config)​

Set the configuration.

Parameters:


config()​

Get the current configuration.

Returns:


setLineCallback(cb)​

Set a callback invoked for every stdout/stderr line.

Parameters:

  • cb : PythonLineCallback Line callback (channel, line).

setProgressCallback(cb)​

Set a callback invoked when a progress line is detected.

Progress protocol: the script prints lines matching: [progress] 42.5% [progress] 42.5% Training epoch 10/50

Parameters:

  • cb : PythonProgressCallback Progress callback (pct, msg).

run(scriptPath, args)​

Run a Python script synchronously.

Parameters:

  • scriptPath : const QString & Path to the .py file.

  • args : const QStringList & Arguments forwarded to the script.

Returns:


runCode(code, args)​

Run a Python one-liner synchronously (python -c "...").

Parameters:

  • code : const QString & Python code string.

  • args : const QStringList & Extra arguments appended after -c code.

Returns:


isPythonAvailable()​

Check that the configured Python interpreter is reachable.

Returns:

  • bool — True if python --version succeeds.

pythonVersion()​

Query the version string of the configured Python interpreter.

Returns:

  • QString — Version string (e.g. "3.11.5"), or empty if unavailable.

isPackageAvailable(packageName)​

Check whether a Python package is importable.

Parameters:

  • packageName : const QString & Package name (e.g. "torch", "mne").

Returns:

  • bool — True if the import succeeds.

ensureVenv()​

Ensure a virtual environment exists, is up-to-date, and has all required packages installed.

Workflow: If config().venvDir is empty, returns immediately (no-op).

Creates the venv if it doesn't exist yet (python -m venv ...).

Installs dependencies:

  • If config().packageDir is set (contains pyproject.toml): runs pip install <packageDir> inside the venv.
  • Else if config().requirementsFile is set: runs pip install -r <file> inside the venv.

On success, updates the internal config so that subsequent run()/runCode() calls use the venv's Python interpreter.

Returns:


runInVenv(scriptPath, args)​

Convenience: ensure venv, then run a script inside it.

Equivalent to calling ensureVenv() + run(), but returns early with an error result if venv setup fails.

Parameters:

  • scriptPath : const QString & Path to the .py file.

  • args : const QStringList & Arguments forwarded to the script.

Returns:


venvPythonPath()​

Get the Python interpreter path inside the configured venv.

Returns:

  • QString — Absolute path to venv python, or empty if no venv configured.

Example​

Used in examples​

ex_utils​

Utilities library: buffers, observers, logging, file formats, montages, layouts and reports.

src/examples/ex_utils/main.cpp, line 312
PythonRunner python; // "python3" from PATH; a venv is configured via PythonRunnerConfig
QStringList progress;
python.setProgressCallback([&](float pct, const QString& msg) { progress << QString("%1 %2").arg(pct).arg(msg); });
const PythonRunnerResult run = python.runCode("import sys\nprint('[progress] 50% half')\nprint(sum(map(int, sys.argv[1:])))", {"2", "3"});
PythonTestHelper helper; // oracle access for tests
const MatrixXd fromNumpy = helper.evalMatrix("print('1 2'); print('3 4')"); // one line per row
if (python.isPythonAvailable()) {
ok &= expect(run.success && run.stdOut.trimmed().endsWith("5") && progress == QStringList({"50 half"}) && fromNumpy == (Matrix2d() << 1, 2, 3, 4).finished(),
"PythonRunner passes arguments and parses [progress] lines; PythonTestHelper reads a matrix");
} else {
qInfo().noquote() << " skip PythonRunner (python3 not found)";

Authors of this file​