Browse Source

introduce helpers.warn_once()

Falko Schindler 10 months ago
parent
commit
f22690adf4

+ 11 - 12
nicegui/client.py

@@ -61,7 +61,6 @@ class Client:
         self.on_air = False
         self._disconnect_task: Optional[asyncio.Task] = None
         self._deleted = False
-        self._has_warned_about_deleted_client = False
         self.tab_id: Optional[str] = None
 
         self.outbox = Outbox(self)
@@ -196,17 +195,17 @@ class Client:
         :return: AwaitableResponse that can be awaited to get the result of the JavaScript code
         """
         if respond is True:
-            log.warning('The "respond" argument of run_javascript() has been removed. '
-                        'Now the method always returns an AwaitableResponse that can be awaited. '
-                        'Please remove the "respond=True" argument.')
+            helpers.warn_once('The "respond" argument of run_javascript() has been removed. '
+                              'Now the method always returns an AwaitableResponse that can be awaited. '
+                              'Please remove the "respond=True" argument.')
         if respond is False:
             raise ValueError('The "respond" argument of run_javascript() has been removed. '
                              'Now the method always returns an AwaitableResponse that can be awaited. '
                              'Please remove the "respond=False" argument and call the method without awaiting.')
         if check_interval != 0.01:
-            log.warning('The "check_interval" argument of run_javascript() and similar methods has been removed. '
-                        'Now the method automatically returns when receiving a response without checking regularly in an interval. '
-                        'Please remove the "check_interval" argument.')
+            helpers.warn_once('The "check_interval" argument of run_javascript() and similar methods has been removed. '
+                              'Now the method automatically returns when receiving a response without checking regularly in an interval. '
+                              'Please remove the "check_interval" argument.')
 
         request_id = str(uuid.uuid4())
         target_id = self._temporary_socket_id or self.id
@@ -328,11 +327,11 @@ class Client:
 
     def check_existence(self) -> None:
         """Check if the client still exists and print a warning if it doesn't."""
-        if self._deleted and not self._has_warned_about_deleted_client:
-            self._has_warned_about_deleted_client = True
-            log.warning('Client has been deleted but is still being used. This is most likely a bug in your application code. '
-                        'See https://github.com/zauberzeug/nicegui/issues/3028 for more information.',
-                        stack_info=True)
+        if self._deleted:
+            helpers.warn_once('Client has been deleted but is still being used. '
+                              'This is most likely a bug in your application code. '
+                              'See https://github.com/zauberzeug/nicegui/issues/3028 for more information.',
+                              stack_info=True)
 
     @contextmanager
     def individual_target(self, socket_id: str) -> Iterator[None]:

+ 4 - 4
nicegui/context.py

@@ -2,7 +2,7 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, List
 
-from .logging import log
+from . import helpers
 from .slot import Slot
 
 if TYPE_CHECKING:
@@ -13,17 +13,17 @@ class Context:
 
     def get_slot_stack(self) -> List[Slot]:
         """Return the slot stack of the current asyncio task. (DEPRECATED, use context.slot_stack instead)"""
-        log.warning('context.get_slot_stack() is deprecated, use context.slot_stack instead')
+        helpers.warn_once('context.get_slot_stack() is deprecated, use context.slot_stack instead')
         return self.slot_stack
 
     def get_slot(self) -> Slot:
         """Return the current slot. (DEPRECATED, use context.slot instead)"""
-        log.warning('context.get_slot() is deprecated, use context.slot instead')
+        helpers.warn_once('context.get_slot() is deprecated, use context.slot instead')
         return self.slot
 
     def get_client(self) -> Client:
         """Return the current client. (DEPRECATED, use context.client instead)"""
-        log.warning('context.get_client() is deprecated, use context.client instead')
+        helpers.warn_once('context.get_client() is deprecated, use context.client instead')
         return self.client
 
     @property

+ 2 - 3
nicegui/elements/highchart.py

