Skip to content

Commit abcbe77

Browse files
Copilotedvilme
andauthored
Update to Pygls 2.0 with minimum Python 3.10 (#274)
* Initial plan * Update to pygls 2.0: migrate APIs and regenerate requirements - Import LanguageServer from pygls.lsp.server instead of pygls.server - Rename workspace.Document → workspace.TextDocument - Rename get_document() → get_text_document() - Rename publish_diagnostics() → text_document_publish_diagnostics() - Rename show_message_log() → window_log_message() with LogMessageParams - Rename show_message() → window_show_message() with ShowMessageParams - Update lsprotocol import style to match upgraded extensions - Regenerate requirements.txt with pygls==2.0.1, lsprotocol==2025.0.0 - Update test mocks for pygls 2.0 module structure Co-authored-by: edvilme <5952839+edvilme@users.noreply.github.com> * Update minimum Python version from 3.9 to 3.10 - Update runtime.txt to python-3.10.16 - Update Python version check in python.ts and extension.ts - Update README.md requirements section - Update comments in requirements.in files Co-authored-by: edvilme <5952839+edvilme@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: edvilme <5952839+edvilme@users.noreply.github.com>
1 parent e71e1cf commit abcbe77

File tree

10 files changed

+186
-193
lines changed

10 files changed

+186
-193
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ The TypeScript part handles working with VS Code and its UI. The extension templ
1313
## Requirements
1414

1515
1. VS Code 1.64.0 or greater
16-
1. Python 3.9 or greater
16+
1. Python 3.10 or greater
1717
1. node >= 18.17.0
1818
1. npm >= 8.19.0 (`npm` is installed with node, check npm version, use `npm install -g npm@8.3.0` to update)
1919
1. Python extension for VS Code
@@ -24,7 +24,7 @@ You should know to create and work with python virtual environments.
2424

2525
1. Use this [template to create your repo](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template).
2626
1. Check-out your repo locally on your development machine.
27-
1. Create and activate a python virtual environment for this project in a terminal. Be sure to use the minimum version of python for your tool. This template was written to work with python 3.9 or greater.
27+
1. Create and activate a python virtual environment for this project in a terminal. Be sure to use the minimum version of python for your tool. This template was written to work with python 3.10 or greater.
2828
1. Install `nox` in the activated environment: `python -m pip install nox`.
2929
1. Add your favorite tool to `requirements.in`
3030
1. Run `nox --session setup`.

bundled/tool/lsp_server.py

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,17 @@ def update_sys_path(path_to_add: str, strategy: str) -> None:
3838
# pylint: disable=wrong-import-position,import-error
3939
import lsp_jsonrpc as jsonrpc
4040
import lsp_utils as utils
41-
import lsprotocol.types as lsp
42-
from pygls import server, uris, workspace
41+
from lsprotocol import types as lsp
42+
from pygls import uris, workspace
43+
from pygls.lsp.server import LanguageServer
4344

4445
WORKSPACE_SETTINGS = {}
4546
GLOBAL_SETTINGS = {}
4647
RUNNER = pathlib.Path(__file__).parent / "lsp_runner.py"
4748

4849
MAX_WORKERS = 5
4950
# TODO: Update the language server name and version.
50-
LSP_SERVER = server.LanguageServer(
51+
LSP_SERVER = LanguageServer(
5152
name="<pytool-display-name>", version="<server version>", max_workers=MAX_WORKERS
5253
)
5354

@@ -91,28 +92,34 @@ def update_sys_path(path_to_add: str, strategy: str) -> None:
9192
@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DID_OPEN)
9293
def did_open(params: lsp.DidOpenTextDocumentParams) -> None:
9394
"""LSP handler for textDocument/didOpen request."""
94-
document = LSP_SERVER.workspace.get_document(params.text_document.uri)
95+
document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
9596
diagnostics: list[lsp.Diagnostic] = _linting_helper(document)
96-
LSP_SERVER.publish_diagnostics(document.uri, diagnostics)
97+
LSP_SERVER.text_document_publish_diagnostics(
98+
lsp.PublishDiagnosticsParams(uri=document.uri, diagnostics=diagnostics)
99+
)
97100

98101

99102
@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DID_SAVE)
100103
def did_save(params: lsp.DidSaveTextDocumentParams) -> None:
101104
"""LSP handler for textDocument/didSave request."""
102-
document = LSP_SERVER.workspace.get_document(params.text_document.uri)
105+
document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
103106
diagnostics: list[lsp.Diagnostic] = _linting_helper(document)
104-
LSP_SERVER.publish_diagnostics(document.uri, diagnostics)
107+
LSP_SERVER.text_document_publish_diagnostics(
108+
lsp.PublishDiagnosticsParams(uri=document.uri, diagnostics=diagnostics)
109+
)
105110

