Updated formatting of tests, README, etc

This commit is contained in:
itdominator 2023-11-11 23:54:48 -06:00
parent 248771d57e
commit 818934e539
6 changed files with 327 additions and 295 deletions

View File

@ -1,15 +1,11 @@
# pylspclient
# PyLSPClient
[LSP](https://microsoft.github.io/language-server-protocol/) client implementation in Python.
[![image](https://img.shields.io/pypi/v/pylspclient.svg)](https://pypi.org/project/pylspclient/)
[![Build Status](https://travis-ci.org/yeger00/pylspclient.svg?branch=master)](https://travis-ci.org/yeger00/pylspclient)
# What is LSP?
# Installation
```
pip install pylspclient
```
# Run the tests
@ -21,4 +17,4 @@ or
```
python setup.py test
```
```

201
examples/capabilities.py Normal file
View File

@ -0,0 +1,201 @@
# Python imports
# Lib imports
# Application imports
class Capabilities:
data = {
"textDocument": {
"codeAction": {
"dynamicRegistration": True
},
"codeLens": {
"dynamicRegistration": True
},
"colorProvider": {
"dynamicRegistration": True
},
"completion": {
"completionItem": {
"commitCharactersSupport": True,
"documentationFormat": [
"markdown",
"plaintext"
],
"snippetSupport": True
},
"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
]
},
"contextSupport": True,
"dynamicRegistration": True
},
"definition": {
"dynamicRegistration": True
},
"documentHighlight": {
"dynamicRegistration": True
},
"documentLink": {
"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
]
}
},
"formatting": {
"dynamicRegistration": True
},
"hover": {
"contentFormat": [
"markdown",
"plaintext"
],
"dynamicRegistration": True
},
"implementation": {
"dynamicRegistration": True
},
"onTypeFormatting": {
"dynamicRegistration": True
},
"publishDiagnostics": {
"relatedInformation": True
},
"rangeFormatting": {
"dynamicRegistration": True
},
"references": {
"dynamicRegistration": True
},
"rename": {
"dynamicRegistration": True
},
"signatureHelp": {
"dynamicRegistration": True,
"signatureInformation": {
"documentationFormat": [
"markdown",
"plaintext"
]
}
},
"synchronization": {
"didSave": True,
"dynamicRegistration": True,
"willSave": True,
"willSaveWaitUntil": True
},
"typeDefinition": {
"dynamicRegistration": True
}
},
"workspace": {
"applyEdit": True,
"configuration": True,
"didChangeConfiguration": {
"dynamicRegistration": True
},
"didChangeWatchedFiles": {
"dynamicRegistration": True
},
"executeCommand": {
"dynamicRegistration": 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
]
}
},
"workspaceEdit": {
"documentChanges": True
},
"workspaceFolders": True
}
}

View File

@ -1,7 +1,15 @@
import pylspclient
# Python imports
import argparse
import subprocess
import threading
import argparse
# Lib imports
# Application imports
import pylspclient
from .capabilities import Capabilities
class ReadPipe(threading.Thread):
def __init__(self, pipe):
@ -11,156 +19,66 @@ class ReadPipe(threading.Thread):
def run(self):
line = self.pipe.readline().decode('utf-8')
while line:
print(line)
line = self.pipe.readline().decode('utf-8')
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='pylspclient example with clangd')
parser.add_argument('clangd_path', type=str, default="/usr/bin/clangd-6.0",
help='the clangd path', nargs="?")
args = parser.parse_args()
p = subprocess.Popen([args.clangd_path], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
parser = argparse.ArgumentParser(description = 'PyLSPClient example with clangd')
parser.add_argument('clangd_path', type=str, default="/usr/bin/clangd-6.0", help = 'the clangd path', nargs="?")
args = parser.parse_args()
p = subprocess.Popen([args.clangd_path], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
read_pipe = ReadPipe(p.stderr)
read_pipe.start()
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(p.stdin, p.stdout)
# To work with socket: sock_fd = sock.makefile()
lsp_endpoint = pylspclient.LspEndpoint(json_rpc_endpoint)
lsp_client = pylspclient.LspClient(lsp_endpoint)
capabilities = {'textDocument': {'codeAction': {'dynamicRegistration': True},
'codeLens': {'dynamicRegistration': True},
'colorProvider': {'dynamicRegistration': True},
'completion': {'completionItem': {'commitCharactersSupport': True,
'documentationFormat': ['markdown', 'plaintext'],
'snippetSupport': True},
'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]},
'contextSupport': True,
'dynamicRegistration': True},
'definition': {'dynamicRegistration': True},
'documentHighlight': {'dynamicRegistration': True},
'documentLink': {'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]}},
'formatting': {'dynamicRegistration': True},
'hover': {'contentFormat': ['markdown', 'plaintext'],
'dynamicRegistration': True},
'implementation': {'dynamicRegistration': True},
'onTypeFormatting': {'dynamicRegistration': True},
'publishDiagnostics': {'relatedInformation': True},
'rangeFormatting': {'dynamicRegistration': True},
'references': {'dynamicRegistration': True},
'rename': {'dynamicRegistration': True},
'signatureHelp': {'dynamicRegistration': True,
'signatureInformation': {'documentationFormat': ['markdown', 'plaintext']}},
'synchronization': {'didSave': True,
'dynamicRegistration': True,
'willSave': True,
'willSaveWaitUntil': True},
'typeDefinition': {'dynamicRegistration': True}},
'workspace': {'applyEdit': True,
'configuration': True,
'didChangeConfiguration': {'dynamicRegistration': True},
'didChangeWatchedFiles': {'dynamicRegistration': True},
'executeCommand': {'dynamicRegistration': 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]}},'workspaceEdit': {'documentChanges': True},
'workspaceFolders': True}}
root_uri = 'file:///home/osboxes/projects/ctest/'
lsp_endpoint = pylspclient.LspEndpoint(json_rpc_endpoint)
lsp_client = pylspclient.LspClient(lsp_endpoint)
root_uri = 'file:///home/osboxes/projects/ctest/'
workspace_folders = [{'name': 'python-lsp', 'uri': root_uri}]
print(lsp_client.initialize(p.pid, None, root_uri, None, capabilities, "off", workspace_folders))
print(lsp_client.initialize(p.pid, None, root_uri, None, Capabilities.data, "off", workspace_folders))
print(lsp_client.initialized())
file_path = "/home/osboxes/projects/ctest/test.c"
uri = "file://" + file_path
text = open(file_path, "r").read()
file_path = "/home/osboxes/projects/ctest/test.c"
uri = f"file://{file_path}"
text = open(file_path, "r").read()
languageId = pylspclient.lsp_structs.LANGUAGE_IDENTIFIER.C
version = 1
version = 1
lsp_client.didOpen(pylspclient.lsp_structs.TextDocumentItem(uri, languageId, version, text))
try:
symbols = lsp_client.documentSymbol(pylspclient.lsp_structs.TextDocumentIdentifier(uri))
for symbol in symbols:
print(symbol.name)
except pylspclient.lsp_structs.ResponseError:
# documentSymbol is supported from version 8.
print("Failed to document symbols")
print("Failed to load document symbols...")
lsp_client.definition(
pylspclient.lsp_structs.TextDocumentIdentifier(uri),
pylspclient.lsp_structs.Position(14, 4)
)
lsp_client.signatureHelp(
pylspclient.lsp_structs.TextDocumentIdentifier(uri),
pylspclient.lsp_structs.Position(14, 4)
)
lsp_client.definition(
pylspclient.lsp_structs.TextDocumentIdentifier(uri),
pylspclient.lsp_structs.Position(14, 4)
)
lsp_client.completion(
pylspclient.lsp_structs.TextDocumentIdentifier(uri),
pylspclient.lsp_structs.Position(14, 4),
pylspclient.lsp_structs.CompletionContext(pylspclient.lsp_structs.CompletionTriggerKind.Invoked)
)
lsp_client.definition(pylspclient.lsp_structs.TextDocumentIdentifier(uri), pylspclient.lsp_structs.Position(14, 4))
lsp_client.signatureHelp(pylspclient.lsp_structs.TextDocumentIdentifier(uri), pylspclient.lsp_structs.Position(14, 4))
lsp_client.definition(pylspclient.lsp_structs.TextDocumentIdentifier(uri), pylspclient.lsp_structs.Position(14, 4))
lsp_client.completion(pylspclient.lsp_structs.TextDocumentIdentifier(uri), pylspclient.lsp_structs.Position(14, 4), pylspclient.lsp_structs.CompletionContext(pylspclient.lsp_structs.CompletionTriggerKind.Invoked))
lsp_client.shutdown()
lsp_client.exit()

View File

@ -1,12 +1,20 @@
import pylspclient
# Python imports
import subprocess
import threading
# Lib imports
import pylspclient
# Application imports
from .capabilities import Capabilities
# In order to run this example, you need to have python-language-server module installed.
# See more information on the project page: https://github.com/palantir/python-language-server
class ReadPipe(threading.Thread):
def __init__(self, pipe):
threading.Thread.__init__(self)
@ -15,135 +23,26 @@ class ReadPipe(threading.Thread):
def run(self):
line = self.pipe.readline().decode('utf-8')
while line:
print(line)
line = self.pipe.readline().decode('utf-8')
if __name__ == "__main__":
pyls_cmd = ["python", "-m", "pyls"]
p = subprocess.Popen(pyls_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
pyls_cmd = ["python", "-m", "pyls"]
p = subprocess.Popen(pyls_cmd, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
read_pipe = ReadPipe(p.stderr)
read_pipe.start()
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(p.stdin, p.stdout)
# To work with socket: sock_fd = sock.makefile()
lsp_endpoint = pylspclient.LspEndpoint(json_rpc_endpoint)
lsp_client = pylspclient.LspClient(lsp_endpoint)
capabilities = {'textDocument': {'codeAction': {'dynamicRegistration': True},
'codeLens': {'dynamicRegistration': True},
'colorProvider': {'dynamicRegistration': True},
'completion': {'completionItem': {'commitCharactersSupport': True,
'documentationFormat': ['markdown', 'plaintext'],
'snippetSupport': True},
'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]},
'contextSupport': True,
'dynamicRegistration': True},
'definition': {'dynamicRegistration': True},
'documentHighlight': {'dynamicRegistration': True},
'documentLink': {'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]}},
'formatting': {'dynamicRegistration': True},
'hover': {'contentFormat': ['markdown', 'plaintext'],
'dynamicRegistration': True},
'implementation': {'dynamicRegistration': True},
'onTypeFormatting': {'dynamicRegistration': True},
'publishDiagnostics': {'relatedInformation': True},
'rangeFormatting': {'dynamicRegistration': True},
'references': {'dynamicRegistration': True},
'rename': {'dynamicRegistration': True},
'signatureHelp': {'dynamicRegistration': True,
'signatureInformation': {'documentationFormat': ['markdown', 'plaintext']}},
'synchronization': {'didSave': True,
'dynamicRegistration': True,
'willSave': True,
'willSaveWaitUntil': True},
'typeDefinition': {'dynamicRegistration': True}},
'workspace': {'applyEdit': True,
'configuration': True,
'didChangeConfiguration': {'dynamicRegistration': True},
'didChangeWatchedFiles': {'dynamicRegistration': True},
'executeCommand': {'dynamicRegistration': 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]}},'workspaceEdit': {'documentChanges': True},
'workspaceFolders': True}}
root_uri = 'file:///path/to/python/project'
lsp_endpoint = pylspclient.LspEndpoint(json_rpc_endpoint)
lsp_client = pylspclient.LspClient(lsp_endpoint)
root_uri = 'file:///path/to/python/project'
workspace_folders = [{'name': 'python-lsp', 'uri': root_uri}]
print(lsp_client.initialize(p.pid, None, root_uri, None, capabilities, "off", workspace_folders))
print(lsp_client.initialize(p.pid, None, root_uri, None, Capabilities.data, "off", workspace_folders))
print(lsp_client.initialized())
lsp_client.shutdown()
lsp_client.exit()
lsp_client.exit()

View File

@ -22,15 +22,15 @@ class PyTest(TestCommand):
setup(
name="pylspclient",
version="0.0.2",
author="Avi Yeger",
author_email="yeger00@gmail.com",
description="LSP client implementation in Python",
name="PyLSPClient",
version="0.0.1",
author="ITDominator",
author_email="1itdominator@gmail.com",
description="Python LSP client implementation cloned from Avi Yeger's effoerts",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/yeger00/pylspclient",
packages=find_packages(),
tests_require=["pytest", "pytest_mock"],
cmdclass={"test": PyTest},
)
)

View File

@ -1,7 +1,14 @@
# Python imports
import os
import pylspclient
import pytest
# Lib imports
import pylspclient
# Application imports
JSON_RPC_RESULT_LIST = [
'Content-Length: 40\r\n\r\n{"key_str": "some_string", "key_num": 1}'.encode("utf-8"),
'Content-Length: 40\r\n\r\n{"key_num": 1, "key_str": "some_string"}'.encode("utf-8")
@ -9,12 +16,14 @@ JSON_RPC_RESULT_LIST = [
def test_send_sanity():
pipein, pipeout = os.pipe()
pipein = os.fdopen(pipein, "rb")
pipeout = os.fdopen(pipeout, "wb")
pipein, pipeout = os.pipe()
pipein = os.fdopen(pipein, "rb")
pipeout = os.fdopen(pipeout, "wb")
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(pipeout, None)
json_rpc_endpoint.send_request({"key_num":1, "key_str":"some_string"})
result = pipein.read(len(JSON_RPC_RESULT_LIST[0]))
result = pipein.read(len(JSON_RPC_RESULT_LIST[0]))
assert(result in JSON_RPC_RESULT_LIST)
@ -24,57 +33,66 @@ def test_send_class():
self.key_num = value_num
self.key_str = value_str
pipein, pipeout = os.pipe()
pipein = os.fdopen(pipein, "rb")
pipeout = os.fdopen(pipeout, "wb")
pipein, pipeout = os.pipe()
pipein = os.fdopen(pipein, "rb")
pipeout = os.fdopen(pipeout, "wb")
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(pipeout, None)
json_rpc_endpoint.send_request(RpcClass(1, "some_string"))
result = pipein.read(len(JSON_RPC_RESULT_LIST[0]))
result = pipein.read(len(JSON_RPC_RESULT_LIST[0]))
assert(result in JSON_RPC_RESULT_LIST)
def test_recv_sanity():
pipein, pipeout = os.pipe()
pipein = os.fdopen(pipein, "rb")
pipeout = os.fdopen(pipeout, "wb")
pipein, pipeout = os.pipe()
pipein = os.fdopen(pipein, "rb")
pipeout = os.fdopen(pipeout, "wb")
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(None, pipein)
pipeout.write('Content-Length: 40\r\n\r\n{"key_str": "some_string", "key_num": 1}'.encode("utf-8"))
pipeout.flush()
result = json_rpc_endpoint.recv_response()
result = json_rpc_endpoint.recv_response()
assert({"key_num":1, "key_str":"some_string"} == result)
def test_recv_wrong_header():
pipein, pipeout = os.pipe()
pipein = os.fdopen(pipein, "rb")
pipeout = os.fdopen(pipeout, "wb")
pipein, pipeout = os.pipe()
pipein = os.fdopen(pipein, "rb")
pipeout = os.fdopen(pipeout, "wb")
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(None, pipein)
pipeout.write('Contentength: 40\r\n\r\n{"key_str": "some_string", "key_num": 1}'.encode("utf-8"))
pipeout.flush()
with pytest.raises(pylspclient.lsp_structs.ResponseError):
result = json_rpc_endpoint.recv_response()
print("should never get here", result)
print("Shouldn't' ever get here...", result)
def test_recv_missing_size():
pipein, pipeout = os.pipe()
pipein = os.fdopen(pipein, "rb")
pipeout = os.fdopen(pipeout, "wb")
pipein, pipeout = os.pipe()
pipein = os.fdopen(pipein, "rb")
pipeout = os.fdopen(pipeout, "wb")
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(None, pipein)
pipeout.write('Content-Type: 40\r\n\r\n{"key_str": "some_string", "key_num": 1}'.encode("utf-8"))
pipeout.flush()
with pytest.raises(pylspclient.lsp_structs.ResponseError):
result = json_rpc_endpoint.recv_response()
print("should never get here", result)
print("Shouldn't' ever get here...", result)
def test_recv_close_pipe():
pipein, pipeout = os.pipe()
pipein = os.fdopen(pipein, "rb")
pipeout = os.fdopen(pipeout, "wb")
pipein, pipeout = os.pipe()
pipein = os.fdopen(pipein, "rb")
pipeout = os.fdopen(pipeout, "wb")
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(None, pipein)
pipeout.close()
result = json_rpc_endpoint.recv_response()
result = json_rpc_endpoint.recv_response()
assert(result is None)