Kaynağa Gözat

Fix misleading error message if storage secret is set (#3310)

* fix misleading error message is storage secret is set

* add pytests

* fix storage access in on_connect handler
Falko Schindler 10 ay önce
ebeveyn
işleme
32f5d497cf
3 değiştirilmiş dosya ile 46 ekleme ve 3 silme
  1. 2 1
      nicegui/client.py
  2. 8 2
      nicegui/storage.py
  3. 36 0
      tests/test_storage.py

+ 2 - 1
nicegui/client.py

@@ -13,7 +13,7 @@ from fastapi.responses import Response
 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
@@ -245,6 +245,7 @@ class Client:
         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

+ 8 - 2
nicegui/storage.py

@@ -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()
@@ -120,7 +122,9 @@ class Storage:
             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,
@@ -140,7 +144,9 @@ class Storage:
             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')

+ 36 - 0
tests/test_storage.py

@@ -278,3 +278,39 @@ def test_deepcopy(screen: Screen):
     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')