From 888333ef03df6e1705d115570616d25900083ab3 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Mon, 22 Mar 2021 12:07:59 -0700 Subject: [PATCH] Fallback to jedi when using python 2.7, <=3.5 (#15734) * Fallback to jedi when using 2.7 * Address comments. * Update jedi-language-server to latest again --- .github/actions/build-vsix/action.yml | 3 + gulpfile.js | 33 ++++++- jedils_requirements.in | 6 ++ jedils_requirements.txt | 95 +++++++++++++++++++ news/2 Fixes/15724.md | 1 + pythonFiles/run-jedi-language-server.py | 11 +++ pythonFiles/runJediLanguageServer.py | 91 ------------------ requirements.in | 3 - requirements.txt | 22 +---- src/client/activation/activationService.ts | 7 ++ .../activation/jedi/languageClientFactory.ts | 2 +- src/client/telemetry/constants.ts | 1 + src/client/telemetry/index.ts | 4 + 13 files changed, 161 insertions(+), 118 deletions(-) create mode 100644 jedils_requirements.in create mode 100644 jedils_requirements.txt create mode 100644 news/2 Fixes/15724.md create mode 100644 pythonFiles/run-jedi-language-server.py delete mode 100644 pythonFiles/runJediLanguageServer.py diff --git a/.github/actions/build-vsix/action.yml b/.github/actions/build-vsix/action.yml index ece1a773a12b..dc4518f5712a 100644 --- a/.github/actions/build-vsix/action.yml +++ b/.github/actions/build-vsix/action.yml @@ -16,6 +16,9 @@ runs: - run: python -m pip --disable-pip-version-check install -t ./pythonFiles/lib/python --no-cache-dir --implementation py --no-deps --upgrade -r requirements.txt shell: bash + - run: python -m pip --disable-pip-version-check install -t ./pythonFiles/lib/jedilsp --no-cache-dir --implementation py --no-deps --upgrade -r jedils_requirements.txt + shell: bash + - run: | python -m pip --disable-pip-version-check install -r build/debugger-install-requirements.txt python ./pythonFiles/install_debugpy.py diff --git a/gulpfile.js b/gulpfile.js index 367b74079a6a..7ea0c9f9b4aa 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -215,7 +215,7 @@ gulp.task('checkDependencies', gulp.series('checkNativeDependencies')); gulp.task('prePublishNonBundle', gulp.series('compile', 'compile-webviews')); gulp.task('installPythonRequirements', async () => { - const args = [ + let args = [ '-m', 'pip', '--disable-pip-version-check', @@ -230,7 +230,36 @@ gulp.task('installPythonRequirements', async () => { '-r', './requirements.txt', ]; - const success = await spawnAsync(process.env.CI_PYTHON_PATH || 'python3', args, undefined, true) + let success = await spawnAsync(process.env.CI_PYTHON_PATH || 'python3', args, undefined, true) + .then(() => true) + .catch((ex) => { + console.error("Failed to install Python Libs using 'python3'", ex); + return false; + }); + if (!success) { + console.info("Failed to install Python Libs using 'python3', attempting to install using 'python'"); + await spawnAsync('python', args).catch((ex) => + console.error("Failed to install Python Libs using 'python'", ex), + ); + return; + } + + args = [ + '-m', + 'pip', + '--disable-pip-version-check', + 'install', + '-t', + './pythonFiles/lib/jedilsp', + '--no-cache-dir', + '--implementation', + 'py', + '--no-deps', + '--upgrade', + '-r', + './jedils_requirements.txt', + ]; + success = await spawnAsync(process.env.CI_PYTHON_PATH || 'python3', args, undefined, true) .then(() => true) .catch((ex) => { console.error("Failed to install Python Libs using 'python3'", ex); diff --git a/jedils_requirements.in b/jedils_requirements.in new file mode 100644 index 000000000000..84d1c3d19fcb --- /dev/null +++ b/jedils_requirements.in @@ -0,0 +1,6 @@ +# This file is used to generate requirements.txt. +# To update requirements.txt, run the following commands. +# 1) pip install pip-tools +# 2) pip-compile --generate-hashes jedils_requirements.in + +jedi-language-server diff --git a/jedils_requirements.txt b/jedils_requirements.txt new file mode 100644 index 000000000000..b8e57c36142a --- /dev/null +++ b/jedils_requirements.txt @@ -0,0 +1,95 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile --generate-hashes jedils_requirements.in +# +click==7.1.2 \ + --hash=sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a \ + --hash=sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc + # via jedi-language-server +docstring-to-markdown==0.7 \ + --hash=sha256:374bad3595b970bc558e1422225f313229988424d5b242d85cbda7da30370375 \ + --hash=sha256:d1811fb2ad38bf8ac24e8bac6c74503cdb120a6a3b2c62bf9a0ab44a59656901 + # via jedi-language-server +jedi-language-server==0.28.7 \ + --hash=sha256:7d22a87cf2017f439f872e7d630101969dcff4ef2aa061d10aa697b42de7351c \ + --hash=sha256:8a53e65d4dff8aff74626d729c942a4b887f63b241270dba9cb4ebefaa92a006 + # via -r jedils_requirements.in +jedi==0.18.0 \ + --hash=sha256:18456d83f65f400ab0c2d3319e48520420ef43b23a086fdc05dff34132f0fb93 \ + --hash=sha256:92550a404bad8afed881a137ec9a461fed49eca661414be45059329614ed0707 + # via jedi-language-server +parso==0.8.1 \ + --hash=sha256:15b00182f472319383252c18d5913b69269590616c947747bc50bf4ac768f410 \ + --hash=sha256:8519430ad07087d4c997fda3a7918f7cfa27cb58972a8c89c2a0295a1c940e9e + # via jedi +psutil==5.8.0 \ + --hash=sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64 \ + --hash=sha256:02b8292609b1f7fcb34173b25e48d0da8667bc85f81d7476584d889c6e0f2131 \ + --hash=sha256:0ae6f386d8d297177fd288be6e8d1afc05966878704dad9847719650e44fc49c \ + --hash=sha256:0c9ccb99ab76025f2f0bbecf341d4656e9c1351db8cc8a03ccd62e318ab4b5c6 \ + --hash=sha256:0dd4465a039d343925cdc29023bb6960ccf4e74a65ad53e768403746a9207023 \ + --hash=sha256:12d844996d6c2b1d3881cfa6fa201fd635971869a9da945cf6756105af73d2df \ + --hash=sha256:1bff0d07e76114ec24ee32e7f7f8d0c4b0514b3fae93e3d2aaafd65d22502394 \ + --hash=sha256:245b5509968ac0bd179287d91210cd3f37add77dad385ef238b275bad35fa1c4 \ + --hash=sha256:28ff7c95293ae74bf1ca1a79e8805fcde005c18a122ca983abf676ea3466362b \ + --hash=sha256:36b3b6c9e2a34b7d7fbae330a85bf72c30b1c827a4366a07443fc4b6270449e2 \ + --hash=sha256:52de075468cd394ac98c66f9ca33b2f54ae1d9bff1ef6b67a212ee8f639ec06d \ + --hash=sha256:5da29e394bdedd9144c7331192e20c1f79283fb03b06e6abd3a8ae45ffecee65 \ + --hash=sha256:61f05864b42fedc0771d6d8e49c35f07efd209ade09a5afe6a5059e7bb7bf83d \ + --hash=sha256:6223d07a1ae93f86451d0198a0c361032c4c93ebd4bf6d25e2fb3edfad9571ef \ + --hash=sha256:6323d5d845c2785efb20aded4726636546b26d3b577aded22492908f7c1bdda7 \ + --hash=sha256:6ffe81843131ee0ffa02c317186ed1e759a145267d54fdef1bc4ea5f5931ab60 \ + --hash=sha256:74f2d0be88db96ada78756cb3a3e1b107ce8ab79f65aa885f76d7664e56928f6 \ + --hash=sha256:74fb2557d1430fff18ff0d72613c5ca30c45cdbfcddd6a5773e9fc1fe9364be8 \ + --hash=sha256:90d4091c2d30ddd0a03e0b97e6a33a48628469b99585e2ad6bf21f17423b112b \ + --hash=sha256:90f31c34d25b1b3ed6c40cdd34ff122b1887a825297c017e4cbd6796dd8b672d \ + --hash=sha256:99de3e8739258b3c3e8669cb9757c9a861b2a25ad0955f8e53ac662d66de61ac \ + --hash=sha256:c6a5fd10ce6b6344e616cf01cc5b849fa8103fbb5ba507b6b2dee4c11e84c935 \ + --hash=sha256:ce8b867423291cb65cfc6d9c4955ee9bfc1e21fe03bb50e177f2b957f1c2469d \ + --hash=sha256:d225cd8319aa1d3c85bf195c4e07d17d3cd68636b8fc97e6cf198f782f99af28 \ + --hash=sha256:ea313bb02e5e25224e518e4352af4bf5e062755160f77e4b1767dd5ccb65f876 \ + --hash=sha256:ea372bcc129394485824ae3e3ddabe67dc0b118d262c568b4d2602a7070afdb0 \ + --hash=sha256:f4634b033faf0d968bb9220dd1c793b897ab7f1189956e1aa9eae752527127d3 \ + --hash=sha256:fcc01e900c1d7bee2a37e5d6e4f9194760a93597c97fee89c4ae51701de03563 + # via pygls +pydantic==1.8.1 \ + --hash=sha256:0c40162796fc8d0aa744875b60e4dc36834db9f2a25dbf9ba9664b1915a23850 \ + --hash=sha256:20d42f1be7c7acc352b3d09b0cf505a9fab9deb93125061b376fbe1f06a5459f \ + --hash=sha256:2287ebff0018eec3cc69b1d09d4b7cebf277726fa1bd96b45806283c1d808683 \ + --hash=sha256:258576f2d997ee4573469633592e8b99aa13bda182fcc28e875f866016c8e07e \ + --hash=sha256:26cf3cb2e68ec6c0cfcb6293e69fb3450c5fd1ace87f46b64f678b0d29eac4c3 \ + --hash=sha256:2f2736d9a996b976cfdfe52455ad27462308c9d3d0ae21a2aa8b4cd1a78f47b9 \ + --hash=sha256:3114d74329873af0a0e8004627f5389f3bb27f956b965ddd3e355fe984a1789c \ + --hash=sha256:3bbd023c981cbe26e6e21c8d2ce78485f85c2e77f7bab5ec15b7d2a1f491918f \ + --hash=sha256:3bcb9d7e1f9849a6bdbd027aabb3a06414abd6068cb3b21c49427956cce5038a \ + --hash=sha256:4bbc47cf7925c86a345d03b07086696ed916c7663cb76aa409edaa54546e53e2 \ + --hash=sha256:6388ef4ef1435364c8cc9a8192238aed030595e873d8462447ccef2e17387125 \ + --hash=sha256:830ef1a148012b640186bf4d9789a206c56071ff38f2460a32ae67ca21880eb8 \ + --hash=sha256:8fbb677e4e89c8ab3d450df7b1d9caed23f254072e8597c33279460eeae59b99 \ + --hash=sha256:c17a0b35c854049e67c68b48d55e026c84f35593c66d69b278b8b49e2484346f \ + --hash=sha256:dd4888b300769ecec194ca8f2699415f5f7760365ddbe243d4fd6581485fa5f0 \ + --hash=sha256:dde4ca368e82791de97c2ec019681ffb437728090c0ff0c3852708cf923e0c7d \ + --hash=sha256:e3f8790c47ac42549dc8b045a67b0ca371c7f66e73040d0197ce6172b385e520 \ + --hash=sha256:e8bc082afef97c5fd3903d05c6f7bb3a6af9fc18631b4cc9fedeb4720efb0c58 \ + --hash=sha256:eb8ccf12295113ce0de38f80b25f736d62f0a8d87c6b88aca645f168f9c78771 \ + --hash=sha256:fb77f7a7e111db1832ae3f8f44203691e15b1fa7e5a1cb9691d4e2659aee41c4 \ + --hash=sha256:fbfb608febde1afd4743c6822c19060a8dbdd3eb30f98e36061ba4973308059e \ + --hash=sha256:fff29fe54ec419338c522b908154a2efabeee4f483e48990f87e189661f31ce3 + # via + # jedi-language-server + # pygls +pygls==0.10.1 \ + --hash=sha256:133b3987fc6dee992dc32b9a77f1452f9de44cb7141328b5c85a184e68c083d5 \ + --hash=sha256:ab0cd3273e265e792b926ad621ab10199a3bd0e7b8786233e9eda54cc1071e3a + # via jedi-language-server +typeguard==2.11.1 \ + --hash=sha256:33243c1cbfcb9736a06c6db22dd08876b5f297e6344aa272a2862c0f8e669f64 \ + --hash=sha256:c62706201ec6c14962162fa67d70bd2762753247533d70ff2442e5ac08f94fa2 + # via pygls +typing-extensions==3.7.4.3 \ + --hash=sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918 \ + --hash=sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c \ + --hash=sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f + # via pydantic diff --git a/news/2 Fixes/15724.md b/news/2 Fixes/15724.md new file mode 100644 index 000000000000..adcb42676dcf --- /dev/null +++ b/news/2 Fixes/15724.md @@ -0,0 +1 @@ +Upgrade to latest `jedi-language-server` and use it for python >= 3.6. Use `jedi<0.18` for python 2.7 and <=3.5. diff --git a/pythonFiles/run-jedi-language-server.py b/pythonFiles/run-jedi-language-server.py new file mode 100644 index 000000000000..31095121409f --- /dev/null +++ b/pythonFiles/run-jedi-language-server.py @@ -0,0 +1,11 @@ +import sys +import os + +# Add the lib path to our sys path so jedi_language_server can find its references +EXTENSION_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, os.path.join(EXTENSION_ROOT, "pythonFiles", "lib", "jedilsp")) + + +from jedi_language_server.cli import cli + +sys.exit(cli()) diff --git a/pythonFiles/runJediLanguageServer.py b/pythonFiles/runJediLanguageServer.py deleted file mode 100644 index 538a22dbcb71..000000000000 --- a/pythonFiles/runJediLanguageServer.py +++ /dev/null @@ -1,91 +0,0 @@ -import sys -import os - -# Add the lib path to our sys path so jedi_language_server can find its references -EXTENSION_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -sys.path.insert(0, os.path.join(EXTENSION_ROOT, "pythonFiles", "lib", "python")) - -import pygls.protocol - -try: - unicode -except Exception: - unicode = str - - -def is_json_basic_type(obj): - """Checks if the object is an int, float, bool, or str.""" - if isinstance(obj, (int, float, bool, str)): - return True - return sys.version_info < (3,) and isinstance(obj, unicode) - - -def handle_null_fields(obj, obj_field_name=None): - """Removes fields with a 'None' value. - - The LS Client in VS Code expects optional fields that are not needed - to be omitted. Unfortunately, pygls uses 'null' in these instances. - """ - # This is a temporary workaround to address the following issues: - # https://github.com/microsoft/vscode-languageserver-node/issues/740#issuecomment-773967897 - # https://github.com/pappasam/jedi-language-server/issues/60 - # https://github.com/openlawlibrary/pygls/issues/145 - # https://github.com/microsoft/vscode-languageserver-node/issues/740 - if is_json_basic_type(obj): - return - elif isinstance(obj, list): - for o in obj: - handle_null_fields(o, obj_field_name) - return - elif isinstance(obj, dict): - for k, v in obj.items(): - handle_null_fields(v, k) - - important_attribute = lambda x: not x.startswith("_") and not callable( - getattr(obj, x) - ) - - for attr in filter(important_attribute, dir(obj)): - member = getattr(obj, attr) - if member is None: - # This is a special condition to handle VersionedTextDocumentIdentifier object. - # See issues: - # https://github.com/pappasam/jedi-language-server/issues/61 - # https://github.com/openlawlibrary/pygls/issues/146 - # - # The version field should either use `0` or the value received from `client`. - # Seems like using `null` or removing this causes VS Code to ignore - # code actions. - if ( - attr == "version" - and obj_field_name == "textDocument" - and "uri" in dir(obj) - ): - setattr(obj, "version", 0) - else: - delattr(obj, attr) - - elif is_json_basic_type(member): - continue - - else: - handle_null_fields(member, attr) - - -def patched_without_none_fields(resp): - """Monkeypatch for `JsonRPCResponseMessage.without_none_fields` to remove `None` results.""" - if resp.error is None: - del resp.error - if hasattr(resp, "result"): - handle_null_fields(resp.result) - else: - del resp.result - return resp - - -pygls.protocol.JsonRPCResponseMessage.without_none_fields = patched_without_none_fields - - -from jedi_language_server.cli import cli - -sys.exit(cli()) diff --git a/requirements.in b/requirements.in index c3fe1e770589..8a3b585d6a90 100644 --- a/requirements.in +++ b/requirements.in @@ -5,8 +5,5 @@ # IntelliSense via Jedi jedi<0.18 # For Python 2.7 support -pygls; python_version >= '3.6' # To make requirements.txt keep the marker to avoid Python 2.7. -jedi-language-server<0.22; python_version >= '3.6' # To work with Jedi 0.17. # Sort Imports isort==5.7.0; python_version >= '3.6' -cached-property>=1.5.1 diff --git a/requirements.txt b/requirements.txt index f28c93fb237d..6de728e72a50 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,35 +4,15 @@ # # pip-compile --generate-hashes requirements.in # -cached-property==1.5.2 \ - --hash=sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130 \ - --hash=sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0 - # via -r requirements.in -click==7.1.2 \ - --hash=sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a \ - --hash=sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc - # via jedi-language-server isort==5.7.0 ; python_version >= "3.6" \ --hash=sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e \ --hash=sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc # via -r requirements.in -jedi-language-server==0.21.0 ; python_version >= "3.6" \ - --hash=sha256:7d7ffcb884ac469be1d1d7d286c1c9484c25f08b049c951bec8bf4c88e0cc6b0 \ - --hash=sha256:bb9d5e5c0aadf69cc441263685c83c12e67b6ed6f546dbd92dbed417123d8a47 - # via -r requirements.in jedi==0.17.2 \ --hash=sha256:86ed7d9b750603e4ba582ea8edc678657fb4007894a12bcf6f4bb97892f31d20 \ --hash=sha256:98cc583fa0f2f8304968199b01b6b4b94f469a1f4a74c1560506ca2a211378b5 - # via - # -r requirements.in - # jedi-language-server + # via -r requirements.in parso==0.7.1 \ --hash=sha256:97218d9159b2520ff45eb78028ba8b50d2bc61dcc062a9682666f2dc4bd331ea \ --hash=sha256:caba44724b994a8a5e086460bb212abc5a8bc46951bf4a9a1210745953622eb9 # via jedi -pygls==0.9.1 ; python_version >= "3.6" \ - --hash=sha256:89b4361e0ba38effdfc735e25ae207c8af2f4d4ce26961e8628b600f19b16ed4 \ - --hash=sha256:c21c942415457315f316c0b6c19d4c743fd2974d457e02a85472154c8f1b6399 - # via - # -r requirements.in - # jedi-language-server diff --git a/src/client/activation/activationService.ts b/src/client/activation/activationService.ts index 6e9735fb0135..7721feda490a 100644 --- a/src/client/activation/activationService.ts +++ b/src/client/activation/activationService.ts @@ -233,6 +233,13 @@ export class LanguageServerExtensionActivationService } } + if (serverType === LanguageServerType.JediLSP && interpreter && interpreter.version) { + if (interpreter.version.major < 3 || (interpreter.version.major === 3 && interpreter.version.minor < 6)) { + sendTelemetryEvent(EventName.JEDI_LANGUAGE_SERVER_FALLBACK); + serverType = LanguageServerType.Jedi; + } + } + this.sendTelemetryForChosenLanguageServer(serverType).ignoreErrors(); await this.logStartup(serverType); diff --git a/src/client/activation/jedi/languageClientFactory.ts b/src/client/activation/jedi/languageClientFactory.ts index 16ff56682d41..82616ca36f15 100644 --- a/src/client/activation/jedi/languageClientFactory.ts +++ b/src/client/activation/jedi/languageClientFactory.ts @@ -23,7 +23,7 @@ export class JediLanguageClientFactory implements ILanguageClientFactory { clientOptions: LanguageClientOptions, ): Promise { // Just run the language server using a module - const lsScriptPath = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'runJediLanguageServer.py'); + const lsScriptPath = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'run-jedi-language-server.py'); const interpreter = await this.interpreterService.getActiveInterpreter(resource); const serverOptions: ServerOptions = { command: interpreter ? interpreter.path : 'python', diff --git a/src/client/telemetry/constants.ts b/src/client/telemetry/constants.ts index fe96b62ba88a..c2e1d202111a 100644 --- a/src/client/telemetry/constants.ts +++ b/src/client/telemetry/constants.ts @@ -121,6 +121,7 @@ export enum EventName { HASHED_PACKAGE_PERF = 'HASHED_PACKAGE_PERF', JEDI_MEMORY = 'JEDI_MEMORY', + JEDI_LANGUAGE_SERVER_FALLBACK = 'JEDI_FALLBACK', JEDI_LANGUAGE_SERVER_ENABLED = 'JEDI_LANGUAGE_SERVER.ENABLED', JEDI_LANGUAGE_SERVER_STARTUP = 'JEDI_LANGUAGE_SERVER.STARTUP', JEDI_LANGUAGE_SERVER_READY = 'JEDI_LANGUAGE_SERVER.READY', diff --git a/src/client/telemetry/index.ts b/src/client/telemetry/index.ts index 09ee984885c9..c95839ae4e3f 100644 --- a/src/client/telemetry/index.ts +++ b/src/client/telemetry/index.ts @@ -1370,6 +1370,10 @@ export interface IEventNamePropertyMapping { */ userAction: string; }; + /** + * Telemetry event sent when we fallback from JediLSP to Jedi + */ + [EventName.JEDI_LANGUAGE_SERVER_FALLBACK]: unknown; /** * Telemetry event sent when Jedi Language Server is started for workspace (workspace folder in case of multi-root) */