Migrating to v1.0 ================= The most notable change of the ``v1.0`` release of ``pygls`` is the removal of its hand written LSP type and method definitions in favour of relying on the types provided by the `lsprotocol`_ library which are automatically generated from the LSP specification. As as side effect this has also meant the removal of `pydantic`_ as a dependency, since ``lsprotocol`` uses `attrs`_ and `cattrs`_ for serialisation and validation. This guide outlines how to adapt an existing server to the breaking changes introduced in this release. Known Migrations ---------------- You may find insight and inspiration from these projects that have already successfully migrated to v1: * `jedi-language-server`_ * `vscode-ruff`_ * `esbonio`_ * `yara-language-server`_ Updating Imports ---------------- The ``pygls.lsp.methods`` and ``pygls.lsp.types`` modules no longer exist. Instead, all types and method names should now be imported from the ``lsprotocol.types`` module. Additionally, the following types and constants have been renamed. ================================================================== ============== pygls lsprotocol ================================================================== ============== ``CODE_ACTION`` ``TEXT_DOCUMENT_CODE_ACTION`` ``CODE_LENS`` ``TEXT_DOCUMENT_CODE_LENS`` ``COLOR_PRESENTATION`` ``TEXT_DOCUMENT_COLOR_PRESENTATION`` ``COMPLETION`` ``TEXT_DOCUMENT_COMPLETION`` ``DECLARATION`` ``TEXT_DOCUMENT_DECLARATION`` ``DEFINITION`` ``TEXT_DOCUMENT_DEFINITION`` ``DOCUMENT_COLOR`` ``TEXT_DOCUMENT_DOCUMENT_COLOR`` ``DOCUMENT_HIGHLIGHT`` ``TEXT_DOCUMENT_DOCUMENT_HIGHLIGHT`` ``DOCUMENT_LINK`` ``TEXT_DOCUMENT_DOCUMENT_LINK`` ``DOCUMENT_SYMBOL`` ``TEXT_DOCUMENT_DOCUMENT_SYMBOL`` ``FOLDING_RANGE`` ``TEXT_DOCUMENT_FOLDING_RANGE`` ``FORMATTING`` ``TEXT_DOCUMENT_FORMATTING`` ``HOVER`` ``TEXT_DOCUMENT_HOVER`` ``IMPLEMENTATION`` ``TEXT_DOCUMENT_IMPLEMENTATION`` ``LOG_TRACE_NOTIFICATION`` ``LOG_TRACE`` ``ON_TYPE_FORMATTING`` ``TEXT_DOCUMENT_ON_TYPE_FORMATTING`` ``PREPARE_RENAME`` ``TEXT_DOCUMENT_PREPARE_RENAME`` ``PROGRESS_NOTIFICATION`` ``PROGRESS`` ``RANGE_FORMATTING`` ``TEXT_DOCUMENT_RANGE_FORMATTING`` ``REFERENCES`` ``TEXT_DOCUMENT_REFERENCES`` ``RENAME`` ``TEXT_DOCUMENT_RENAME`` ``SELECTION_RANGE`` ``TEXT_DOCUMENT_SELECTION_RANGE`` ``SET_TRACE_NOTIFICATION`` ``SET_TRACE`` ``SIGNATURE_HELP`` ``TEXT_DOCUMENT_SIGNATURE_HELP`` ``TEXT_DOCUMENT_CALL_HIERARCHY_INCOMING_CALLS`` ``CALL_HIERARCHY_INCOMING_CALLS`` ``TEXT_DOCUMENT_CALL_HIERARCHY_OUTGOING_CALLS`` ``CALL_HIERARCHY_OUTGOING_CALLS`` ``TEXT_DOCUMENT_CALL_HIERARCHY_PREPARE`` ``TEXT_DOCUMENT_PREPARE_CALL_HIERARCHY`` ``TYPE_DEFINITION`` ``TEXT_DOCUMENT_TYPE_DEFINITION`` ``WORKSPACE_FOLDERS`` ``WORKSPACE_WORKSPACE_FOLDERS`` ``ApplyWorkspaceEditResponse`` ``ApplyWorkspaceEditResult`` ``ClientInfo`` ``InitializeParamsClientInfoType`` ``CodeActionDisabled`` ``CodeActionDisabledType`` ``CodeActionLiteralSupportActionKindClientCapabilities`` ``CodeActionClientCapabilitiesCodeActionLiteralSupportTypeCodeActionKindType`` ``CodeActionLiteralSupportClientCapabilities`` ``CodeActionClientCapabilitiesCodeActionLiteralSupportType`` ``CompletionItemClientCapabilities`` ``CompletionClientCapabilitiesCompletionItemType`` ``CompletionItemKindClientCapabilities`` ``CompletionClientCapabilitiesCompletionItemKindType`` ``CompletionTagSupportClientCapabilities`` ``CompletionClientCapabilitiesCompletionItemTypeTagSupportType`` ``DocumentSymbolCapabilitiesTagSupport`` ``DocumentSymbolClientCapabilitiesTagSupportType`` ``InsertTextModeSupportClientCapabilities`` ``CompletionClientCapabilitiesCompletionItemTypeInsertTextModeSupportType`` ``MarkedStringType`` ``MarkedString`` ``MarkedString`` ``MarkedString_Type1`` ``PrepareRename`` ``PrepareRenameResult_Type1`` ``PublishDiagnosticsTagSupportClientCapabilities`` ``PublishDiagnosticsClientCapabilitiesTagSupportType`` ``ResolveSupportClientCapabilities`` ``CodeActionClientCapabilitiesResolveSupportType`` ``SemanticTokensRequestsFull`` ``SemanticTokensRegistrationOptionsFullType1`` ``SemanticTokensRequests`` ``SemanticTokensClientCapabilitiesRequestsType`` ``ServerInfo`` ``InitializeResultServerInfoType`` ``ShowMessageRequestActionItem`` ``ShowMessageRequestClientCapabilitiesMessageActionItemType`` ``SignatureHelpInformationClientCapabilities`` ``SignatureHelpClientCapabilitiesSignatureInformationType`` ``SignatureHelpInformationParameterInformationClientCapabilities`` ``SignatureHelpClientCapabilitiesSignatureInformationTypeParameterInformationType`` ``TextDocumentContentChangeEvent`` ``TextDocumentContentChangeEvent_Type1`` ``TextDocumentContentChangeTextEvent`` ``TextDocumentContentChangeEvent_Type2`` ``TextDocumentSyncOptionsServerCapabilities`` ``TextDocumentSyncOptions`` ``Trace`` ``TraceValues`` ``URI`` ``str`` ``WorkspaceCapabilitiesSymbolKind`` ``WorkspaceSymbolClientCapabilitiesSymbolKindType`` ``WorkspaceCapabilitiesTagSupport`` ``WorkspaceSymbolClientCapabilitiesTagSupportType`` ``WorkspaceFileOperationsServerCapabilities`` ``FileOperationOptions`` ``WorkspaceServerCapabilities`` ``ServerCapabilitiesWorkspaceType`` ================================================================== ============== Custom Models ------------- One of the most obvious changes is the switch to `attrs`_ and `cattrs`_ for serialization and deserialisation. This means that any custom models used by your language server will need to be converted to an ``attrs`` style class. .. code-block:: python # Before from pydantic import BaseModel, Field class ExampleConfig(BaseModel): build_dir: Optional[str] = Field(None, alias="buildDir") builder_name: str = Field("html", alias="builderName") conf_dir: Optional[str] = Field(None, alias="confDir") .. code-block:: python # After import attrs @attrs.define class ExampleConfig: build_dir: Optional[str] = attrs.field(default=None) builder_name: str = attrs.field(default="html") conf_dir: Optional[str] = attrs.field(default=None) Pygls provides a default `converter`_ that it will use when converting your models to/from JSON, which should be sufficient for most scenarios. .. code-block:: pycon >>> from pygls.protocol import default_converter >>> converter = default_converter() >>> config = ExampleConfig(builder_name='epub', conf_dir='/path/to/conf') >>> converter.unstructure(config) {'builderName': 'epub', 'confDir': '/path/to/conf'} # Note how snake_case is converted to camelCase >>> converter.structure({'builderName': 'epub', 'confDir': '/path/to/conf'}, ExampleConfig) ExampleConfig(build_dir=None, builder_name='epub', conf_dir='/path/to/conf') However, depending on the complexity of your type definitions you may find the default converter fail to parse some of your types. .. code-block:: pycon >>> from typing import Literal, Union >>> @attrs.define ... class ExampleConfig: ... num_jobs: Union[Literal["auto"], int] = attrs.field(default='auto') ... >>> converter.structure({'numJobs': 'auto'}, ExampleConfig) + Exception Group Traceback (most recent call last): | File "", line 1, in | File "/.../python3.10/site-packages/cattrs/converters.py", li ne 309, in structure | return self._structure_func.dispatch(cl)(obj, cl) | File "", line 10, in structure_ExampleConfig | if errors: raise __c_cve('While structuring ' + 'ExampleConfig', errors, __cl) | cattrs.errors.ClassValidationError: While structuring ExampleConfig (1 sub-exception) +-+---------------- 1 ---------------- | Traceback (most recent call last): | File "", line 6, in structure_ExampleConfig | res['num_jobs'] = __c_structure_num_jobs(o['numJobs'], __c_type_num_jobs) | File "/.../python3.10/site-packages/cattrs/converters.py", line 377, in _structure_error | raise StructureHandlerNotFoundError(msg, type_=cl) | cattrs.errors.StructureHandlerNotFoundError: Unsupported type: typing.Union[typing.Literal['auto'], int]. Register a structure hook for it. | Structuring class ExampleConfig @ attribute num_jobs +------------------------------------ In which case you can extend the converter provided by ``pygls`` with your own `structure hooks`_ .. code-block:: python from pygls.protocol import default_converter def custom_converter(): converter = default_converter() converter.register_structure_hook(Union[Literal['auto', int], lambda obj, _: obj) return converter You can then override the default converter used by ``pygls`` when constructing your language server instance .. code-block:: python server = LanguageServer( name="my-language-server", version="v1.0", converter_factory=custom_converter ) See the `hooks.py`_ module in ``lsprotocol`` for some example structure hooks Miscellaneous ------------- Mandatory ``name`` and ``version`` """""""""""""""""""""""""""""""""" It is now necessary to provide a name and version when constructing an instance of the ``LanguageServer`` class .. code-block:: python from pygls.server import LanguageServer server = LanguageServer(name="my-language-server", version="v1.0") ``ClientCapabilities.get_capability`` is now ``get_capability`` """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" .. code-block:: python # Before from pygls.lsp.types import ClientCapabilities client_capabilities = ClientCapabilities() commit_character_support = client_capabilities.get_capability( "text_document.completion.completion_item.commit_characters_support", False ) .. code-block:: python # After from lsprotocol.types import ClientCapabilities from pygls.capabilities import get_capability client_capabilities = ClientCapabilities() commit_character_support = get_capability( client_capabilities, "text_document.completion.completion_item.commit_characters_support", False ) .. _attrs: https://www.attrs.org/en/stable/index.html .. _cattrs: https://cattrs.readthedocs.io/en/stable/ .. _converter: https://cattrs.readthedocs.io/en/stable/converters.html .. _hooks.py: https://github.com/microsoft/lsprotocol/blob/main/lsprotocol/_hooks.py .. _lsprotocol: https://github.com/microsoft/lsprotocol .. _pydantic: https://pydantic-docs.helpmanual.io/ .. _structure hooks: https://cattrs.readthedocs.io/en/stable/structuring.html#registering-custom-structuring-hooks .. _jedi-language-server: https://github.com/pappasam/jedi-language-server/pull/230 .. _yara-language-server: https://github.com/avast/yls/pull/34 .. _vscode-ruff: https://github.com/charliermarsh/vscode-ruff/pull/37 .. _esbonio: https://github.com/swyddfa/esbonio/pull/484