11 #include <QApplication>
14 #include <QMessageBox>
22 #if defined(USE_EMBEDDED_MODULES)
23 #if defined(Q_OS_WINDOWS)
24 static QString BundledSitePackagesPath()
26 return QDir::listSeparator() + QApplication::applicationDirPath() +
27 "/plugins/Python/Lib/site-packages";
29 #elif defined(Q_OS_MACOS)
30 static QString BundledSitePackagesPath()
32 return QDir::listSeparator() + QApplication::applicationDirPath() +
33 "/../Resources/python/lib/site-packages";
36 static QString BundledSitePackagesPath()
38 return QDir::listSeparator() + QApplication::applicationDirPath() +
39 "/plugins/Python/lib/site-packages";
50 if (parts.size() == 3)
52 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
77 pythonProcess.setArguments({
"--version"});
78 pythonProcess.start(QIODevice::ReadOnly);
79 pythonProcess.waitForFinished();
81 const QString versionStr =
85 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
86 if (splits.size() == 2 && splits[0].toString().contains(
"Python"))
90 if (splits.size() == 2 && splits[0].contains(
"Python"))
115 if (cfgFile.open(QIODevice::ReadOnly | QIODevice::Text))
117 while (!cfgFile.atEnd())
119 QString line = cfgFile.readLine();
120 QStringList v = line.split(
"=");
124 QString
name = v[0].simplified();
125 QString value = v[1].simplified();
131 else if (
name ==
"include-system-site-packages")
133 cfg.includeSystemSitesPackages = (value ==
"true");
135 else if (
name ==
"version")
150 return m_pythonHome !=
nullptr && m_pythonPath !=
nullptr;
155 return m_pythonHome.get();
160 return m_pythonPath.get();
167 #if defined(Q_OS_WINDOWS)
171 return envRoot +
"/python.exe";
173 return envRoot +
"/Scripts/python.exe";
175 return envRoot +
"/python.exe";
185 return envRoot +
"/bin/python";
195 #if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
204 #if defined(Q_OS_MACOS)
205 const QString pythonEnvDirPath(QApplication::applicationDirPath() +
"/../Resources/python");
207 const QString pythonEnvDirPath(QApplication::applicationDirPath() +
"/plugins/Python");
214 QDir envRoot(prefix);
216 if (!envRoot.exists())
218 m_pythonHome = QString();
219 m_pythonPath = QString();
224 if (envRoot.exists(
"pyvenv.cfg"))
228 if (m_pythonHome.isEmpty() && m_pythonPath.isEmpty())
230 qDebug() <<
"Failed to get paths info from python executable at (venv)"
239 else if (envRoot.exists(
"conda-meta"))
243 if (m_pythonHome.isEmpty() && m_pythonPath.isEmpty())
245 qDebug() <<
"Failed to get paths info from python executable at (conda)"
255 #if defined(Q_OS_WIN32) || defined(Q_OS_MACOS)
259 if (m_pythonHome.isEmpty() && m_pythonPath.isEmpty())
261 qDebug() <<
"Failed to get paths info from python executable at (bundled)"
272 m_pythonHome = envRoot.path();
273 m_pythonPath = QString(
"%1/DLLs;%1/lib;%1/Lib;%1/Lib/site-packages;").arg(m_pythonHome);
276 #if defined(USE_EMBEDDED_MODULES)
277 m_pythonPath.append(BundledSitePackagesPath());
286 m_pythonHome = condaPrefix;
287 m_pythonPath = QString(
"%1/DLLs;%1/lib;%1/Lib;%1/Lib/site-packages;").arg(condaPrefix);
289 #if defined(USE_EMBEDDED_MODULES)
290 m_pythonPath.append(BundledSitePackagesPath());
299 m_pythonHome = venvPrefix;
300 m_pythonPath = QString(
"%1/Lib;%1/Lib/site-packages;%3/DLLs;%3/lib;").arg(venvPrefix, cfg.
home);
303 m_pythonPath.append(QString(
"%1/Lib/site-packages;").arg(cfg.
home));
306 #if defined(USE_EMBEDDED_MODULES)
307 m_pythonPath.append(BundledSitePackagesPath());
314 pythonProcess.setProgram(pythonExePath);
320 #if defined(Q_OS_WINDOWS)
321 const QString additionalPath = QString(
"%1/Library/bin").arg(m_pythonHome);
323 const QString additionalPath = QString(
"%1/lib/bin").arg(m_pythonHome);
326 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
327 QString
path = env.value(
"PATH").append(QDir::listSeparator()).append(additionalPath);
328 env.insert(
"PATH",
path);
329 pythonProcess.setProcessEnvironment(env);
343 QProcess pythonProcess;
354 QMessageBox::warning(
356 "Invalid Python Environment",
357 "The selected directory does not seems to be a valid python environment");
363 QMessageBox::warning(
365 "Incompatible Python Environment",
366 QString(
"The selected directory does not contain a Python Environment that is "
367 "compatible. Expected a python version like %1.%2.x, selected environment "
368 "has version %3.%4.%5")
382 return qEnvironmentVariableIsSet(
"CONDA_PREFIX") || qEnvironmentVariableIsSet(
"VIRTUAL_ENV");
389 QString root = qEnvironmentVariable(
"CONDA_PREFIX");
398 root = qEnvironmentVariable(
"VIRTUAL_ENV");
414 const QString pythonPathScript = QStringLiteral(
415 "import os;import sys;print(os.pathsep.join(sys.path[1:]));print(sys.prefix, end='')");
417 QProcess pythonProcess;
418 pythonProcess.setProgram(pythonExecutable);
419 pythonProcess.setArguments({
"-c", pythonPathScript});
420 pythonProcess.start(QIODevice::ReadOnly);
421 pythonProcess.waitForFinished();
424 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
425 QString::fromUtf8(pythonProcess.readAllStandardOutput());
430 QStringList pathsAndHome =
result.split(
'\n');
432 if (pathsAndHome.size() != 2)
434 plgPrint() <<
"pythonExecutable: " << pythonExecutable;
435 plgWarning() <<
"'" <<
result <<
"' could not be parsed as a list if paths and a home path."
436 <<
"Expected 2 strings found " << pathsAndHome.size();
440 m_pythonPath = pathsAndHome.takeFirst();
441 m_pythonHome = pathsAndHome.takeFirst();
443 #if defined(USE_EMBEDDED_MODULES)
444 m_pythonPath.append(BundledSitePackagesPath());
static QString PathToPythonExecutableInEnv(PythonConfig::Type envType, const QString &envRoot)
static Version GetPythonExeVersion(QProcess &pythonProcess)
constexpr Version PythonVersion(PY_MAJOR_VERSION, PY_MINOR_VERSION, PY_MICRO_VERSION)
Python Version the plugin was compiled against.
QtCompatTextCodec * qtCompatCodecForName(const char *name)
QString qtCompatStringRefToString(const QStringView &view)
QStringView QtCompatStringRef
QtCompatStringRefList qtCompatSplitRefChar(const QString &str, QChar sep)
QStringView qtCompatStringRef(const QString &str) noexcept
PluginLogger< CVLog::LOG_WARNING > plgWarning
wchar_t * QStringToWcharArray(const QString &string)
Returns a newly allocated wchar_t array (null terminated) from a QString.
PluginLogger< CVLog::LOG_STANDARD > plgPrint
const wchar_t * pythonPath() const
Returns the pythonPath.
const wchar_t * pythonHome() const
Returns the pythonHome.
bool isSet() const
returns true if both paths are non empty
Version getVersion() const
static PythonConfig fromContainingEnvironment()
bool validateAndDisplayErrors(QWidget *parent=nullptr) const
PythonConfigPaths pythonCompatiblePaths() const
void initFromLocation(const QString &prefix)
void preparePythonProcess(QProcess &pythonProcess) const
void initFromPythonExecutable(const QString &pythonExecutable)
static bool IsInsideEnvironment()
void initCondaEnv(const QString &condaPrefix)
Initialize the paths to use the conda environment stored at condaPrefix.
void initVenv(const QString &venvPrefix)
Initialize the paths to use the python venv stored at venvPrefix.
QString toUnicode(const char *chars, int len=-1)
static const std::string path
std::string toString(T x)
static PyVenvCfg FromFile(const QString &path)
bool includeSystemSitesPackages
Simple representation of a SemVer version.
constexpr Version()=default
bool operator==(const Version &other) const
bool isCompatibleWithCompiledVersion() const