Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

ui.log raise error : "Client has been deleted but is still being used" on first page refresh .... #4422

Closed
zak-45 opened this issue Mar 5, 2025 · 0 comments

Comments

@zak-45
Copy link

zak-45 commented Mar 5, 2025

Description

Info : Win 11, Python 3.12, NiceGUI 2.12.1

I have made a script to capture stdin, stderr and put the messages into ui.log().
All is working well, except on first page reload (...no more after), I receive this error message:

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 (most recent call last):
  File "C:\Program Files\Python311\Lib\threading.py", line 1002, in _bootstrap
    self._bootstrap_inner()
  File "C:\Program Files\Python311\Lib\threading.py", line 1045, in _bootstrap_inner
    self.run()
  File "C:\Program Files\Python311\Lib\threading.py", line 982, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Users\zak-4\PycharmProjects\WLEDVideoSync\src\utl\console.py", line 74, in read_queue
    self.log_ui.push(log_message)
  File "C:\Users\zak-4\PycharmProjects\WLEDVideoSync\.venv\Lib\site-packages\nicegui\elements\log.py", line 26, in push
    Label(text)
  File "C:\Users\zak-4\PycharmProjects\WLEDVideoSync\.venv\Lib\site-packages\nicegui\elements\label.py", line 13, in __init__
    super().__init__(tag='div', text=text)
  File "C:\Users\zak-4\PycharmProjects\WLEDVideoSync\.venv\Lib\site-packages\nicegui\elements\mixins\text_element.py", line 14, in __init__
    super().__init__(**kwargs)
  File "C:\Users\zak-4\PycharmProjects\WLEDVideoSync\.venv\Lib\site-packages\nicegui\element.py", line 77, in __init__
    self.client.outbox.enqueue_update(self)
  File "C:\Users\zak-4\PycharmProjects\WLEDVideoSync\.venv\Lib\site-packages\nicegui\outbox.py", line 50, in enqueue_update
    self.client.check_existence()
  File "C:\Users\zak-4\PycharmProjects\WLEDVideoSync\.venv\Lib\site-packages\nicegui\client.py", line 346, in check_existence
    helpers.warn_once('Client has been deleted but is still being used. '
  File "C:\Users\zak-4\PycharmProjects\WLEDVideoSync\.venv\Lib\site-packages\nicegui\helpers.py", line 20, in warn_once
    log.warning(message, stack_info=stack_info)

Had take a look to the provided link, but not really related for my case ..??!!

Here is the script :

from nicegui import ui
import sys
import multiprocessing
import threading
import time

class ConsoleCapture:
    """Captures and displays console output in a NiceGUI UI.

    Redirects stdout and stderr to a queue, which is then displayed
    in an ui.log element.  Provides options for UI customization and restoring
    the original console output streams.
    """
    def __init__(self, show_console=False, text_color='text-white', bg_color='bg-black'):
        """Initialize the ConsoleCapture.

        Sets up console capturing by redirecting stdout and stderr, initializing the UI
        if requested, and starting a background thread to process captured output.
        """
        self.original_stdout = sys.stdout
        self.original_stderr = sys.stderr
        self.text_color = text_color
        self.bg_color = bg_color
        if show_console:
            self.setup_ui()
        else:
            self.log_ui = None
        self.log_queue = multiprocessing.Queue()

        sys.stdout = self
        sys.stderr = self

        # Start a background thread to read from the queue
        self.running = True
        threading.Thread(target=self.read_queue, daemon=True).start()

    def setup_ui(self):
        """Set up the UI for the console output.

        Creates and configures an ui.log element to display captured console output,
        applying specified styling classes.
        """
        self.log_ui = ui.log()
        self.log_ui.classes(f'console-output w-full h-30 {self.bg_color} {self.text_color}')

    def write(self, text):
        """Override sys.stdout and sys.stderr to send output to the queue and original streams."""
        if text.strip():
            self.log_queue.put(text.strip())  # Send to the queue
            # Write to the original stdout or stderr
            if "Error" in text:
                self.original_stderr.write(text)
            else:
                self.original_stdout.write(text)

    def flush(self):
        """Flush method for compatibility."""
        pass

    def restore(self):
        """Restore original stdout and stderr."""
        sys.stdout = self.original_stdout
        sys.stderr = self.original_stderr
        self.running = False

    def read_queue(self):
        """Continuously read from the queue and update the UI log."""
        while self.running:
            try:
                while not self.log_queue.empty():
                    log_message = self.log_queue.get()
                    if self.log_ui is not None:
                        self.log_ui.push(log_message)
            except Exception as e:
                self.original_stderr.write(f"Queue reading error: {e}\n")
            time.sleep(0.1)  # Prevent busy waiting


if __name__ in "__main__":
    # NiceGUI app
    @ui.page('/')
    async def main_page():

        capture = ConsoleCapture(show_console=False)

        with ui.column():
            ui.button('Print Message', on_click=lambda: print('Hello from stdout!'))
            ui.button('Raise Exception', on_click=lambda: 1 / 0)
            ui.button('Send Custom Log', on_click=lambda: capture.log_queue.put("[INFO] Custom log message"))
            ui.button('Restore Console', on_click=capture.restore)

        capture.setup_ui()

        ui.context.client.on_disconnect(lambda: print('client disconnected'))
        ui.context.client.on_disconnect(lambda: print('client connected'))

    ui.run(reload=False)

Thanks

@zauberzeug zauberzeug locked and limited conversation to collaborators Mar 5, 2025
@falkoschindler falkoschindler converted this issue into discussion #4423 Mar 5, 2025

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant