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

PermissionError for nbextensions on startup with v1.29+ #611

Open
brian-c-ogorman opened this issue Apr 18, 2024 · 6 comments
Open

PermissionError for nbextensions on startup with v1.29+ #611

brian-c-ogorman opened this issue Apr 18, 2024 · 6 comments
Labels
bug Something isn't working

Comments

@brian-c-ogorman
Copy link
Contributor

brian-c-ogorman commented Apr 18, 2024

I'm getting the following error when attempting to run Solara with version 1.29+:

PermissionError: [Errno 13] Permission denied: '/usr/local/share/jupyter/nbextensions/jupyter-vuetify/extension.js'

Everything works fine on 1.28.0 though. I started a thread in the discord questions channel, but it seems like an issue might be more appropriate.

This is the logging output with the stacktrace:

2024-04-18 16:04:17,505 [INFO ] [79501] solara.server.app: app-status check: 81d2c0e7-a41d-4c15-a4b5-8d12eca8cf73 app not started
2024-04-18 16:04:17,527 [INFO ] [79501] solara.server.app: Shut down virtual kernel: 81d2c0e7-a41d-4c15-a4b5-8d12eca8cf73
2024-04-18 16:04:17,574 [INFO ] [79501] solara.server.app: Disconnect page df0beeeb-043e-4b84-b676-2e470826b8ba for kernel 81d2c0e7-a41d-4c15-a4b5-8d12eca8cf73
2024-04-18 16:04:17,576 [INFO ] [79501] solara.server.app: Scheduling kernel cull, will wait for max 86400.0 before shutting down the virtual kernel 81d2c0e7-a41d-4c15-a4b5-8d12eca8cf73
2024-04-18 16:04:20,734 [ERROR] [79501] uvicorn.error: Exception in ASGI application
Traceback (most recent call last):
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/uvicorn/protocols/http/h11_impl.py", line 407, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 69, in __call__
    return await self.app(scope, receive, send)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/applications.py", line 123, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/middleware/errors.py", line 186, in __call__
    raise exc
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/middleware/errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/middleware/gzip.py", line 24, in __call__
    await responder(scope, receive, send)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/middleware/gzip.py", line 44, in __call__
    await self.app(scope, receive, self.send_with_gzip)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 65, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/routing.py", line 756, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/routing.py", line 776, in app
    await route.handle(scope, receive, send)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/routing.py", line 297, in handle
    await self.app(scope, receive, send)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/routing.py", line 77, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/starlette/routing.py", line 72, in app
    response = await func(request)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/solara/server/starlette.py", line 318, in root
    content = server.read_root(request_path, root_path)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/solara/server/server.py", line 266, in read_root
    nbextensions, nbextensions_hashes = get_nbextensions()
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/solara/cache.py", line 100, in __call__
    value = self.function(*args, **kwargs)
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/solara/server/server.py", line 432, in get_nbextensions
    nbextensions_hashes = {name: hash_extension(name) for name in nbextensions}
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/solara/server/server.py", line 432, in <dictcomp>
    nbextensions_hashes = {name: hash_extension(name) for name in nbextensions}
  File "/.../venv/solara-1-29/lib/python3.10/site-packages/solara/server/server.py", line 424, in hash_extension
    if (directory / (name + ".js")).exists():
  File "~/miniconda3/envs/py310/lib/python3.10/pathlib.py", line 1290, in exists
    self.stat()
  File "~/miniconda3/envs/py310/lib/python3.10/pathlib.py", line 1097, in stat
    return self._accessor.stat(self, follow_symlinks=follow_symlinks)
PermissionError: [Errno 13] Permission denied: '/usr/local/share/jupyter/nbextensions/jupyter-vuetify/extension.js'

It looks like it is related to this change, though whether that change is the cause or simply exposed the issue, I do not know.

@brian-c-ogorman
Copy link
Contributor Author

I have learned a bit more on this. I think my issue comes from this existence check here.

It seems that paths returned by:

from jupyter_core.paths import jupyter_path

jupyter_path("nbextensions")

