aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/python/pythonlanguageclient.cpp
diff options
context:
space:
mode:
authorDavid Schulz <david.schulz@qt.io>2025-02-07 14:06:06 +0100
committerDavid Schulz <david.schulz@qt.io>2025-02-10 13:03:28 +0000
commit1ca67ada59de4a8c055c9f84821f6591c99d7d26 (patch)
tree804cf54b002d42d628880b3521638a6351c70d28 /src/plugins/python/pythonlanguageclient.cpp
parent7046c208d19826eb6d8fee45c1ccdd821f253577 (diff)
Python: Fix check for outdated pyls
Unfortunately pip still reports the python language server as outdated even if the package was updated, most likely since the old package is still in that directory. So instead of purely relying on the pip output we compare the pip reported current version against the version the python language server reports when startet with "--version". Since neither the pip nor the version check is completely free we cache this information now in case the server is installed or it is not and no pip is available. Change-Id: I3a56fd5240672555bd54e92685c0c58c4dc95d7c Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/plugins/python/pythonlanguageclient.cpp')
-rw-r--r--src/plugins/python/pythonlanguageclient.cpp81
1 files changed, 48 insertions, 33 deletions
diff --git a/src/plugins/python/pythonlanguageclient.cpp b/src/plugins/python/pythonlanguageclient.cpp
index 87cb1915023..e074a446820 100644
--- a/src/plugins/python/pythonlanguageclient.cpp
+++ b/src/plugins/python/pythonlanguageclient.cpp
@@ -79,43 +79,58 @@ static FilePath pyLspPath(const FilePath &python)
static PythonLanguageServerState checkPythonLanguageServer(const FilePath &python)
{
+ static QHash<FilePath, PythonLanguageServerState> m_stateCache;
using namespace LanguageClient;
- auto lspPath = pyLspPath(python);
- if (lspPath.isEmpty())
- return {PythonLanguageServerState::NotInstallable, FilePath()};
-
- Process pythonProcess;
- pythonProcess.setCommand({python, {"-m", "pip", "-V"}});
- using namespace std::chrono_literals;
- pythonProcess.runBlocking(2s);
- bool pipAvailable = pythonProcess.allOutput().startsWith("pip ");
-
- if (lspPath.pathAppended("bin").pathAppended("pylsp").withExecutableSuffix().exists()) {
- if (pipAvailable) {
- Process pythonProcess;
- Environment env = pythonProcess.environment();
- env.set("PYTHONPATH", lspPath.toUserOutput());
- pythonProcess.setEnvironment(env);
- pythonProcess.setCommand({python, {"-m", "pip", "list", "--outdated", "--format=json"}});
- pythonProcess.runBlocking(20s);
- QString output = pythonProcess.allOutput();
-
- // Only the first line contains the json data. Following lines might contain warnings.
- if (int index = output.indexOf('\n'); index >= 0)
- output.truncate(index);
-
- const QJsonDocument doc = QJsonDocument::fromJson(output.toUtf8());
- for (const QJsonValue &value : doc.array()) {
- if (value.toObject().value("name") == "python-lsp-server")
- return {PythonLanguageServerState::Updatable, lspPath};
+ using namespace std::chrono;
+
+ if (auto it = m_stateCache.find(python); it != m_stateCache.end())
+ return it.value();
+
+ const FilePath lspPath = pyLspPath(python);
+ if (!lspPath.isEmpty()) {
+ bool pipAvailable = pipIsUsable(python);
+
+ const FilePath pylsp = (lspPath / "bin" / "pylsp").withExecutableSuffix();
+ if (pylsp.exists()) {
+ if (pipAvailable) {
+ Process pythonProcess;
+ Environment env = pylsp.deviceEnvironment();
+ env.appendOrSet("PYTHONPATH", lspPath.toUserOutput());
+ pythonProcess.setEnvironment(env);
+ pythonProcess.setCommand(
+ {python, {"-m", "pip", "list", "--outdated", "--format=json"}});
+ pythonProcess.runBlocking(20s);
+ QString output = pythonProcess.allOutput();
+
+ // Only the first line contains the json data. Following lines might contain warnings.
+ if (int index = output.indexOf('\n'); index >= 0)
+ output.truncate(index);
+
+ const QJsonDocument doc = QJsonDocument::fromJson(output.toUtf8());
+ for (const QJsonValue &value : doc.array()) {
+ if (value.toObject().value("name") == "python-lsp-server") {
+ Process pylsProcess;
+ Environment env = pylsp.deviceEnvironment();
+ env.appendOrSet("PYTHONPATH", lspPath.toUserOutput());
+ pylsProcess.setEnvironment(env);
+ pylsProcess.setCommand({pylsp, {"--version"}});
+ pylsProcess.runBlocking(20s);
+ output = pylsProcess.allOutput();
+ if (!output.contains(value.toObject().value("latest_version").toString()))
+ return {PythonLanguageServerState::Updatable, lspPath};
+ break;
+ }
+ }
}
+ return m_stateCache.insert(python, {PythonLanguageServerState::Installed, lspPath})
+ .value();
}
- return {PythonLanguageServerState::Installed, lspPath};
- }
- if (pipAvailable)
- return {PythonLanguageServerState::Installable, lspPath};
- return {PythonLanguageServerState::NotInstallable, FilePath()};
+ if (pipAvailable)
+ return {PythonLanguageServerState::Installable, lspPath};
+ }
+ return m_stateCache.insert(python, {PythonLanguageServerState::NotInstallable, FilePath()})
+ .value();
}