106111

107112
@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DID_CLOSE)
108113
def did_close(params: lsp.DidCloseTextDocumentParams) -> None:
109114
"""LSP handler for textDocument/didClose request."""
110-
document = LSP_SERVER.workspace.get_document(params.text_document.uri)
115+
document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
111116
# Publishing empty diagnostics to clear the entries for this file.
112-
LSP_SERVER.publish_diagnostics(document.uri, [])
117+
LSP_SERVER.text_document_publish_diagnostics(
118+
lsp.PublishDiagnosticsParams(uri=document.uri, diagnostics=[])
119+
)
113120

114121

115-
def _linting_helper(document: workspace.Document) -> list[lsp.Diagnostic]:
122+
def _linting_helper(document: workspace.TextDocument) -> list[lsp.Diagnostic]:
116123
# TODO: Determine if your tool supports passing file content via stdin.
117124
# If you want to support linting on change then your tool will need to
118125
# support linting over stdin to be effective. Read, and update
@@ -200,7 +207,7 @@ def formatting(params: lsp.DocumentFormattingParams) -> list[lsp.TextEdit] | Non
200207
# formatting support on save. You have to return an array of lsp.TextEdit
201208
# objects, to provide your formatted results.
202209

203-
document = LSP_SERVER.workspace.get_document(params.text_document.uri)
210+
document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
204211
edits = _formatting_helper(document)
205212
if edits:
206213
return edits
@@ -210,7 +217,7 @@ def formatting(params: lsp.DocumentFormattingParams) -> list[lsp.TextEdit] | Non
210217
return None
211218

212219

213-
def _formatting_helper(document: workspace.Document) -> list[lsp.TextEdit] | None:
220+
def _formatting_helper(document: workspace.TextDocument) -> list[lsp.TextEdit] | None:
214221
# TODO: For formatting on save support the formatter you use must support
215222
# formatting via stdin.
216223
# Read, and update_run_tool_on_document and _run_tool functions as needed
@@ -240,7 +247,7 @@ def _get_line_endings(lines: list[str]) -> str:
240247
return None
241248

242249

243-
def _match_line_endings(document: workspace.Document, text: str) -> str:
250+
def _match_line_endings(document: workspace.TextDocument, text: str) -> str:
244251
"""Ensures that the edited text line endings matches the document line endings."""
245252
expected = _get_line_endings(document.source.splitlines(keepends=True))
246253
actual = _get_line_endings(text.splitlines(keepends=True))
@@ -289,7 +296,7 @@ def on_shutdown(_params: Optional[Any] = None) -> None:
289296
jsonrpc.shutdown_json_rpc()
290297

291298