do not always exist (which is why the function is calling exists()). In my case, the file that was being checked (/usr/local/share/jupyter/nbextensions/jupyter-vuetify/extension.js) did not exist.

However, pathlib.Path.exists() will raise a PermissionError if it does not have permission to read from the location/file. And in my case, my permissions to /usr/local/share were set to:

drwx------

It worked when I updated the directory permissions to:

drwxr-xr-x

While this does solve my issue, I think the code could be more robust here. If the user doesn't have permission to a folder or file, shouldn't that be considered the same as "does not exist"? That is, maybe the call to exists() should be wrapped in a try/except PermissionError, and then ignore paths/files that the user does not have permission to?

@maartenbreddels
Copy link
Contributor

Hi Brian,

thank you for the detailed explanation. This should be a relative easy fix (although difficult to test in CI).

Regards,

Maarten

@maartenbreddels maartenbreddels added the bug Something isn't working label Apr 19, 2024
@maartenbreddels
Copy link
Contributor

Do you feel comfortable opening a PR for this? https://solara.dev/documentation/advanced/development/setup should guide you though it.

@brian-c-ogorman
Copy link
Contributor Author

brian-c-ogorman commented May 5, 2024

Hi @maartenbreddels, sure, I'd like to give it a try 🙂. I might need some guidance on the testing bit.

I just tried setting up a development environment, but I ran into some issues creating a virtual environment from requirements-dev.txt. The development setup instructions don't specify which version of Python to use, so I tried both Python 3.9 and 3.10, but I had issues with both.

With Python 3.9:

ERROR: Ignored the following versions that require a different python version: 0.10.6 Requires-Python >=2.7, <3.6; 0.10.7 Requires-Python >=2.7, <3.6; 8.19.0 Requires-Python >=3.10; 8.20.0 Requires-Python >=3.10; 8.21.0 Requires-Python >=3.10; 8.22.0 Requires-Python >=3.10; 8.22.1 Requires-Python >=3.10; 8.22.2 Requires-Python >=3.10; 8.23.0 Requires-Python >=3.10; 8.24.0 Requires-Python >=3.10
ERROR: Could not find a version that satisfies the requirement pytest-ipywidgets==1.32.1; extra == "pytest" (from solara[pytest]) (from versions: 1.31.0)
ERROR: No matching distribution found for pytest-ipywidgets==1.32.1; extra == "pytest"

With Python 3.10:

ERROR: Ignored the following versions that require a different python version: 0.10.6 Requires-Python >=2.7, <3.6; 0.10.7 Requires-Python >=2.7, <3.6
ERROR: Could not find a version that satisfies the requirement pytest-ipywidgets==1.32.1; extra == "pytest" (from solara[pytest]) (from versions: 1.31.0)
ERROR: No matching distribution found for pytest-ipywidgets==1.32.1; extra == "pytest"

I'm not sure if it is okay to ignore these?

@iisakkirotko
Copy link
Collaborator

Hey @brian-c-ogorman!

It looks like pytest-ipywidgets hasn't been released for the last couple releases we've done (it should always release when we release solara). We'll get the releases out ASAP.

@iisakkirotko
Copy link
Collaborator

@brian-c-ogorman the dev install should work now!

brian-c-ogorman pushed a commit to brian-c-ogorman/solara that referenced this issue May 13, 2024
jupyter_core.paths.jupyter_path("nbextensions") may return directories
that do not exist. However, the user may not have permission to read
some of these paths, leading to a PermissionError when calling
pathlib.Path.exists(), which crashes the application.

This change catches the PermissionError and logs it as a warning,
preventing the application from crashing. Essentially: if the user does
not have permission to the path, it might as well not exist.

See widgetti#611
maartenbreddels pushed a commit that referenced this issue May 14, 2024
jupyter_core.paths.jupyter_path("nbextensions") may return directories
that do not exist. However, the user may not have permission to read
some of these paths, leading to a PermissionError when calling
pathlib.Path.exists(), which crashes the application.

This change catches the PermissionError and logs it as a warning,
preventing the application from crashing. Essentially: if the user does
not have permission to the path, it might as well not exist.

See #611

Co-authored-by: Brian O'Gorman <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants