python-lsp / python-lsp-server

Fork of the python-language-server project, maintained by the Spyder IDE team and the community
MIT License
1.76k stars 186 forks source link

flake8 can error out when deleting lines #438

Closed krassowski closed 10 months ago

krassowski commented 10 months ago

In 1.8.0 (did not check earlier versions yet) when lines are deleted while flake8 lint is running, and the diagnostic would end out of range of current document, flake8 can error out:

Traceback (most recent call last):
  File "site-packages/pylsp/config/config.py", line 40, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pluggy/_manager.py", line 418, in traced_hookexec
    return outcome.get_result()
           ^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pluggy/_result.py", line 108, in get_result
    raise exc.with_traceback(exc.__traceback__)
  File "site-packages/pluggy/_result.py", line 70, in from_call
    result = func()
             ^^^^^^
  File "site-packages/pluggy/_manager.py", line 415, in <lambda>
    lambda: oldcall(hook_name, hook_impls, caller_kwargs, firstresult)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pluggy/_callers.py", line 116, in _multicall
    raise exception.with_traceback(exception.__traceback__)
  File "site-packages/pluggy/_callers.py", line 80, in _multicall
    res = hook_impl.function(*args)
          ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pylsp/plugins/flake8_lint.py", line 83, in pylsp_lint
    return parse_stdout(document, output)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "site-packages/pylsp/plugins/flake8_lint.py", line 215, in parse_stdout
    "character": len(document.lines[line]),
                     ~~~~~~~~~~~~~~^^^^^^
IndexError: list index out of range

The relevant line is:

https://github.com/python-lsp/python-lsp-server/blob/6c168d0f8ee2e59ec8438373bc2c1b33cb74cdfa/pylsp/plugins/flake8_lint.py#L215

To reproduce create a python file like:


variable

This will generate "F821 undefined name 'variable'". Then proceed to removing the empty lines and observe the error. Note:

ccordoba12 commented 10 months ago

It seems there is a mismatch between the state of the document (reflected in document.lines) and the flake8 output. So when document.lines is accessed in the line you referenced, the actual lines are different.

A possible solution could be to pass document.lines to parse_output, instead of document, so that the latter method is called with the current document state.

Could you try that to see if it fixes the problem? Thanks!

krassowski commented 10 months ago

It does. In particular, it seems that accessing document.lines in a loop is a bad idea as it reads can read from disk at each access (if the private _source is None):

https://github.com/python-lsp/python-lsp-server/blob/8377b2cb11208dfda917100807cf3d6019ac58ef/pylsp/workspace.py#L414-L425