diff options
| author | David Schulz <david.schulz@qt.io> | 2025-02-07 14:06:06 +0100 |
|---|---|---|
| committer | David Schulz <david.schulz@qt.io> | 2025-02-10 13:03:28 +0000 |
| commit | 1ca67ada59de4a8c055c9f84821f6591c99d7d26 (patch) | |
| tree | 804cf54b002d42d628880b3521638a6351c70d28 /src/plugins/python/pythonlanguageclient.cpp | |
| parent | 7046c208d19826eb6d8fee45c1ccdd821f253577 (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.cpp | 81 |
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(); } |
