Windows support
The lsp-devtools agent does not work on windows, due to the way it currently tries to obtain async readers/writers for stdin/stdout.
Hello @alcarney ,
Is there any update on this issue?
I'm looking to use your (awesome!) test framework and was trying to use lsp-devtools record alongside test execution to record a session replay file that helps debug the server outside the test environment. That worked well on Linux but when I switched to Windows to check that it works there, the test infra fails when spawning lsp-devtools agent.
And I can confirm the failure by calling lsp-devtools agent outside the context of a test (error below).
Meanwhile I'm going to look into creating the replay file in a different way, perhaps by overriding something at the protocol level to intercept messages as they are getting sent.
$ lsp-devtools agent -- ada_language_server
Exception in callback _ProactorReadPipeTransport._loop_reading()
handle: <Handle _ProactorReadPipeTransport._loop_reading()>
Traceback (most recent call last):
File "C:\it\local\e3\Lib\asyncio\proactor_events.py", line 305, in _loop_reading
self._read_fut = self._loop._proactor.recv_into(self._sock, self._data)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\it\local\e3\Lib\asyncio\windows_events.py", line 482, in recv_into
self._register_with_iocp(conn)
File "C:\it\local\e3\Lib\asyncio\windows_events.py", line 752, in _register_with_iocp
_overlapped.CreateIoCompletionPort(obj.fileno(), self._iocp, 0, 0)
OSError: [WinError 6] The handle is invalid
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\it\local\e3\Lib\asyncio\events.py", line 84, in _run
self._context.run(self._callback, *self._args)
File "C:\it\local\e3\Lib\asyncio\proactor_events.py", line 315, in _loop_reading
self._fatal_error(exc, 'Fatal read error on pipe transport')
File "C:\it\local\e3\Lib\asyncio\proactor_events.py", line 132, in _fatal_error
self._force_close(exc)
File "C:\it\local\e3\Lib\asyncio\proactor_events.py", line 135, in _force_close
if self._empty_waiter is not None and not self._empty_waiter.done():
^^^^^^^^^^^^^^^^^^
AttributeError: '_ProactorReadPipeTransport' object has no attribute '_empty_waiter'
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "C:\data\ancr\venv\Scripts\lsp-devtools.exe\__main__.py", line 7, in <module>
File "C:\data\ancr\venv\Lib\site-packages\lsp_devtools\cli.py", line 57, in main
return parsed_args.run(parsed_args, extra)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\data\ancr\venv\Lib\site-packages\lsp_devtools\agent\__init__.py", line 58, in run_agent
asyncio.run(main(args, extra))
File "C:\it\local\e3\Lib\asyncio\runners.py", line 190, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "C:\it\local\e3\Lib\asyncio\runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\it\local\e3\Lib\asyncio\base_events.py", line 654, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "C:\data\ancr\venv\Lib\site-packages\lsp_devtools\agent\__init__.py", line 50, in main
await asyncio.gather(
File "C:\data\ancr\venv\Lib\site-packages\lsp_devtools\agent\agent.py", line 159, in start
self.reader, self.writer = await get_streams(self.stdin, self.stdout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\data\ancr\venv\Lib\site-packages\lsp_devtools\agent\agent.py", line 129, in get_streams
write_transport, write_protocol = await loop.connect_write_pipe(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\it\local\e3\Lib\asyncio\base_events.py", line 1619, in connect_write_pipe
transport = self._make_write_pipe_transport(pipe, protocol, waiter)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\it\local\e3\Lib\asyncio\proactor_events.py", line 681, in _make_write_pipe_transport
return _ProactorWritePipeTransport(self,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\it\local\e3\Lib\asyncio\proactor_events.py", line 440, in __init__
self._read_fut = self._loop._proactor.recv(self._sock, 16)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\it\local\e3\Lib\asyncio\windows_events.py", line 459, in recv
self._register_with_iocp(conn)
File "C:\it\local\e3\Lib\asyncio\windows_events.py", line 752, in _register_with_iocp
_overlapped.CreateIoCompletionPort(obj.fileno(), self._iocp, 0, 0)
OSError: [WinError 6] The handle is invalid
Exception ignored in: <function BaseSubprocessTransport.__del__ at 0x00000263C72CF4C0>
Traceback (most recent call last):
File "C:\it\local\e3\Lib\asyncio\base_subprocess.py", line 126, in __del__
File "C:\it\local\e3\Lib\asyncio\base_subprocess.py", line 104, in close
File "C:\it\local\e3\Lib\asyncio\proactor_events.py", line 109, in close
File "C:\it\local\e3\Lib\asyncio\base_events.py", line 762, in call_soon
File "C:\it\local\e3\Lib\asyncio\base_events.py", line 520, in _check_closed
RuntimeError: Event loop is closed
Is there any update on this issue?
I think the answer is to change the agent so that it works similar to how pygls works - reading sys.stdin in a background thread using a ThreadPoolExecutor.
I was looking at making the switch as part of #192 but had issues getting some of the tests to pass so reverted to the current approach for the time being.