v2.0.0
Loading...
Searching...
No Matches
UTILSLIB::PythonTestHelper Class Reference

Test helper for MNE-Python cross-validation. More...

#include <python_test_helper.h>

Public Member Functions

 PythonTestHelper ()
bool isAvailable () const
bool isPythonAvailable () const
bool hasPackage (const QString &packageName) const
PythonRunnerResult eval (const QString &code, int timeoutMs=30000) const
double evalDouble (const QString &code, bool *ok=nullptr, int timeoutMs=30000) const
Eigen::VectorXd evalVector (const QString &code, bool *ok=nullptr, int timeoutMs=60000) const
Eigen::MatrixXd evalMatrix (const QString &code, bool *ok=nullptr, int timeoutMs=60000) const
PythonRunnerResult runScript (const QString &scriptPath, const QStringList &args={}, int timeoutMs=120000) const
Eigen::MatrixXd evalMatrixViaFile (const QString &code, const QString &outputFilePath, bool *ok=nullptr, int timeoutMs=120000) const

Static Public Member Functions

static QString testDataPath ()
static bool isPythonRequired ()
static bool writeMatrix (const QString &filePath, const Eigen::MatrixXd &mat)
static Eigen::MatrixXd readMatrix (const QString &filePath, bool *ok=nullptr)

Detailed Description

Test helper for MNE-Python cross-validation.

Test-frame convenience class for cross-validating MNE-CPP outputs against MNE-Python reference implementations.

Usage inside a QTest test:

if (!py.isAvailable()) {
QSKIP("Python/MNE-Python not available");
}
// Run a Python snippet that computes a reference value
auto result = py.eval("import mne; print(mne.io.read_info('test.fif')['nchan'])");
QVERIFY(result.success);
QCOMPARE(result.stdOut.trimmed().toInt(), expectedNchan);
// Or run a script and parse a numeric output
double pyValue = py.evalDouble("import numpy as np; print(np.linalg.norm(np.ones(10)))");
QVERIFY(qAbs(cppValue - pyValue) < 1e-6);
double evalDouble(const QString &code, bool *ok=nullptr, int timeoutMs=30000) const
PythonRunnerResult eval(const QString &code, int timeoutMs=30000) const

When MNE-Python is not installed, tests should QSKIP gracefully — but never silently. Use the GUARD_PYTHON / GUARD_PYTHON_PACKAGE macros to ensure skips are intentional and visible. When the environment variable MNE_REQUIRE_PYTHON=true is set (e.g. in CI), those macros QFAIL instead of QSKIP, so a missing Python installation is treated as a hard error.

Definition at line 119 of file python_test_helper.h.

Constructor & Destructor Documentation

◆ PythonTestHelper()

PythonTestHelper::PythonTestHelper ( )

Constructs a PythonTestHelper with auto-detected Python.

Definition at line 44 of file python_test_helper.cpp.

Member Function Documentation

◆ eval()

PythonRunnerResult PythonTestHelper::eval ( const QString & code,
int timeoutMs = 30000 ) const

Run inline Python code and return the result.

Parameters
[in]codePython code to execute via python -c.
[in]timeoutMsTimeout in milliseconds (-1 = no limit).
Returns
PythonRunnerResult with captured stdout/stderr.

Definition at line 71 of file python_test_helper.cpp.

◆ evalDouble()

double PythonTestHelper::evalDouble ( const QString & code,
bool * ok = nullptr,
int timeoutMs = 30000 ) const

Run inline Python code that prints a single double value, and parse it.

Parameters
[in]codePython code whose stdout is a single number.
[in]okSet to true on success, false on parse failure.
[in]timeoutMsTimeout in milliseconds.
Returns
The parsed double value, or 0.0 on failure.

Definition at line 79 of file python_test_helper.cpp.

◆ evalMatrix()

MatrixXd PythonTestHelper::evalMatrix ( const QString & code,
bool * ok = nullptr,
int timeoutMs = 60000 ) const

Run inline Python code that prints a matrix (one row per line, space-separated values), and parse it into an Eigen MatrixXd.

Parameters
[in]codePython code whose stdout is a space-separated matrix.
[in]okSet to true on success.
[in]timeoutMsTimeout in milliseconds.
Returns
Eigen MatrixXd, or empty matrix on failure.

Definition at line 144 of file python_test_helper.cpp.

◆ evalMatrixViaFile()

