Name | lsp-client JSON |
Version |
0.1.0
JSON |
| download |
home_page | None |
Summary | Full-featured, well-typed, and easy-to-use LSP client. |
upload_time | 2025-07-12 06:18:28 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.13 |
license | None |
keywords |
lsp
language server protocol
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# (WIP) LSP Client
[](https://badge.fury.io/py/lsp-client)
[](https://pypi.org/project/lsp-client/)
> [!WARNING]
> This project is still in development and may not be fully functional yet. Soon we will have a stable release.
Full-featured, well-typed, and easy-to-use LSP client for Python.
## Features
- **Well-Typed**: Provides type hints and [protocol definition](<README#Requiring LSP Client to Have Desired Capabilities>) for all LSP operations, making it easy to use and integrate with your code.
- **Full-Featured**: Supports a wide range of LSP capabilities, and you can easily [extend it to support more capabilities](<README#(Advanced) Add Support for New LSP Capabilities>).
- **Multiprocessing Support**: Supports [running multiple LSP servers in parallel](<README#Multiple Server Processes>), allowing you to speedup your LSP operations.
- **Easy to Extend**: You can easily [add support for new LSP servers](<README#Add Support for New LSP Servers>) by implementing a few methods.
## Install
```bash
uv add lsp-client
```
Currently, `lsp-client` supports Python 3.13 and above. Any backward-compatible PRs are welcome.
To maintain simplicity, `lsp-client` won't automatically install any LSP servers. Before using it, you need to install the LSP server you want to use and make sure it is available in your `$PATH`. Here are some examples of LSP servers you can use:
- Python: [BasedPyright](https://docs.basedpyright.com/dev/installation/command-line-and-language-server/)
## Usage
```python
import asyncio as aio
from lsp_client import Position
from lsp_client.servers.based_pyright import BasedPyrightClient
async def main():
async with BasedPyrightClient.start(
repo_path="/path/to/your/repo", # Update with your repo path
server_count=1, # adjust it to start more servers if needed
# set server process info if needed
server_info=LSPServerInfo(env={"EXAMPLE_ENV_VAR": "value"}),
) as client:
# Request references for a symbol at a specific position
refs = await client.request_references(
file_path="path/to/your/file.py", # Update with your file path
position=Position(12, 29), # Update with your desired position
)
# [Task-Group](https://docs.python.org/3/library/asyncio-task.html#asyncio.TaskGroup)-like interface
# to run multiple requests in parallel
def_tasks = [
client.create_request(client.request_definition(file_path, position))
for file_path, position in [
("path/to/your/file1.py", Position(10, 5)),
("path/to/your/file2.py", Position(20, 15)),
]
]
for ref in refs or []:
print(ref)
for def_result in [task.result() for task in def_tasks]:
print(def_result)
if __name__ == "__main__":
aio.run(main())
```
### A work-as-is Example
Clone the repository and run the following example to see how it works:
```bash
git clone https://github.com/observerw/lsp-client.git && cd lsp-client
uv sync
```
```python
from pathlib import Path
from asyncio_addon import async_main
from lsp_client import Position, Range, lsp_type
from lsp_client.servers.based_pyright import BasedPyrightClient
repo_path = Path.cwd()
curr_path = Path(__file__)
@async_main
async def main():
async with BasedPyrightClient.start(repo_path=repo_path) as client:
# found all references of `BasedPyrightClient` class
if refs := await client.request_references(
file_path="src/lsp_client/servers/based_pyright.py",
position=Position(8, 24),
):
for ref in refs:
print(f"Found references: {ref}")
# check if includes reference in current file
assert any(
client.from_uri(ref.uri) == curr_path
and ref.range == Range(Position(13, 15), Position(13, 33))
for ref in refs
)
print("All references found successfully.")
# find the definition of `main` function
def_task = client.create_request(
client.request_definition_location(
file_path=curr_path,
position=Position(47, 8),
)
)
match def_task.result():
case [lsp_type.Location() as loc]:
print(f"Found definition: {loc}")
assert client.from_uri(loc.uri) == curr_path
assert loc.range == Range(Position(12, 10), Position(12, 14))
print("Definition found successfully.")
if __name__ == "__main__":
main()
```
## Multiple Server Processes
One key feature of `lsp-client` is the ability to **run multiple LSP server processes in parallel**. This is particularly useful for large codebases or when you need to perform multiple LSP requests simultaneously, which can significantly speed up operations like finding references or definitions.
For example:
```python
async with BasedPyrightClient.start(
repo_path="/path/to/repo",
server_count=4, # Start 4 parallel server processes
) as client:
# Now requests can be processed in parallel across 4 servers
tasks = [
client.create_request(client.request_references(file, position))
for file, position in file_position_pairs
]
# all task results will be available here
results = [task.result() for task in tasks]
```
When a request is made by the client, it will be sent to one of the available server processes. The client will automatically do load balancing among the server processes.
However, please note that **starting too many server processes may consume a lot of system resources and lead to performance degradation**. It is recommended to adjust the `server_count` parameter based on your system's capabilities and the request count you expect to handle.
## Requiring LSP Client to Have Desired Capabilities
All LSP capabilities are declared as [`Protocol`](https://typing.python.org/en/latest/spec/protocol.html), which means you can combine them to create a protocol to constrain the LSP client to have specific capabilities. For example:
```python
# Client with references and definition capabilities
class GoodClient(
lsp_cap.WithRequestReferences,
lsp_cap.WithRequestDefinition,
LSPClientBase,
): ...
# Client with only completions capability
class BadClient(
lsp_cap.WithRequestCompletions,
LSPClientBase,
): ...
# Here we define a protocol that requires the client
# to have both `WithRequestReferences` and `WithRequestDefinition` capabilities.
@runtime_checkable
class DesiredClientProtocol(
lsp_cap.WithRequestReferences,
lsp_cap.WithRequestDefinition,
Protocol, # don't forget to inherit from `Protocol`
): ...
# good client can be accepted
good: type[DesiredClientProtocol] = GoodClient
# bad client cannot be accepted, since it does not have the required capabilities
# type[BadClient] is not assignable to type[DesiredClientProtocol]
bad: type[DesiredClientProtocol] = BadClient
```
## Add Support for New LSP Servers
Add support for a new LSP server is simple. Example from [BasedPyright](src/lsp_client/servers/based_pyright.py):
```python
# We define a new LSP client for BasedPyright
class BasedPyrightClient(
# we can add capabilities as needed
cap.WithRequestReferences,
cap.WithRequestDefinition,
cap.WithRequestHover,
# ...
LSPClientBase, # Remember to inherit from LSPClientBase
):
# language_id which this client supports, required
language_id: ClassVar = lsp_types.LanguageKind.Python
# start command to launch the LSP server, required
# note that the command must start a stdio server
server_cmd: ClassVar = (
"basedpyright-langserver",
"--stdio",
)
client_capabilities: ClassVar[types.ClientCapabilities] = types.ClientCapabilities(
# ... client capabilities specific to BasedPyright ...
)
```
That's it! Provide some necessary information and you are good to go.
## (WIP) Static Mode
If you are performing static code analysis, consider set `static=True` when starting the client. This will benefit you from caching the results of LSP requests.
In static mode, it is required to keep the code repository unchanged during the analysis. That means:
- You should not modify the code files while the client is running.
- All code-modifying LSP requests (like `textDocument/didChange`) will be banned and raised as an error.
## (WIP) Automatic Document Synchronization
Coming soon!
## (Advanced) Add Support for New LSP Capabilities
TODO ...
## What if ... ?
### What if the default capability implementation does not work for my LSP server?
If the default capability implementation doesn't work for your LSP server, you can override the specific methods in your client implementation. For example:
```python
class MyCustomClient(
cap.WithRequestReferences,
LSPClientBase,
):
# ... other implementation ...
@override
async def request_references(
self, file_path: AnyPath, position: Position
) -> types.ReferencesResult:
# Custom implementation for your LSP server
# that differs from the default behavior
return await self.request(
types.ReferencesRequest(
id=jsonrpc_uuid(),
params=types.ReferenceParams(
# Custom parameters for your server
context=types.ReferenceContext(include_declaration=True), # Different default
text_document=types.TextDocumentIdentifier(
uri=self.as_uri(file_path)
),
position=position,
),
),
schema=types.ReferencesResponse,
)
```
You can override any capability method to customize the behavior for your specific LSP server requirements.
## Why Do We ... ?
### Why do we need this project?
`multilspy` is great, but extending it needs some extra works, including:
- Support for more LSP servers
- Support for more LSP capabilities
- Support for parallel LSP server processes
- Provide better type hints and documentation
- ...
This project takes the spirit of `multilspy`, and refactor the code to provide more out-of-the-box support for various LSP servers (we even support [Github Copilot Server](src/lsp_client/servers/copilot.py)) and capabilities, and **make it easier to extend and use**.
### (Static Mode) Why do we need to use Language Server to perform static code analysis?
It seems weird to use a language server for static code analysis, since it is highly dynamic and requires a daemon to run. In an ideal world, we would have a nice static analysis tool that can analyze the code and export the results, so we can just use these results without needing a running server.
However, the truth is almost all static analysis tools are far from satisfying. For example, for Python:
- [pycallgraph](https://github.com/gak/pycallgraph) is archived long ago and [py-call-graph](https://github.com/Lewiscowles1986/py-call-graph) mainly focuses on call graph visualization.
- Github's [stack-graph](https://github.com/github/stack-graphs) seems cool, but it is mainly focused on name resolution (i.e. `textDocument/definition`) and does not provide a full static analysis solution.
- [LSIF](https://lsif.dev/) is dead, and its successor [scip](https://github.com/sourcegraph/scip-python) is not being actively maintained.
On contrast, LSP servers are usually well-maintained (since they are used by many IDEs), and they provide a lot of useful features for static code analysis, such as find references, find definitions, hover information, and more.
Sadly, most LSP servers are designed for dynamic analysis and do not provide cache mechanism, which means they will be slow when performing code analysis on large codebases. But considering their rich features and good maintainability, it is a good trade-off.
### Why do we have `WithRequestDocumentSymbols`, `WithRequestDocumentSymbolInformation`, and `WithRequestDocumentBaseSymbols` for `textDocument/documentSymbol` capability?
According to the [LSP specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol), LSP servers should return `SymbolInformation[]` whenever possible. However, some LSP servers do not support this feature and only return `DocumentSymbol[]`, so the return type of `WithRequestDocumentSymbols` is `Sequence[types.DocumentSymbolInformation] | Sequence[types.DocumentSymbol]`, which can be troublesome when you want to use the return values:
```python
for sym in await client.request_document_symbols(file_path):
# type matching is required here, boring!
if isinstance(sym, types.DocumentSymbolInformation):
print(f"Symbol: {sym.name} at {sym.location.range}")
elif isinstance(sym, types.DocumentSymbol):
print(f"Document Symbol: {sym.name} at {sym.range}")
```
To make it easier to use, we provide `WithRequestDocumentSymbolInformation` that returns `Sequence[types.DocumentSymbolInformation]` only and `WithRequestDocumentBaseSymbols` that returns `Sequence[types.DocumentSymbol]` only. If you can ensure that your LSP server supports `SymbolInformation`, you can use `WithRequestDocumentSymbolInformation` to get a more convenient return type.
This design is also applied to:
- `WithRequestDefinition`
- `WithRequestWorkspaceSymbols`
## Thanks
This project is heavily inspired by [multilspy](https://github.com/microsoft/multilspy), thanks for their great work!
Raw data
{
"_id": null,
"home_page": null,
"name": "lsp-client",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.13",
"maintainer_email": null,
"keywords": "LSP, Language Server Protocol",
"author": null,
"author_email": "observerw <wozluohd@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/43/d2/84717f44a81fc7733e96d9512d5f9665f9b1c997b4b852f8323de61d49f3/lsp_client-0.1.0.tar.gz",
"platform": null,
"description": "# (WIP) LSP Client\n\n[](https://badge.fury.io/py/lsp-client)\n[](https://pypi.org/project/lsp-client/)\n\n> [!WARNING]\n> This project is still in development and may not be fully functional yet. Soon we will have a stable release.\n\nFull-featured, well-typed, and easy-to-use LSP client for Python.\n\n## Features\n\n- **Well-Typed**: Provides type hints and [protocol definition](<README#Requiring LSP Client to Have Desired Capabilities>) for all LSP operations, making it easy to use and integrate with your code.\n- **Full-Featured**: Supports a wide range of LSP capabilities, and you can easily [extend it to support more capabilities](<README#(Advanced) Add Support for New LSP Capabilities>).\n- **Multiprocessing Support**: Supports [running multiple LSP servers in parallel](<README#Multiple Server Processes>), allowing you to speedup your LSP operations.\n- **Easy to Extend**: You can easily [add support for new LSP servers](<README#Add Support for New LSP Servers>) by implementing a few methods.\n\n## Install\n\n```bash\nuv add lsp-client\n```\n\nCurrently, `lsp-client` supports Python 3.13 and above. Any backward-compatible PRs are welcome.\n\nTo maintain simplicity, `lsp-client` won't automatically install any LSP servers. Before using it, you need to install the LSP server you want to use and make sure it is available in your `$PATH`. Here are some examples of LSP servers you can use:\n\n- Python: [BasedPyright](https://docs.basedpyright.com/dev/installation/command-line-and-language-server/)\n\n## Usage\n\n```python\nimport asyncio as aio\nfrom lsp_client import Position\nfrom lsp_client.servers.based_pyright import BasedPyrightClient\n\nasync def main():\n async with BasedPyrightClient.start(\n repo_path=\"/path/to/your/repo\", # Update with your repo path\n server_count=1, # adjust it to start more servers if needed\n # set server process info if needed\n server_info=LSPServerInfo(env={\"EXAMPLE_ENV_VAR\": \"value\"}),\n ) as client:\n # Request references for a symbol at a specific position\n refs = await client.request_references(\n file_path=\"path/to/your/file.py\", # Update with your file path\n position=Position(12, 29), # Update with your desired position\n )\n # [Task-Group](https://docs.python.org/3/library/asyncio-task.html#asyncio.TaskGroup)-like interface\n # to run multiple requests in parallel\n def_tasks = [\n client.create_request(client.request_definition(file_path, position))\n for file_path, position in [\n (\"path/to/your/file1.py\", Position(10, 5)),\n (\"path/to/your/file2.py\", Position(20, 15)),\n ]\n ]\n\n for ref in refs or []:\n print(ref)\n \n for def_result in [task.result() for task in def_tasks]:\n print(def_result)\n\n\nif __name__ == \"__main__\":\n aio.run(main())\n```\n\n### A work-as-is Example\n\nClone the repository and run the following example to see how it works:\n\n```bash\ngit clone https://github.com/observerw/lsp-client.git && cd lsp-client\nuv sync\n```\n\n```python\nfrom pathlib import Path\n\nfrom asyncio_addon import async_main\n\nfrom lsp_client import Position, Range, lsp_type\nfrom lsp_client.servers.based_pyright import BasedPyrightClient\n\nrepo_path = Path.cwd()\ncurr_path = Path(__file__)\n\n\n@async_main\nasync def main():\n async with BasedPyrightClient.start(repo_path=repo_path) as client:\n # found all references of `BasedPyrightClient` class\n if refs := await client.request_references(\n file_path=\"src/lsp_client/servers/based_pyright.py\",\n position=Position(8, 24),\n ):\n for ref in refs:\n print(f\"Found references: {ref}\")\n\n # check if includes reference in current file\n assert any(\n client.from_uri(ref.uri) == curr_path\n and ref.range == Range(Position(13, 15), Position(13, 33))\n for ref in refs\n )\n print(\"All references found successfully.\")\n\n # find the definition of `main` function\n def_task = client.create_request(\n client.request_definition_location(\n file_path=curr_path,\n position=Position(47, 8),\n )\n )\n\n match def_task.result():\n case [lsp_type.Location() as loc]:\n print(f\"Found definition: {loc}\")\n assert client.from_uri(loc.uri) == curr_path\n assert loc.range == Range(Position(12, 10), Position(12, 14))\n print(\"Definition found successfully.\")\n\n\nif __name__ == \"__main__\":\n main()\n```\n\n## Multiple Server Processes\n\nOne key feature of `lsp-client` is the ability to **run multiple LSP server processes in parallel**. This is particularly useful for large codebases or when you need to perform multiple LSP requests simultaneously, which can significantly speed up operations like finding references or definitions.\n\nFor example:\n\n```python\nasync with BasedPyrightClient.start(\n repo_path=\"/path/to/repo\",\n server_count=4, # Start 4 parallel server processes\n) as client:\n # Now requests can be processed in parallel across 4 servers\n tasks = [\n client.create_request(client.request_references(file, position))\n for file, position in file_position_pairs\n ]\n# all task results will be available here\nresults = [task.result() for task in tasks]\n```\n\nWhen a request is made by the client, it will be sent to one of the available server processes. The client will automatically do load balancing among the server processes.\n\nHowever, please note that **starting too many server processes may consume a lot of system resources and lead to performance degradation**. It is recommended to adjust the `server_count` parameter based on your system's capabilities and the request count you expect to handle.\n\n## Requiring LSP Client to Have Desired Capabilities\n\nAll LSP capabilities are declared as [`Protocol`](https://typing.python.org/en/latest/spec/protocol.html), which means you can combine them to create a protocol to constrain the LSP client to have specific capabilities. For example:\n\n```python\n# Client with references and definition capabilities\nclass GoodClient(\n lsp_cap.WithRequestReferences,\n lsp_cap.WithRequestDefinition,\n LSPClientBase,\n): ...\n\n# Client with only completions capability\nclass BadClient(\n lsp_cap.WithRequestCompletions,\n LSPClientBase,\n): ...\n\n# Here we define a protocol that requires the client\n# to have both `WithRequestReferences` and `WithRequestDefinition` capabilities.\n@runtime_checkable\nclass DesiredClientProtocol(\n lsp_cap.WithRequestReferences,\n lsp_cap.WithRequestDefinition,\n Protocol, # don't forget to inherit from `Protocol`\n): ...\n\n# good client can be accepted\ngood: type[DesiredClientProtocol] = GoodClient\n\n# bad client cannot be accepted, since it does not have the required capabilities\n# type[BadClient] is not assignable to type[DesiredClientProtocol]\nbad: type[DesiredClientProtocol] = BadClient\n```\n\n## Add Support for New LSP Servers\n\nAdd support for a new LSP server is simple. Example from [BasedPyright](src/lsp_client/servers/based_pyright.py):\n\n```python\n# We define a new LSP client for BasedPyright\nclass BasedPyrightClient(\n # we can add capabilities as needed\n cap.WithRequestReferences,\n cap.WithRequestDefinition,\n cap.WithRequestHover,\n # ...\n LSPClientBase, # Remember to inherit from LSPClientBase\n):\n # language_id which this client supports, required\n language_id: ClassVar = lsp_types.LanguageKind.Python\n # start command to launch the LSP server, required\n # note that the command must start a stdio server\n server_cmd: ClassVar = (\n \"basedpyright-langserver\",\n \"--stdio\",\n )\n client_capabilities: ClassVar[types.ClientCapabilities] = types.ClientCapabilities(\n # ... client capabilities specific to BasedPyright ...\n )\n```\n\nThat's it! Provide some necessary information and you are good to go.\n\n## (WIP) Static Mode\n\nIf you are performing static code analysis, consider set `static=True` when starting the client. This will benefit you from caching the results of LSP requests.\n\nIn static mode, it is required to keep the code repository unchanged during the analysis. That means:\n\n- You should not modify the code files while the client is running.\n- All code-modifying LSP requests (like `textDocument/didChange`) will be banned and raised as an error.\n\n## (WIP) Automatic Document Synchronization\n\nComing soon!\n\n## (Advanced) Add Support for New LSP Capabilities\n\nTODO ...\n\n## What if ... ?\n\n### What if the default capability implementation does not work for my LSP server?\n\nIf the default capability implementation doesn't work for your LSP server, you can override the specific methods in your client implementation. For example:\n\n```python\nclass MyCustomClient(\n cap.WithRequestReferences,\n LSPClientBase, \n):\n # ... other implementation ...\n \n @override\n async def request_references(\n self, file_path: AnyPath, position: Position\n ) -> types.ReferencesResult:\n # Custom implementation for your LSP server\n # that differs from the default behavior\n return await self.request(\n types.ReferencesRequest(\n id=jsonrpc_uuid(),\n params=types.ReferenceParams(\n # Custom parameters for your server\n context=types.ReferenceContext(include_declaration=True), # Different default\n text_document=types.TextDocumentIdentifier(\n uri=self.as_uri(file_path)\n ),\n position=position,\n ),\n ),\n schema=types.ReferencesResponse,\n )\n```\n\nYou can override any capability method to customize the behavior for your specific LSP server requirements.\n\n## Why Do We ... ?\n\n### Why do we need this project?\n\n`multilspy` is great, but extending it needs some extra works, including:\n\n- Support for more LSP servers\n- Support for more LSP capabilities\n- Support for parallel LSP server processes\n- Provide better type hints and documentation\n- ...\n\nThis project takes the spirit of `multilspy`, and refactor the code to provide more out-of-the-box support for various LSP servers (we even support [Github Copilot Server](src/lsp_client/servers/copilot.py)) and capabilities, and **make it easier to extend and use**.\n\n### (Static Mode) Why do we need to use Language Server to perform static code analysis?\n\nIt seems weird to use a language server for static code analysis, since it is highly dynamic and requires a daemon to run. In an ideal world, we would have a nice static analysis tool that can analyze the code and export the results, so we can just use these results without needing a running server.\n\nHowever, the truth is almost all static analysis tools are far from satisfying. For example, for Python:\n\n- [pycallgraph](https://github.com/gak/pycallgraph) is archived long ago and [py-call-graph](https://github.com/Lewiscowles1986/py-call-graph) mainly focuses on call graph visualization.\n- Github's [stack-graph](https://github.com/github/stack-graphs) seems cool, but it is mainly focused on name resolution (i.e. `textDocument/definition`) and does not provide a full static analysis solution.\n- [LSIF](https://lsif.dev/) is dead, and its successor [scip](https://github.com/sourcegraph/scip-python) is not being actively maintained.\n\nOn contrast, LSP servers are usually well-maintained (since they are used by many IDEs), and they provide a lot of useful features for static code analysis, such as find references, find definitions, hover information, and more.\n\nSadly, most LSP servers are designed for dynamic analysis and do not provide cache mechanism, which means they will be slow when performing code analysis on large codebases. But considering their rich features and good maintainability, it is a good trade-off.\n\n### Why do we have `WithRequestDocumentSymbols`, `WithRequestDocumentSymbolInformation`, and `WithRequestDocumentBaseSymbols` for `textDocument/documentSymbol` capability?\n\nAccording to the [LSP specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol), LSP servers should return `SymbolInformation[]` whenever possible. However, some LSP servers do not support this feature and only return `DocumentSymbol[]`, so the return type of `WithRequestDocumentSymbols` is `Sequence[types.DocumentSymbolInformation] | Sequence[types.DocumentSymbol]`, which can be troublesome when you want to use the return values:\n\n```python\nfor sym in await client.request_document_symbols(file_path):\n # type matching is required here, boring!\n if isinstance(sym, types.DocumentSymbolInformation):\n print(f\"Symbol: {sym.name} at {sym.location.range}\")\n elif isinstance(sym, types.DocumentSymbol):\n print(f\"Document Symbol: {sym.name} at {sym.range}\")\n```\n\nTo make it easier to use, we provide `WithRequestDocumentSymbolInformation` that returns `Sequence[types.DocumentSymbolInformation]` only and `WithRequestDocumentBaseSymbols` that returns `Sequence[types.DocumentSymbol]` only. If you can ensure that your LSP server supports `SymbolInformation`, you can use `WithRequestDocumentSymbolInformation` to get a more convenient return type.\n\nThis design is also applied to:\n\n- `WithRequestDefinition`\n- `WithRequestWorkspaceSymbols`\n\n## Thanks\n\nThis project is heavily inspired by [multilspy](https://github.com/microsoft/multilspy), thanks for their great work!\n",
"bugtrack_url": null,
"license": null,
"summary": "Full-featured, well-typed, and easy-to-use LSP client.",
"version": "0.1.0",
"project_urls": null,
"split_keywords": [
"lsp",
" language server protocol"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "bd45b74aed3c80197d8551d768a6401387c90131c79b4f0ce7aa6d795a91e499",
"md5": "b2ef382c7eccaae6be70ffd2bd9c4e6c",
"sha256": "bb3d7c0a2c6a934e6003d290b1c4798c74eb098eda23c64cd3cfb9328df34d7c"
},
"downloads": -1,
"filename": "lsp_client-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "b2ef382c7eccaae6be70ffd2bd9c4e6c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.13",
"size": 28285,
"upload_time": "2025-07-12T06:18:27",
"upload_time_iso_8601": "2025-07-12T06:18:27.004352Z",
"url": "https://files.pythonhosted.org/packages/bd/45/b74aed3c80197d8551d768a6401387c90131c79b4f0ce7aa6d795a91e499/lsp_client-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "43d284717f44a81fc7733e96d9512d5f9665f9b1c997b4b852f8323de61d49f3",
"md5": "c6d19623577abdcad758bb460820ea18",
"sha256": "98553b9fc4e3eb5205b9354b0c5ad99cefc6fbf8630cf35e51e014ae70f35a0b"
},
"downloads": -1,
"filename": "lsp_client-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "c6d19623577abdcad758bb460820ea18",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.13",
"size": 35945,
"upload_time": "2025-07-12T06:18:28",
"upload_time_iso_8601": "2025-07-12T06:18:28.085819Z",
"url": "https://files.pythonhosted.org/packages/43/d2/84717f44a81fc7733e96d9512d5f9665f9b1c997b4b852f8323de61d49f3/lsp_client-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-12 06:18:28",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "lsp-client"
}