diff --git a/nicegui/client.py b/nicegui/client.py index 40e21c43a..08bec5bda 100644 --- a/nicegui/client.py +++ b/nicegui/client.py @@ -61,7 +61,6 @@ def __init__(self, page: page, *, request: Optional[Request]) -> None: 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 @@ def run_javascript(self, code: str, *, :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 @@ def delete(self) -> None: 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]: diff --git a/nicegui/context.py b/nicegui/context.py index 929125a66..418051d95 100644 --- a/nicegui/context.py +++ b/nicegui/context.py @@ -2,7 +2,7 @@ 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 diff --git a/nicegui/elements/highchart.py b/nicegui/elements/highchart.py index b1b8d63c9..59cece62e 100644 --- a/nicegui/elements/highchart.py +++ b/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 @@ def __init__(self, *args, **kwargs) -> None: # pylint: disable=unused-argument """ 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]".') diff --git a/nicegui/elements/menu.py b/nicegui/elements/menu.py index 845928fd0..f741176e6 100644 --- a/nicegui/elements/menu.py +++ b/nicegui/elements/menu.py @@ -2,8 +2,8 @@ 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 @@ def props(self, add: Optional[str] = None, *, remove: Optional[str] = None) -> S 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 diff --git a/nicegui/elements/tree.py b/nicegui/elements/tree.py index 3f6a6e4a5..47bb67f7b 100644 --- a/nicegui/elements/tree.py +++ b/nicegui/elements/tree.py @@ -2,9 +2,9 @@ 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 @@ def props(self, add: Optional[str] = None, *, remove: Optional[str] = None) -> S 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 diff --git a/nicegui/functions/style.py b/nicegui/functions/style.py index 962563877..bcd234873 100644 --- a/nicegui/functions/style.py +++ b/nicegui/functions/style.py @@ -10,7 +10,6 @@ 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'') diff --git a/nicegui/helpers.py b/nicegui/helpers.py index 4689a4c4a..838dbf968 100644 --- a/nicegui/helpers.py +++ b/nicegui/helpers.py @@ -7,7 +7,18 @@ 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: