Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot send a TEXT_DOCUMENT_DID_OPEN to the language server for testing purposes #312

Open
dcermak opened this issue Jan 23, 2023 · 6 comments

Comments

@dcermak
Copy link
Contributor

dcermak commented Jan 23, 2023

I am currently migrating salt-lsp from pygls 0.11 to 1.0, which so far went without major issues except that my testing code can no longer open a file on the server by sending a TEXT_DOCUMENT_DID_OPEN. I was using this code:

def open_file(
    client: LanguageServer, file_path: str, request_timeout: int = 5
) -> None:
    with open(file_path) as base_sls:
        proto: SaltLspProto = client.lsp
        proto.send_request(
            TEXT_DOCUMENT_DID_OPEN,
            DidOpenTextDocumentParams(
                text_document=TextDocumentItem(
                    uri="file://" + file_path,
                    language_id="sls",
                    version=0,
                    text=base_sls.read(-1),
                )
            ),
        ).result(timeout=request_timeout)

This used to work with the previous pygls version, but that now fails with:

_________________________________________________________________________________________________________________________________________________________________ test_find_id_in_indirect_include __________________________________________________________________________________________________________________________________________________________________
                                                                                                                                                                                                                                                                                                                                                                     
salt_client_server = (<pygls.server.LanguageServer object at 0x7ffa9669f210>, <salt_lsp.server.SaltServer object at 0x7ffa96682cd0>), sample_workspace = PosixPath('/tmp/pytest-of-dan/pytest-6/test_find_id_in_indirect_inclu0')                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                     
    def test_find_id_in_indirect_include(salt_client_server, sample_workspace):                                                                                                                                                                                                                                                                                      
        client, server = salt_client_server                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                                                                                                     
        open_workspace(client, f"file://{sample_workspace}")                                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                                                                                     
        foo_sls_path = f"{sample_workspace}/foo.sls"                                                                                                                                                                                                                                                                                                                 
        foo_sls_uri = "file://" + foo_sls_path                                                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                                                                     
>       open_file(client, foo_sls_path)                                                                                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                                     
tests/test_find_ids.py:60:                                                                                                                                                                                                                                                                                                                                           
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
tests/conftest.py:647: in open_file                                                                                                                                                                                                                                                                                                                                  
    proto.send_request(                                                                                                                                                                                                                                                                                                                                              
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
                                                                                                                                                                                                                                                                                                                                                                     
self = <pygls.protocol.LanguageServerProtocol object at 0x7ffa987e18d0>, method = 'textDocument/didOpen', params = DidOpenTextDocumentParams(text_document=TextDocumentItem(uri='file:///tmp/pytest-of-dan/pytest-6/test_find_id_in_indirect_inclu0/foo.sls', language_id='sls', version=0, text='include:\n  - bar\n  - baz\n')), callback = None                   
msg_id = '0f0051b2-d26c-401f-94ea-3b6f46c9e5a6'                                                                                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                                                     
    def send_request(self, method, params=None, callback=None, msg_id=None):                                                                                                                                                                                                                                                                                         
        """Sends a JSON RPC request to the client.                                                                                                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                                                                                                     
        Args:                                                                                                                                                                                                                                                                                                                                                        
            method(str): The method name of the message to send                                                                                                                                                                                                                                                                                                      
            params(any): The payload of the message                                                                                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                                                                                                                     
        Returns:                                                                                                                                                                                                                                                                                                                                                     
            Future that will be resolved once a response has been received                                                                                                                                                                                                                                                                                           
        """                                                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                                                                                                     
        if msg_id is None:                                                                                                                                                                                                                                                                                                                                           
            msg_id = str(uuid.uuid4())                                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                                                                                     
        request_type = self.get_message_type(method) or JsonRPCRequestMessage                                                                                                                                                                                                                                                                                        
        logger.debug('Sending request with id "%s": %s %s', msg_id, method, params)                                                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                                                                                                                     
>       request = request_type(                                                                                                                                                                                                                                                                                                                                      
            id=msg_id,                                                                                                                                                                                                                                                                                                                                               
            method=method,                                                                                                                                                                                                                                                                                                                                           
            params=params,                                                                                                                                                                                                                                                                                                                                           
            jsonrpc=JsonRPCProtocol.VERSION,                                                                                                                                                                                                                                                                                                                         
        )                                                                                                                                                                                                                                                                                                                                                            
E       TypeError: TextDocumentDidOpenNotification.__init__() got an unexpected keyword argument 'id'                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                                                                                                     
/home/dan/.cache/pypoetry/virtualenvs/salt-lsp-qRQ_K-3P-py3.11/lib/python3.11/site-packages/pygls/protocol.py:581: TypeError                                                                                                                                                                                                                                         
dcermak pushed a commit to dcermak/pygls that referenced this issue Jan 23, 2023
dcermak added a commit to dcermak/pygls that referenced this issue Jan 23, 2023
@tombh
Copy link
Collaborator

tombh commented Jan 23, 2023

Ohh is this what #313 fixes?

@dcermak
Copy link
Contributor Author

dcermak commented Jan 23, 2023

Yes

@alcarney
Copy link
Collaborator

This is expected as textDocument/didOpen is a notification, not a request (see spec)
There is the notify method that you can use instead.

This means that the changes in #313 shouldn't be necessary.

@tombh
Copy link
Collaborator

tombh commented Jan 23, 2023

Thank you @alcarney 🙇 I suspect this will resolve the issue, if so then we'll close the issue and PR.

dcermak added a commit to dcermak/pygls that referenced this issue Jan 23, 2023
@dcermak
Copy link
Contributor Author

dcermak commented Jan 23, 2023

This is expected as textDocument/didOpen is a notification, not a request (see spec)
There is the notify method that you can use instead.

Ah, thank you! I have switched to using notify, which fixes the runtime error, but sadly it creates a new one: The notify function is synchronous, but the processing of that notification happens asynchronously in the background. So the tests that run immediately after that fail, as the document has not yet been loaded. This worked with send_request, albeit of course only accidentally. Can I somehow wait for the result of that notification to be processed?

@alcarney
Copy link
Collaborator

Unfortunately, I don't know of anything in the spec to help with this.

The solution I came up with for esbonio was to have the server send a custom notification of its own after it finished what I was waiting for and then extend the LanguageServerProtocol object used client side to add a mechanism to wait for a given notification

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants