Skip to content

Commit

Permalink
Fix misleading error message if storage secret is set (#3310)
Browse files Browse the repository at this point in the history
* fix misleading error message is storage secret is set

* add pytests

* fix storage access in on_connect handler
  • Loading branch information
falkoschindler authored Jul 8, 2024
1 parent c9feeac commit 32f5d49
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 3 deletions.
3 changes: 2 additions & 1 deletion nicegui/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from fastapi.templating import Jinja2Templates
from typing_extensions import Self

from . import background_tasks, binding, core, helpers, json
from . import background_tasks, binding, core, helpers, json, storage
from .awaitable_response import AwaitableResponse
from .dependencies import generate_resources
from .element import Element
Expand Down Expand Up @@ -245,6 +245,7 @@ def handle_handshake(self) -> None:
if self._disconnect_task:
self._disconnect_task.cancel()
self._disconnect_task = None
storage.request_contextvar.set(self.request)
for t in self.connect_handlers:
self.safe_invoke(t)
for t in core.app._connect_handlers: # pylint: disable=protected-access
Expand Down
10 changes: 8 additions & 2 deletions nicegui/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,11 @@ def set_storage_secret(storage_secret: Optional[str] = None) -> None:
elif storage_secret is not None:
core.app.add_middleware(RequestTrackingMiddleware)
core.app.add_middleware(SessionMiddleware, secret_key=storage_secret)
Storage.secret = storage_secret


class Storage:
secret: Optional[str] = None

def __init__(self) -> None:
self.path = Path(os.environ.get('NICEGUI_STORAGE_PATH', '.nicegui')).resolve()
Expand All @@ -120,7 +122,9 @@ def browser(self) -> Union[ReadOnlyDict, Dict]:
if self._is_in_auto_index_context():
raise RuntimeError('app.storage.browser can only be used with page builder functions '
'(https://nicegui.io/documentation/page)')
raise RuntimeError('app.storage.browser needs a storage_secret passed in ui.run()')
if Storage.secret is None:
raise RuntimeError('app.storage.browser needs a storage_secret passed in ui.run()')
raise RuntimeError('app.storage.browser can only be used within a UI context')
if request.state.responded:
return ReadOnlyDict(
request.session,
Expand All @@ -140,7 +144,9 @@ def user(self) -> PersistentDict:
if self._is_in_auto_index_context():
raise RuntimeError('app.storage.user can only be used with page builder functions '
'(https://nicegui.io/documentation/page)')
raise RuntimeError('app.storage.user needs a storage_secret passed in ui.run()')
if Storage.secret is None:
raise RuntimeError('app.storage.user needs a storage_secret passed in ui.run()')
raise RuntimeError('app.storage.user can only be used within a UI context')
session_id = request.session['id']
if session_id not in self._users:
self._users[session_id] = PersistentDict(self.path / f'storage-user-{session_id}.json', encoding='utf-8')
Expand Down
36 changes: 36 additions & 0 deletions tests/test_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,39 @@ def page():
screen.should_contain('Loaded')
screen.wait(0.5)
assert Path('.nicegui', 'storage-general.json').read_text('utf-8') == '{"a":{"b":0}}'


def test_missing_storage_secret(screen: Screen):
@ui.page('/')
def page():
ui.label(app.storage.user.get('message', 'no message'))

screen.open('/')
screen.assert_py_logger('ERROR', 'app.storage.user needs a storage_secret passed in ui.run()')


def test_storage_access_in_on_connect(screen: Screen):
@ui.page('/')
def root():
app.storage.user['value'] = 'Test'
app.on_connect(lambda: ui.label(app.storage.user.get('value')))

screen.ui_run_kwargs['storage_secret'] = 'secret'

screen.open('/')
screen.should_contain('Test')


def test_storage_access_in_binding_function(screen: Screen):
model = {'name': 'John'}

@ui.page('/')
def index():
def f(v):
return v + app.storage.user.get('surname', '')
ui.label().bind_text_from(model, 'name', backward=f)

screen.ui_run_kwargs['storage_secret'] = 'secret'

screen.open('/')
screen.assert_py_logger('ERROR', 'app.storage.user can only be used within a UI context')

0 comments on commit 32f5d49

Please sign in to comment.