Python: optimize the pip and venv checks

Those checks can take an considerable amount of time. So instead of
running them the first time we want to check this info run them in the
background as soon as we have loaded the python settings.

Change-Id: I287acd2a5fd7b053873257238f7dfbaa9cf00170
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2024-12-12 11:50:31 +01:00
parent 5fa27341fe
commit 94c4360085
2 changed files with 36 additions and 20 deletions

View File

@@ -855,11 +855,18 @@ QString PythonSettings::pylsConfiguration()
return settingsInstance->m_pylsConfiguration;
}
static void cacheVenvAndPipUsability(const Interpreter &interpreter)
{
Utils::asyncRun(&venvIsUsable, interpreter.command);
Utils::asyncRun(&pipIsUsable, interpreter.command);
}
void PythonSettings::addInterpreter(const Interpreter &interpreter, bool isDefault)
{
if (Utils::anyOf(settingsInstance->m_interpreters, Utils::equal(&Interpreter::id, interpreter.id)))
return;
settingsInstance->m_interpreters.append(interpreter);
cacheVenvAndPipUsability(interpreter);
if (isDefault)
settingsInstance->m_defaultInterpreterId = interpreter.id;
saveSettings();
@@ -1026,8 +1033,12 @@ void PythonSettings::initFromSettings(QtcSettings *settings)
const auto [valid, outdatedInterpreters] = Utils::partition(m_interpreters, keepInterpreter);
m_interpreters = valid;
if (!settings->value(kitsGeneratedKey, false).toBool()) {
for (const Interpreter &interpreter : m_interpreters) {
const bool kitsGenerated = settings->value(kitsGeneratedKey, false).toBool();
if (kitsGenerated)
fixupPythonKits();
for (const Interpreter &interpreter : std::as_const(m_interpreters)) {
cacheVenvAndPipUsability(interpreter);
if (!kitsGenerated) {
if (interpreter.autoDetected) {
const FilePath &cmd = interpreter.command;
if (!cmd.isLocal() || cmd.parentDir().pathAppended("activate").exists())
@@ -1035,8 +1046,6 @@ void PythonSettings::initFromSettings(QtcSettings *settings)
}
addKitsForInterpreter(interpreter, false);
}
} else {
fixupPythonKits();
}
for (const Interpreter &outdated : outdatedInterpreters)

View File

@@ -20,6 +20,7 @@
#include <utils/algorithm.h>
#include <utils/mimeutils.h>
#include <utils/qtcprocess.h>
#include <utils/synchronizedvalue.h>
#include <QReadLocker>
@@ -192,31 +193,37 @@ bool isVenvPython(const FilePath &python)
return python.parentDir().parentDir().pathAppended("pyvenv.cfg").exists();
}
static bool isUsableHelper(QHash<FilePath, bool> *cache, const QString &keyString,
const QString &commandArg, const FilePath &python)
static bool isUsableHelper(
SynchronizedValue<QHash<FilePath, bool>> *cache,
const QString &commandArg,
const FilePath &python)
{
auto it = cache->find(python);
if (it == cache->end()) {
const Key key = keyFromString(keyString);
std::optional<bool> result;
cache->read([&result, python](const QHash<FilePath, bool> &cache) {
if (auto it = cache.find(python); it != cache.end())
result = it.value();
});
if (result)
return *result;
Process process;
process.setCommand({python, {"-m", commandArg, "-h"}});
process.runBlocking();
const bool usable = process.result() == ProcessResult::FinishedWithSuccess;
it = cache->insert(python, usable);
}
return *it;
cache->writeLocked()->insert(python, usable);
return usable;
}
bool venvIsUsable(const FilePath &python)
{
static QHash<FilePath, bool> cache;
return isUsableHelper(&cache, "pyVenvIsUsable", "venv", python);
static SynchronizedValue<QHash<FilePath, bool>> cache;
return isUsableHelper(&cache, "venv", python);
}
bool pipIsUsable(const FilePath &python)
{
static QHash<FilePath, bool> cache;
return isUsableHelper(&cache, "pyPipIsUsable", "pip", python);
static SynchronizedValue<QHash<FilePath, bool>> cache;
return isUsableHelper(&cache, "pip", python);
}
QString pythonVersion(const FilePath &python)