MatrixXd PythonTestHelper::evalMatrixViaFile ( const QString & code,
const QString & outputFilePath,
bool * ok = nullptr,
int timeoutMs = 120000 ) const

Run Python code that writes a matrix to outputFilePath (e.g. via numpy.savetxt), then read the result back as an Eigen MatrixXd.

This is preferred over evalMatrix() for large matrices or when full double precision is required, because it avoids stdout parsing.

Example:

QString code = QString(
"import numpy as np\n"
"cov = np.eye(3)\n"
"np.savetxt('%1', cov, fmt='%%.17e')\n"
).arg(outPath);
bool ok;
auto mat = helper.evalMatrixViaFile(code, outPath, &ok);
Parameters
[in]codePython code to execute.
[in]outputFilePathPath where Python writes the matrix.
[out]okSet to true on success.
[in]timeoutMsTimeout in milliseconds.
Returns
Parsed MatrixXd, or empty matrix on failure.

Definition at line 323 of file python_test_helper.cpp.

◆ evalVector()

VectorXd PythonTestHelper::evalVector ( const QString & code,
bool * ok = nullptr,
int timeoutMs = 60000 ) const

Run inline Python code that prints a flat array of doubles (one per line or space-separated), and parse it into an Eigen VectorXd.

Parameters
[in]codePython code whose stdout is numeric values.
[in]okSet to true on success.
[in]timeoutMsTimeout in milliseconds.
Returns
Eigen VectorXd, or empty vector on failure.

Definition at line 97 of file python_test_helper.cpp.

◆ hasPackage()

bool PythonTestHelper::hasPackage ( const QString & packageName) const

Check if a specific Python package is importable.

Parameters
[in]packageNamePackage name (e.g. "numpy", "scipy", "mne").
Returns
True if the import succeeds.

Definition at line 64 of file python_test_helper.cpp.

◆ isAvailable()

bool PythonTestHelper::isAvailable ( ) const

Check if Python is available and MNE-Python is importable.

Returns
True if both python3 and the 'mne' package are available.

Definition at line 50 of file python_test_helper.cpp.

◆ isPythonAvailable()

bool PythonTestHelper::isPythonAvailable ( ) const

Check if Python is available (without checking for mne package).

Returns
True if python3 is reachable.

Definition at line 57 of file python_test_helper.cpp.

◆ isPythonRequired()

bool PythonTestHelper::isPythonRequired ( )
static

Check whether the environment demands Python availability.

When MNE_REQUIRE_PYTHON=true is set, test guards should QFAIL instead of QSKIP, ensuring skips are never silent in CI.

Returns
True if MNE_REQUIRE_PYTHON environment variable is "true" (or "1").

Definition at line 226 of file python_test_helper.cpp.

◆ readMatrix()

MatrixXd PythonTestHelper::readMatrix ( const QString & filePath,
bool * ok = nullptr )
static

Read an Eigen matrix from a text file (space-separated values, one row per line). Compatible with numpy.savetxt() output.

Parameters
[in]filePathInput file path.
[out]okSet to true on success, false on failure.
Returns
Parsed MatrixXd, or empty matrix on failure.

Definition at line 260 of file python_test_helper.cpp.

◆ runScript()

PythonRunnerResult PythonTestHelper::runScript ( const QString & scriptPath,
const QStringList & args = {},
int timeoutMs = 120000 ) const

Run a Python script file and return the result.

Parameters
[in]scriptPathPath to the .py file.
[in]argsArguments forwarded to the script.
[in]timeoutMsTimeout in milliseconds.
Returns
PythonRunnerResult.

Definition at line 209 of file python_test_helper.cpp.

◆ testDataPath()

QString PythonTestHelper::testDataPath ( )
static

Get the standard path to mne-cpp-test-data from the test binary location.

Returns
Absolute path to the test data directory.

Definition at line 219 of file python_test_helper.cpp.

◆ writeMatrix()

bool PythonTestHelper::writeMatrix ( const QString & filePath,
const Eigen::MatrixXd & mat )
static

Write an Eigen matrix to a text file with full double precision. The format is one row per line, space-separated values, using %.17e notation — compatible with Python's numpy.loadtxt().

Parameters
[in]filePathOutput file path.
[in]matMatrix to write.
Returns
True on success.

Definition at line 234 of file python_test_helper.cpp.


The documentation for this class was generated from the following files: