swyddfa / esbonio

A language server for working with Sphinx projects.
https://docs.esbon.io/
121 stars 21 forks source link

Breaks if `esbonio` is installed globally #761

Closed neongreen-sc closed 3 months ago

neongreen-sc commented 3 months ago

Expected behavior

If global python has esbonio installed, it should either be ignored or I should get an error message.

Actual behavior

Esbonio cannot start the server.

Log output

[esbonio] Unable to import module 'esbonio.server.features.preview_manager'
Traceback (most recent call last):
  File "c:\workspace\python-3.11.2\Lib\site-packages\esbonio\server\setup.py", line 123, in _load_module
    module = importlib.import_module(modname)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "importlib\__init__.py", line 126, in import_module
  File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1149, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "c:\workspace\python-3.11.2\Lib\site-packages\esbonio\server\features\preview_manager\__init__.py", line 18, in <module>
    from .webview import WebviewServer
  File "c:\workspace\python-3.11.2\Lib\site-packages\esbonio\server\features\preview_manager\webview.py", line 13, in <module>
    from websockets.server import serve
ModuleNotFoundError: No module named 'websockets'

(Optional) Settings from conf.py

No response

neongreen-sc commented 3 months ago

NB: this is for the prerelease version (0.92.1)

alcarney commented 3 months ago

I can't think of why this might be happening since the extension does try to ensure that the bundled version of esbonio is used. (By running python -S and using the PYTHONPATH environment variable to make the relevant dependencies available)

Could you add a file called test.py to the root of your workspace that contains

import sys
print(sys.path, file=sys.stderr)

and set esbonio.server.startupModule to test.py before running the Esbonio: Restart Language Server command.

You'll get a bunch of errors, but you should also see the contents of sys.path in the Output window e.g.

[client] Starting Language Server
['/var/home/alex/Projects/swyddfa/esbonio/develop/docs', '/var/home/alex/Projects/swyddfa/esbonio/develop/code/bundled/libs', '/usr/lib64/python312.zip', '/usr/lib64/python3.12', '/usr/lib64/python3.12/lib-dynload']
[Error - 19:52:42] Server process exited with code 0.

We should then at least be able to see where Python is looking for esbonio and work backwards from there.

neongreen-sc commented 3 months ago

@alcarney done!

['c:\\workspace\\python-3.11.2\\python311.zip', 'c:\\workspace\\python-3.11.2', 'c:\\workspace\\python-3.11.2\\Lib\\site-packages']

This corresponds to the python interpreter I chose in VSCode.

neongreen-sc commented 3 months ago

I also printed os.environ and it does look like PYTHONPATH is set correctly:

'PYTHONPATH': 'c:\\Users\\[username]\\.vscode\\extensions\\swyddfa.esbonio-0.92.1\\bundled\\libs'
neongreen-sc commented 3 months ago

Oh wait, right.

I forgot that our org ships a broken version of Python that does not respect $PYTHONPATH.

Yeah that would explain it.

Do you know if there's any way to initialize sys.path manually that wouldn't involve forking the VSCode extension?

alcarney commented 3 months ago

Umm... we could probably do it here in test.py and start the server ourselves...

I think something like the following would work

import os
import sys

sys.path.insert(0, os.environ['PYTHONPATH'])

from esbonio.server.cli import main

sys.exit(main())
neongreen-sc commented 3 months ago

I will close this issue, because there's nothing esbonio can do with broken python.