292-
def get_cwd(settings: dict, document: Optional[workspace.Document]) -> str:
299+
def get_cwd(settings: dict, document: Optional[workspace.TextDocument]) -> str:
293300
"""Returns the working directory for running the tool.
294301
295302
Resolves the following VS Code file-related variable substitutions when
@@ -389,7 +396,7 @@ def _get_settings_by_path(file_path: pathlib.Path):
389396
return setting_values[0]
390397

391398

392-
def _get_document_key(document: workspace.Document):
399+
def _get_document_key(document: workspace.TextDocument):
393400
if WORKSPACE_SETTINGS:
394401
document_workspace = pathlib.Path(document.path)
395402
workspaces = {s["workspaceFS"] for s in WORKSPACE_SETTINGS.values()}
@@ -403,7 +410,7 @@ def _get_document_key(document: workspace.Document):
403410
return None
404411

405412

406-
def _get_settings_by_document(document: workspace.Document | None):
413+
def _get_settings_by_document(document: workspace.TextDocument | None):
407414
if document is None or document.path is None:
408415
return list(WORKSPACE_SETTINGS.values())[0]
409416

@@ -425,7 +432,7 @@ def _get_settings_by_document(document: workspace.Document | None):
425432
# Internal execution APIs.
426433
# *****************************************************
427434
def _run_tool_on_document(
428-
document: workspace.Document,
435+
document: workspace.TextDocument,
429436
use_stdin: bool = False,
430437
extra_args: Optional[Sequence[str]] = None,
431438
) -> utils.RunResult | None:
@@ -635,25 +642,37 @@ def _run_tool(extra_args: Sequence[str]) -> utils.RunResult:
635642
def log_to_output(
636643
message: str, msg_type: lsp.MessageType = lsp.MessageType.Log
637644
) -> None:
638-
LSP_SERVER.show_message_log(message, msg_type)
645+
LSP_SERVER.window_log_message(lsp.LogMessageParams(type=msg_type, message=message))
639646

640647

641648
def log_error(message: str) -> None:
642-
LSP_SERVER.show_message_log(message, lsp.MessageType.Error)
649+
LSP_SERVER.window_log_message(
650+
lsp.LogMessageParams(type=lsp.MessageType.Error, message=message)
651+
)
643652
if os.getenv("LS_SHOW_NOTIFICATION", "off") in ["onError", "onWarning", "always"]:
644-
LSP_SERVER.show_message(message, lsp.MessageType.Error)
653+
LSP_SERVER.window_show_message(
654+
lsp.ShowMessageParams(type=lsp.MessageType.Error, message=message)
655+
)
645656

646657

647658
def log_warning(message: str) -> None:
648-
LSP_SERVER.show_message_log(message, lsp.MessageType.Warning)
659+
LSP_SERVER.window_log_message(
660+
lsp.LogMessageParams(type=lsp.MessageType.Warning, message=message)
661+
)
649662
if os.getenv("LS_SHOW_NOTIFICATION", "off") in ["onWarning", "always"]:
650-
LSP_SERVER.show_message(message, lsp.MessageType.Warning)
663+
LSP_SERVER.window_show_message(
664+
lsp.ShowMessageParams(type=lsp.MessageType.Warning, message=message)
665+
)
651666

652667

653668
def log_always(message: str) -> None:
654-
LSP_SERVER.show_message_log(message, lsp.MessageType.Info)
669+
LSP_SERVER.window_log_message(
670+
lsp.LogMessageParams(type=lsp.MessageType.Info, message=message)
671+
)
655672
if os.getenv("LS_SHOW_NOTIFICATION", "off") in ["always"]:
656-
LSP_SERVER.show_message(message, lsp.MessageType.Info)
673+
LSP_SERVER.window_show_message(
674+
lsp.ShowMessageParams(type=lsp.MessageType.Info, message=message)
675+
)
657676

658677

659678
# *****************************************************

requirements.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This file is used to generate requirements.txt.
22
# NOTE:
3-
# Use Python 3.9 or greater which ever is the minimum version of the python
3+
# Use Python 3.10 or greater which ever is the minimum version of the python
44
# you plan on supporting when creating the environment or using pip-tools.
55
# Only run the commands below to manully upgrade packages in requirements.txt:
66
# 1) python -m pip install pip-tools

requirements.txt

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,35 @@
11
#
2-
# This file is autogenerated by pip-compile with Python 3.9
2+
# This file is autogenerated by pip-compile with Python 3.12
33
# by the following command:
44
#
5-
# pip-compile --generate-hashes --output-file=requirements.txt requirements.in
5+
# pip-compile --generate-hashes ./requirements.in
66
#
7-
attrs==25.3.0 \
8-
--hash=sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3 \
9-
--hash=sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b
7+
attrs==25.4.0 \
8+
--hash=sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11 \
9+
--hash=sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373
1010
# via
1111
# cattrs
1212
# lsprotocol
13-
cattrs==24.1.3 \
14-
--hash=sha256:981a6ef05875b5bb0c7fb68885546186d306f10f0f6718fe9b96c226e68821ff \
15-
--hash=sha256:adf957dddd26840f27ffbd060a6c4dd3b2192c5b7c2c0525ef1bd8131d8a83f5
13+
# pygls
14+
cattrs==26.1.0 \
15+
--hash=sha256:d1e0804c42639494d469d08d4f26d6b9de9b8ab26b446db7b5f8c2e97f7c3096 \
16+
--hash=sha256:fa239e0f0ec0715ba34852ce813986dfed1e12117e209b816ab87401271cdd40
1617
# via
1718
# lsprotocol
1819
# pygls
19-
exceptiongroup==1.2.2 \
20-
--hash=sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b \
21-
--hash=sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc
22-
# via cattrs
23-
lsprotocol==2023.0.1 \
24-
--hash=sha256:c75223c9e4af2f24272b14c6375787438279369236cd568f596d4951052a60f2 \
25-
--hash=sha256:cc5c15130d2403c18b734304339e51242d3018a05c4f7d0f198ad6e0cd21861d
20+
lsprotocol==2025.0.0 \
21+
--hash=sha256:e879da2b9301e82cfc3e60d805630487ac2f7ab17492f4f5ba5aaba94fe56c29 \
22+
--hash=sha256:f9d78f25221f2a60eaa4a96d3b4ffae011b107537facee61d3da3313880995c7
2623
# via pygls
2724
packaging==26.0 \
2825
--hash=sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4 \
2926
--hash=sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529
3027
# via -r requirements.in
31-
pygls==1.3.1 \
32-
--hash=sha256:140edceefa0da0e9b3c533547c892a42a7d2fd9217ae848c330c53d266a55018 \
33-
--hash=sha256:6e00f11efc56321bdeb6eac04f6d86131f654c7d49124344a9ebb968da3dd91e
28+
pygls==2.0.1 \
29+
--hash=sha256:2f774a669fbe2ece977d302786f01f9b0c5df7d0204ea0fa371ecb08288d6b86 \
30+
--hash=sha256:d29748042cea5bedc98285eb3e2c0c60bf3fc73786319519001bf72bbe8f36cc
3431
# via -r requirements.in
35-
typing-extensions==4.13.1 \
36-
--hash=sha256:4b6cf02909eb5495cfbc3f6e8fd49217e6cc7944e145cdda8caa3734777f9e69 \
37-
--hash=sha256:98795af00fb9640edec5b8e31fc647597b4691f099ad75f469a2616be1a76dff
32+
typing-extensions==4.15.0 \
33+
--hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \
34+
--hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548
3835
# via cattrs

runtime.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
python-3.9.21
1+
python-3.10.16

src/common/python.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,11 @@ export async function runPythonExtensionCommand(command: string, ...rest: any[])
124124

125125
export function checkVersion(resolved: ResolvedEnvironment | undefined): boolean {
126126
const version = resolved?.version;
127-
if (version?.major === 3 && version?.minor >= 8) {
127+
if (version?.major === 3 && version?.minor >= 10) {
128128
return true;
129129
}
130130
traceError(`Python version ${version?.major}.${version?.minor} is not supported.`);
131131
traceError(`Selected python path: ${resolved?.executable.uri?.fsPath}`);
132-
traceError('Supported versions are 3.8 and above.');
132+
traceError('Supported versions are 3.10 and above.');
133133
return false;
134134
}

src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
8181
'Python interpreter missing:\r\n' +
8282
'[Option 1] Select python interpreter using the ms-python.python.\r\n' +
8383
`[Option 2] Set an interpreter using "${serverId}.interpreter" setting.\r\n` +
84-
'Please use Python 3.8 or greater.',
84+
'Please use Python 3.10 or greater.',
8585
);
8686
} finally {
8787
isRestarting = false;

src/test/python_tests/requirements.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This file is used to generate ./src/test/python_tests/requirements.txt.
22
# NOTE:
3-
# Use Python 3.8 or greater which ever is the minimum version of the python
3+
# Use Python 3.10 or greater which ever is the minimum version of the python
44
# you plan on supporting when creating the environment or using pip-tools.
55
# Only run the commands below to manully upgrade packages in requirements.txt:
66
# 1) python -m pip install pip-tools

0 commit comments

Comments
 (0)