41#include <QCoreApplication>
44#include <QProcessEnvironment>
46#include <QRegularExpression>
74 return m_runner.isPythonAvailable();
81 return m_runner.isPackageAvailable(packageName);
89 return m_runner.runCode(code);
102 bool parseOk =
false;
103 double value = result.
stdOut.trimmed().toDouble(&parseOk);
104 if (ok) *ok = parseOk;
105 return parseOk ? value : 0.0;
119 QString output = result.
stdOut.trimmed();
120 if (output.isEmpty()) {
125 QStringList lines = output.split(
'\n', Qt::SkipEmptyParts);
128 QList<double> values;
129 for (
const QString& line : lines) {
130 QStringList tokens = line.trimmed().split(QRegularExpression(
"\\s+"), Qt::SkipEmptyParts);
131 for (
const QString& token : tokens) {
132 bool parseOk =
false;
133 double val = token.toDouble(&parseOk);
142 VectorXd vec(values.size());
143 for (
int i = 0; i < values.size(); ++i) {
161 QString output = result.
stdOut.trimmed();
162 if (output.isEmpty()) {
167 QStringList lines = output.split(
'\n', Qt::SkipEmptyParts);
168 int nRows = lines.size();
171 QList<QList<double>> rowData;
172 for (
const QString& line : lines) {
173 QStringList tokens = line.trimmed().split(QRegularExpression(
"\\s+"), Qt::SkipEmptyParts);
175 nCols = tokens.size();
176 }
else if (tokens.size() != nCols) {
182 for (
const QString& token : tokens) {
183 bool parseOk =
false;
184 double val = token.toDouble(&parseOk);
199 MatrixXd mat(nRows, nCols);
200 for (
int r = 0; r < nRows; ++r) {
201 for (
int c = 0; c < nCols; ++c) {
202 mat(r, c) = rowData[r][c];
213 const QStringList& args,
217 return m_runner.run(scriptPath, args);
224 return QCoreApplication::applicationDirPath() +
"/../resources/data/mne-cpp-test-data/";
231 const QString val = QProcessEnvironment::systemEnvironment().value(
"MNE_REQUIRE_PYTHON").toLower();
232 return val ==
"true" || val ==
"1";
239 QFile file(filePath);
240 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
244 QTextStream out(&file);
245 out.setRealNumberNotation(QTextStream::ScientificNotation);
246 out.setRealNumberPrecision(17);
248 for (
int r = 0; r < mat.rows(); ++r) {
249 for (
int c = 0; c < mat.cols(); ++c) {
250 if (c > 0) out <<
' ';
264 QFile file(filePath);
265 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
270 QTextStream in(&file);
271 QList<QList<double>> rowData;
274 while (!in.atEnd()) {
275 QString line = in.readLine().trimmed();
276 if (line.isEmpty())
continue;
278 QStringList tokens = line.split(QRegularExpression(
"\\s+"), Qt::SkipEmptyParts);
280 nCols = tokens.size();
281 }
else if (tokens.size() != nCols) {
287 for (
const QString& token : tokens) {
288 bool parseOk =
false;
289 double val = token.toDouble(&parseOk);
301 if (rowData.isEmpty() || nCols <= 0) {
306 MatrixXd mat(rowData.size(), nCols);
307 for (
int r = 0; r < rowData.size(); ++r) {
308 for (
int c = 0; c < nCols; ++c) {
309 mat(r, c) = rowData[r][c];
320 const QString& outputFilePath,
PythonTestHelper class declaration — test-frame convenience for MNE-Python cross-validation.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
Script execution result container.
Eigen::VectorXd evalVector(const QString &code, bool *ok=nullptr, int timeoutMs=60000) const
static bool writeMatrix(const QString &filePath, const Eigen::MatrixXd &mat)
double evalDouble(const QString &code, bool *ok=nullptr, int timeoutMs=30000) const
PythonRunnerResult runScript(const QString &scriptPath, const QStringList &args={}, int timeoutMs=120000) const
static QString testDataPath()
Eigen::MatrixXd evalMatrixViaFile(const QString &code, const QString &outputFilePath, bool *ok=nullptr, int timeoutMs=120000) const
bool isPythonAvailable() const
bool hasPackage(const QString &packageName) const
PythonRunnerResult eval(const QString &code, int timeoutMs=30000) const
static bool isPythonRequired()
static Eigen::MatrixXd readMatrix(const QString &filePath, bool *ok=nullptr)
Eigen::MatrixXd evalMatrix(const QString &code, bool *ok=nullptr, int timeoutMs=60000) const