pygls: `RecursionError: maximum recursion depth exceeded` on certain Python versions
👋 I’ve received a few reports of this over on the Ruff LSP repo (https://github.com/charliermarsh/ruff-vscode/issues/116). I started debugging and reduced it down to an MRE in pygls.
Given server.py:
from pygls import server
LSP_SERVER = server.LanguageServer(name="Example", version="0.1.0")
def start() -> None:
LSP_SERVER.start_io()
if __name__ == "__main__":
start()
And the following Dockerfile:
# syntax=docker/dockerfile:1
FROM python:3.7.4-slim-buster
RUN pip3 install pygls
COPY server.py server.py
RUN python -m server
Running docker build . gives me an infinite RecursionError:
> [4/4] RUN python -m server:
#10 0.367 Traceback (most recent call last):
#10 0.367 File "/usr/local/lib/python3.7/runpy.py", line 193, in _run_module_as_main
#10 0.367 "__main__", mod_spec)
#10 0.367 File "/usr/local/lib/python3.7/runpy.py", line 85, in _run_code
#10 0.367 exec(code, run_globals)
#10 0.367 File "/server.py", line 7, in <module>
#10 0.367 LSP_SERVER = server.LanguageServer(name="Example", version="0.1.0")
#10 0.367 File "/usr/local/lib/python3.7/site-packages/pygls/server.py", line 357, in __init__
#10 0.367 super().__init__(protocol_cls, converter_factory, loop, max_workers)
#10 0.367 File "/usr/local/lib/python3.7/site-packages/pygls/server.py", line 199, in __init__
#10 0.367 self.lsp = protocol_cls(self, converter_factory())
#10 0.367 File "/usr/local/lib/python3.7/site-packages/pygls/protocol.py", line 163, in default_converter
#10 0.367 converter = converters.get_converter()
#10 0.367 File "/usr/local/lib/python3.7/site-packages/lsprotocol/converters.py", line 17, in get_converter
#10 0.367 return _hooks.register_hooks(converter)
#10 0.367 File "/usr/local/lib/python3.7/site-packages/lsprotocol/_hooks.py", line 35, in register_hooks
#10 0.367 _resolve_forward_references()
#10 0.367 File "/usr/local/lib/python3.7/site-packages/lsprotocol/_hooks.py", line 30, in _resolve_forward_references
#10 0.367 attrs.resolve_types(value, lsp_types.ALL_TYPES_MAP, {})
#10 0.367 File "/usr/local/lib/python3.7/site-packages/attr/_funcs.py", line 408, in resolve_types
#10 0.367 hints = typing.get_type_hints(cls, globalns=globalns, localns=localns)
#10 0.367 File "/usr/local/lib/python3.7/typing.py", line 976, in get_type_hints
#10 0.367 value = _eval_type(value, base_globals, localns)
#10 0.367 File "/usr/local/lib/python3.7/typing.py", line 265, in _eval_type
#10 0.367 ev_args = tuple(_eval_type(a, globalns, localns) for a in t.__args__)
#10 0.367 File "/usr/local/lib/python3.7/typing.py", line 265, in <genexpr>
#10 0.367 ev_args = tuple(_eval_type(a, globalns, localns) for a in t.__args__)
#10 0.367 File "/usr/local/lib/python3.7/typing.py", line 266, in _eval_type
#10 0.367 if ev_args == t.__args__:
#10 0.367 File "/usr/local/lib/python3.7/typing.py", line 661, in __eq__
#10 0.367 return frozenset(self.__args__) == frozenset(other.__args__)
#10 0.367 File "/usr/local/lib/python3.7/typing.py", line 667, in __hash__
#10 0.367 return hash((self.__origin__, self.__args__))
#10 0.367 File "/usr/local/lib/python3.7/typing.py", line 666, in __hash__
...
#10 0.367 return hash((Union, frozenset(self.__args__)))
#10 0.367 File "/usr/local/lib/python3.7/typing.py", line 667, in __hash__
#10 0.367 return hash((self.__origin__, self.__args__))
#10 0.367 File "/usr/local/lib/python3.7/typing.py", line 480, in __hash__
#10 0.367 return hash((self.__forward_arg__, self.__forward_value__))
#10 0.367 RecursionError: maximum recursion depth exceeded while calling a Python object
Thanks as always for all your work on pygls!
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 30 (11 by maintainers)
The above-mentioned change seems to work, I ran the pygls test suite, and tested a few other servers on it. I plan on releasing the fix next week.
(Closing as this is resolved for me!)
Great idea @karthiknadig, thank you.
So I think we can close this issue then. The fix is essentially to reinstall Pygls. Or, for an end user, perhaps even just
lsprotocl, eg:pip install lsprotocol==2023.0.0a1.I think there’s a broader issue here in terms of version pinning. Ideally I think Pygls should have more control of the
lsprotocolversion it uses. I’m leaning towards pinning to a specific version, even though that means we’ll have to make new releases for everylsprotocolchange. @karthiknadig I wonder what you think about semantic versioning forlsprotocol?Yup! All good from my perspective.
@tombh I need to push out another release I will be doing it today.
Published
lsprotocolto pypi with the fix.Replace the entire file from lsprotocol main: https://github.com/microsoft/lsprotocol/blob/main/lsprotocol/types.py that should be enough.
@tombh I will need to investigate and see if fully resolving this is really needed or if it can be done on the fly. If it turns out that we have to resolve all types before we can build the converters then yes this means it won’t work for < 3.7.7.
I’ll reply back with my findings.