diff --git a/generator/requirements.txt b/generator/requirements.txt index 18e30b0..266b0f7 100644 --- a/generator/requirements.txt +++ b/generator/requirements.txt @@ -12,9 +12,9 @@ importlib-metadata==5.0.0 \ --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \ --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43 # via jsonschema -importlib-resources==5.9.0 \ - --hash=sha256:5481e97fb45af8dcf2f798952625591c58fe599d0735d86b10f54de086a61681 \ - --hash=sha256:f78a8df21a79bcc30cfd400bdc38f314333de7c0fb619763f6b9dabab8268bb7 +importlib-resources==5.10.0 \ + --hash=sha256:c01b1b94210d9849f286b86bb51bcea7cd56dde0600d8db721d7b81330711668 \ + --hash=sha256:ee17ec648f85480d523596ce49eae8ead87d5631ae1551f913c0100b5edd3437 # via # -r ./generator/requirements.in # jsonschema @@ -49,15 +49,15 @@ pyrsistent==0.18.1 \ --hash=sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5 \ --hash=sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6 # via jsonschema -typing-extensions==4.3.0 \ - --hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \ - --hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6 +typing-extensions==4.4.0 \ + --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ + --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e # via # importlib-metadata # jsonschema -zipp==3.8.1 \ - --hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \ - --hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009 +zipp==3.9.0 \ + --hash=sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb \ + --hash=sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980 # via # importlib-metadata # importlib-resources diff --git a/lsprotocol/_hooks.py b/lsprotocol/_hooks.py index ec5f1d1..7b62ccc 100644 --- a/lsprotocol/_hooks.py +++ b/lsprotocol/_hooks.py @@ -358,6 +358,15 @@ def _semantic_tokens_hook(object_: Any, _: type): return object_ return converter.structure(object_, lsp_types.SemanticTokensOptionsFullType1) + def _semantic_tokens_capabilities_hook(object_: Any, _: type): + if object_ is None: + return None + if isinstance(object_, (bool, int, str, float)): + return object_ + return converter.structure( + object_, lsp_types.SemanticTokensClientCapabilitiesRequestsTypeFullType1 + ) + structure_hooks = [ ( Optional[ @@ -587,6 +596,15 @@ def _semantic_tokens_hook(object_: Any, _: type): Optional[Union[bool, lsp_types.SemanticTokensOptionsFullType1]], _semantic_tokens_hook, ), + ( + Optional[ + Union[ + bool, + lsp_types.SemanticTokensClientCapabilitiesRequestsTypeFullType1, + ] + ], + _semantic_tokens_capabilities_hook, + ), ] for type_, hook in structure_hooks: converter.register_structure_hook(type_, hook) diff --git a/lsprotocol/validators.py b/lsprotocol/validators.py index 7a92c99..6e6f3e7 100644 --- a/lsprotocol/validators.py +++ b/lsprotocol/validators.py @@ -4,19 +4,18 @@ from typing import Any -import attrs - INTEGER_MIN_VALUE = -(2**31) INTEGER_MAX_VALUE = 2**31 - 1 -def integer_validator(instance: Any, attribute: attrs.Attribute, value: Any) -> bool: +def integer_validator(instance: Any, attribute: Any, value: Any) -> bool: """Validates that integer value belongs in the range expected by LSP.""" if not isinstance(value, int) or not ( INTEGER_MIN_VALUE <= value <= INTEGER_MAX_VALUE ): + name = attribute.name if hasattr(attribute, "name") else str(attribute) raise ValueError( - f"{instance.__class__.__qualname__}.{attribute.name} should be in range [{INTEGER_MIN_VALUE}:{INTEGER_MAX_VALUE}], but was {value}." + f"{instance.__class__.__qualname__}.{name} should be in range [{INTEGER_MIN_VALUE}:{INTEGER_MAX_VALUE}], but was {value}." ) return True @@ -25,13 +24,14 @@ def integer_validator(instance: Any, attribute: attrs.Attribute, value: Any) -> UINTEGER_MAX_VALUE = 2**31 - 1 -def uinteger_validator(instance: Any, attribute: attrs.Attribute, value: Any) -> bool: +def uinteger_validator(instance: Any, attribute: Any, value: Any) -> bool: """Validates that unsigned integer value belongs in the range expected by LSP.""" if not isinstance(value, int) or not ( UINTEGER_MIN_VALUE <= value <= UINTEGER_MAX_VALUE ): + name = attribute.name if hasattr(attribute, "name") else str(attribute) raise ValueError( - f"{instance.__class__.__qualname__}.{attribute.name} should be in range [{UINTEGER_MIN_VALUE}:{UINTEGER_MAX_VALUE}], but was {value}." + f"{instance.__class__.__qualname__}.{name} should be in range [{UINTEGER_MIN_VALUE}:{UINTEGER_MAX_VALUE}], but was {value}." ) return True diff --git a/requirements.txt b/requirements.txt index 7f04d3b..6dbf382 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,7 +18,7 @@ exceptiongroup==1.0.0rc9 \ --hash=sha256:2e3c3fc1538a094aab74fad52d6c33fc94de3dfee3ee01f187c0e0c72aec5337 \ --hash=sha256:9086a4a21ef9b31c72181c77c040a074ba0889ee56a7b289ff0afb0d97655f96 # via cattrs -typing-extensions==4.3.0 \ - --hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \ - --hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6 +typing-extensions==4.4.0 \ + --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ + --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e # via cattrs diff --git a/tests/requests/test_initilize_request.py b/tests/requests/test_initilize_request.py new file mode 100644 index 0000000..cd4caa4 --- /dev/null +++ b/tests/requests/test_initilize_request.py @@ -0,0 +1,407 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import json +import uuid + +import hamcrest +import pytest + +from tests import jsonrpc + +ID = str(uuid.uuid4()) +INITIALIZE_PARAMS = { + "processId": 1105947, + "rootPath": "/home/user/src/Personal/jedi-language-server", + "rootUri": "file:///home/user/src/Personal/jedi-language-server", + "capabilities": { + "workspace": { + "applyEdit": True, + "workspaceEdit": { + "documentChanges": True, + "resourceOperations": ["create", "rename", "delete"], + "failureHandling": "undo", + "normalizesLineEndings": True, + "changeAnnotationSupport": {"groupsOnLabel": False}, + }, + "didChangeConfiguration": {"dynamicRegistration": True}, + "didChangeWatchedFiles": { + "dynamicRegistration": True, + "relativePatternSupport": True, + }, + "codeLens": {"refreshSupport": True}, + "executeCommand": {"dynamicRegistration": True}, + "configuration": True, + "fileOperations": { + "dynamicRegistration": True, + "didCreate": True, + "didRename": True, + "didDelete": True, + "willCreate": True, + "willRename": True, + "willDelete": True, + }, + "semanticTokens": {"refreshSupport": True}, + "inlayHint": {"refreshSupport": True}, + "inlineValue": {"refreshSupport": True}, + "diagnostics": {"refreshSupport": True}, + "symbol": { + "dynamicRegistration": True, + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + ] + }, + "tagSupport": {"valueSet": [1]}, + "resolveSupport": {"properties": ["location.range"]}, + }, + "workspaceFolders": True, + }, + "textDocument": { + "publishDiagnostics": { + "relatedInformation": True, + "versionSupport": True, + "tagSupport": {"valueSet": [1, 2]}, + "codeDescriptionSupport": True, + "dataSupport": True, + }, + "synchronization": { + "dynamicRegistration": True, + "willSave": True, + "willSaveWaitUntil": True, + "didSave": True, + }, + "completion": { + "dynamicRegistration": True, + "contextSupport": True, + "completionItem": { + "snippetSupport": True, + "commitCharactersSupport": True, + "documentationFormat": ["markdown", "plaintext"], + "deprecatedSupport": True, + "preselectSupport": True, + "insertReplaceSupport": True, + "tagSupport": {"valueSet": [1]}, + "resolveSupport": { + "properties": ["documentation", "detail", "additionalTextEdits"] + }, + "labelDetailsSupport": True, + "insertTextModeSupport": {"valueSet": [1, 2]}, + }, + "completionItemKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + ] + }, + "insertTextMode": 2, + "completionList": { + "itemDefaults": [ + "commitCharacters", + "editRange", + "insertTextFormat", + "insertTextMode", + ] + }, + }, + "hover": { + "dynamicRegistration": True, + "contentFormat": ["markdown", "plaintext"], + }, + "signatureHelp": { + "dynamicRegistration": True, + "contextSupport": True, + "signatureInformation": { + "documentationFormat": ["markdown", "plaintext"], + "activeParameterSupport": True, + "parameterInformation": {"labelOffsetSupport": True}, + }, + }, + "references": {"dynamicRegistration": True}, + "definition": {"dynamicRegistration": True, "linkSupport": True}, + "documentHighlight": {"dynamicRegistration": True}, + "documentSymbol": { + "dynamicRegistration": True, + "symbolKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + ] + }, + "hierarchicalDocumentSymbolSupport": True, + "tagSupport": {"valueSet": [1]}, + "labelSupport": True, + }, + "codeAction": { + "dynamicRegistration": True, + "isPreferredSupport": True, + "disabledSupport": True, + "dataSupport": True, + "honorsChangeAnnotations": False, + "resolveSupport": {"properties": ["edit"]}, + "codeActionLiteralSupport": { + "codeActionKind": { + "valueSet": [ + "", + "quickfix", + "refactor", + "refactor.extract", + "refactor.inline", + "refactor.rewrite", + "source", + "source.organizeImports", + ] + } + }, + }, + "codeLens": {"dynamicRegistration": True}, + "formatting": {"dynamicRegistration": True}, + "rangeFormatting": {"dynamicRegistration": True}, + "onTypeFormatting": {"dynamicRegistration": True}, + "rename": { + "dynamicRegistration": True, + "prepareSupport": True, + "honorsChangeAnnotations": True, + "prepareSupportDefaultBehavior": 1, + }, + "documentLink": {"dynamicRegistration": True, "tooltipSupport": True}, + "typeDefinition": {"dynamicRegistration": True, "linkSupport": True}, + "implementation": {"dynamicRegistration": True, "linkSupport": True}, + "declaration": {"dynamicRegistration": True, "linkSupport": True}, + "colorProvider": {"dynamicRegistration": True}, + "foldingRange": { + "dynamicRegistration": True, + "rangeLimit": 5000, + "lineFoldingOnly": True, + "foldingRangeKind": {"valueSet": ["comment", "imports", "region"]}, + "foldingRange": {"collapsedText": False}, + }, + "selectionRange": {"dynamicRegistration": True}, + "callHierarchy": {"dynamicRegistration": True}, + "linkedEditingRange": {"dynamicRegistration": True}, + "semanticTokens": { + "dynamicRegistration": True, + "tokenTypes": [ + "namespace", + "type", + "class", + "enum", + "interface", + "struct", + "typeParameter", + "parameter", + "variable", + "property", + "enumMember", + "event", + "function", + "method", + "macro", + "keyword", + "modifier", + "comment", + "string", + "number", + "regexp", + "decorator", + "operator", + ], + "tokenModifiers": [ + "declaration", + "definition", + "readonly", + "static", + "deprecated", + "abstract", + "async", + "modification", + "documentation", + "defaultLibrary", + ], + "formats": ["relative"], + "requests": {"range": True, "full": {"delta": True}}, + "multilineTokenSupport": False, + "overlappingTokenSupport": False, + "serverCancelSupport": True, + "augmentsSyntaxTokens": True, + }, + "inlayHint": { + "dynamicRegistration": True, + "resolveSupport": { + "properties": [ + "tooltip", + "textEdits", + "label.tooltip", + "label.location", + "label.command", + ] + }, + }, + "inlineValue": {"dynamicRegistration": True}, + "diagnostic": {"dynamicRegistration": True, "relatedDocumentSupport": True}, + "typeHierarchy": {"dynamicRegistration": True}, + }, + "window": { + "showMessage": {"messageActionItem": {"additionalPropertiesSupport": True}}, + "showDocument": {"support": True}, + "workDoneProgress": True, + }, + "general": { + "regularExpressions": {"engine": "ECMAScript", "version": "ES2020"}, + "markdown": {"parser": "marked", "version": "4.0.10"}, + "positionEncodings": ["utf-16"], + "staleRequestSupport": { + "cancel": True, + "retryOnContentModified": [ + "textDocument/inlayHint", + "textDocument/semanticTokens/full", + "textDocument/semanticTokens/range", + "textDocument/semanticTokens/full/delta", + ], + }, + }, + }, + "initializationOptions": { + "enable": True, + "startupMessage": False, + "trace": {"server": "verbose"}, + "jediSettings": { + "autoImportModules": ["pygls"], + "caseInsensitiveCompletion": True, + "debug": False, + }, + "executable": {"args": [], "command": "jedi-language-server"}, + "codeAction": { + "nameExtractFunction": "jls_extract_def", + "nameExtractVariable": "jls_extract_var", + }, + "completion": { + "disableSnippets": False, + "resolveEagerly": False, + "ignorePatterns": [], + }, + "diagnostics": { + "enable": True, + "didOpen": True, + "didChange": True, + "didSave": True, + }, + "hover": { + "enable": True, + "disable": { + "class": {"all": False, "names": [], "fullNames": []}, + "function": {"all": False, "names": [], "fullNames": []}, + "instance": {"all": False, "names": [], "fullNames": []}, + "keyword": {"all": False, "names": [], "fullNames": []}, + "module": {"all": False, "names": [], "fullNames": []}, + "param": {"all": False, "names": [], "fullNames": []}, + "path": {"all": False, "names": [], "fullNames": []}, + "property": {"all": False, "names": [], "fullNames": []}, + "statement": {"all": False, "names": [], "fullNames": []}, + }, + }, + "workspace": { + "extraPaths": [], + "symbols": { + "maxSymbols": 20, + "ignoreFolders": [".nox", ".tox", ".venv", "__pycache__", "venv"], + }, + }, + }, + "trace": "verbose", + "workspaceFolders": [ + { + "uri": "file:///home/user/src/Personal/jedi-language-server", + "name": "jedi-language-server", + } + ], + "locale": "en_US", + "clientInfo": {"name": "coc.nvim", "version": "0.0.82"}, +} + + +TEST_DATA = [ + {"id": ID, "params": INITIALIZE_PARAMS, "method": "initialize", "jsonrpc": "2.0"}, +] + + +@pytest.mark.parametrize("index", list(range(0, len(TEST_DATA)))) +def test_initialize_request_params(index): + data = TEST_DATA[index] + data_str = json.dumps(data) + parsed = jsonrpc.from_json(data_str) + actual_str = jsonrpc.to_json(parsed) + actual_data = json.loads(actual_str) + hamcrest.assert_that(actual_data, hamcrest.is_(data)) diff --git a/tests/requests/test_workspace_sematic_tokens_refresh.py b/tests/requests/test_workspace_sematic_tokens_refresh.py index b9d6ed5..bc8cd29 100644 --- a/tests/requests/test_workspace_sematic_tokens_refresh.py +++ b/tests/requests/test_workspace_sematic_tokens_refresh.py @@ -1,7 +1,6 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -import hashlib import json import uuid diff --git a/tests/requirements.txt b/tests/requirements.txt index 057c725..31c75ca 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -31,9 +31,9 @@ importlib-metadata==5.0.0 \ # jsonschema # pluggy # pytest -importlib-resources==5.9.0 \ - --hash=sha256:5481e97fb45af8dcf2f798952625591c58fe599d0735d86b10f54de086a61681 \ - --hash=sha256:f78a8df21a79bcc30cfd400bdc38f314333de7c0fb619763f6b9dabab8268bb7 +importlib-resources==5.10.0 \ + --hash=sha256:c01b1b94210d9849f286b86bb51bcea7cd56dde0600d8db721d7b81330711668 \ + --hash=sha256:ee17ec648f85480d523596ce49eae8ead87d5631ae1551f913c0100b5edd3437 # via jsonschema iniconfig==1.1.1 \ --hash=sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3 \ @@ -98,16 +98,16 @@ tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f # via pytest -typing-extensions==4.3.0 \ - --hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \ - --hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6 +typing-extensions==4.4.0 \ + --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ + --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e # via # cattrs # importlib-metadata # jsonschema -zipp==3.8.1 \ - --hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \ - --hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009 +zipp==3.9.0 \ + --hash=sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb \ + --hash=sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980 # via # importlib-metadata # importlib-resources