@@ -1,6 +1,5 @@
-from .. import optional_features
+from .. import helpers, optional_features
 from ..element import Element
-from ..logging import log
 from .markdown import Markdown
 
 try:
@@ -22,4 +21,4 @@ except ImportError:
             """
             super().__init__()
             Markdown('Highcharts is not installed. Please run `pip install nicegui[highcharts]`.')
-            log.warning('Highcharts is not installed. Please run "pip install nicegui[highcharts]".')
+            helpers.warn_once('Highcharts is not installed. Please run "pip install nicegui[highcharts]".')

+ 3 - 3
nicegui/elements/menu.py

@@ -2,8 +2,8 @@ from typing import Any, Callable, Optional, Union
 
 from typing_extensions import Self
 
+from .. import helpers
 from ..element import Element
-from ..logging import log
 from .context_menu import ContextMenu
 from .item import Item
 from .mixins.value_element import ValueElement
@@ -41,8 +41,8 @@ class Menu(ValueElement):
         if 'touch-position' in self._props:
             # https://github.com/zauberzeug/nicegui/issues/1738
             del self._props['touch-position']
-            log.warning('The prop "touch-position" is not supported by `ui.menu`.\n'
-                        'Use "ui.context_menu()" instead.')
+            helpers.warn_once('The prop "touch-position" is not supported by `ui.menu`.\n'
+                              'Use "ui.context_menu()" instead.')
         return self
 
 

+ 3 - 3
nicegui/elements/tree.py

@@ -2,9 +2,9 @@ from typing import Any, Callable, Dict, Iterator, List, Literal, Optional, Set
 
 from typing_extensions import Self
 
+from .. import helpers
 from ..element import Element
 from ..events import GenericEventArguments, ValueChangeEventArguments, handle_event
-from ..logging import log
 
 
 class Tree(Element):
@@ -124,6 +124,6 @@ class Tree(Element):
         if 'default-expand-all' in self._props:
             # https://github.com/zauberzeug/nicegui/issues/1385
             del self._props['default-expand-all']
-            log.warning('The prop "default-expand-all" is not supported by `ui.tree`.\n'
-                        'Use ".expand()" instead.')
+            helpers.warn_once('The prop "default-expand-all" is not supported by `ui.tree`.\n'
+                              'Use ".expand()" instead.')
         return self

+ 2 - 3
nicegui/functions/style.py

@@ -10,7 +10,6 @@ except ImportError:
     pass
 
 from .. import helpers
-from ..logging import log
 from .html import add_head_html
 
 
@@ -25,8 +24,8 @@ def add_style(content: Union[str, Path], indented: bool = False) -> None:  # DEP
         content = Path(content).read_text()
     if optional_features.has('sass'):
         content = sass.compile(string=str(content).strip(), indented=indented)
-    log.warning("`ui.add_style` is deprecated, because it can't reliably detect the style language. "
-                'Use `ui.add_css`, `ui.add_scss` or `ui.add_sass` instead.')
+    helpers.warn_once("`ui.add_style` is deprecated, because it can't reliably detect the style language. "
+                      'Use `ui.add_css`, `ui.add_scss` or `ui.add_sass` instead.')
     add_head_html(f'<style>{content}</style>')
 
 

+ 12 - 1
nicegui/helpers.py

@@ -7,7 +7,18 @@ import threading
 import time
 import webbrowser
 from pathlib import Path
-from typing import Any, Optional, Tuple, Union
+from typing import Any, Optional, Set, Tuple, Union
+
+from .logging import log
+
+_shown_warnings: Set[str] = set()
+
+
+def warn_once(message: str, *, stack_info: bool = False) -> None:
+    """Print a warning message only once."""
+    if message not in _shown_warnings:
+        log.warning(message, stack_info=stack_info)
+        _shown_warnings.add(message)
 
 
 def is_pytest() -> bool: