diff --git a/src/tqdm_publisher/_demos/_multiple_bars/_server.py b/src/tqdm_publisher/_demos/_multiple_bars/_server.py index 69f9a8c..248a2ed 100644 --- a/src/tqdm_publisher/_demos/_multiple_bars/_server.py +++ b/src/tqdm_publisher/_demos/_multiple_bars/_server.py @@ -11,46 +11,56 @@ async def handler(websocket: websockets.WebSocketServerProtocol) -> None: """Handle messages from the client and manage the client connections.""" - class WebSocketProgressBar(threading.Thread): + class WebSocketProgressBar: + """ + This is similar to the `send_progress_update_to_client` function from the single bar demo server. + + The translation of this approach into a scoped class definition is merely to showcase an alternative approach + of the execution. + """ def __init__(self, request_id: str): super().__init__() self.request_id = request_id - def update(self, format_dict) -> None: + def update(self, format_dict: dict) -> None: """ This is the function that will run on every update of the TQDM object. It will forward the progress to the client. """ asyncio.run( - websocket.send(message=json.dumps(obj=dict(request_id=self.request_id, format_dict=format_dict))) + websocket.send(message=json.dumps(obj=dict(format_dict=format_dict, request_id=self.request_id))) ) def run(self): """ Emulate running the specified number of tasks by sleeping the specified amount of time on each iteration. - Defaults are chosen for a deterministic and regular update period of one second for a total time of one minute. + Defaults are chosen for a deterministic and regular update period of one second for a total time of + seconds per bar. + + This is similar to the `start_progress_bar` function from the single bar demo server. This is simply a + showcase of an alternative approach to defining and scoping the execution. """ all_task_durations_in_seconds = [1.0 for _ in range(10)] # Ten seconds at one task per second - progress_bar = self.progress_bar = tqdm_publisher.TQDMPublisher(iterable=all_task_durations_in_seconds) - progress_bar.subscribe(callback=self.update) + self.progress_bar = tqdm_publisher.TQDMPublisher(iterable=all_task_durations_in_seconds) + self.progress_bar.subscribe(callback=self.update) - for task_duration in progress_bar: + for task_duration in self.progress_bar: time.sleep(task_duration) - # def start(self): - # thread = threading.Thread(target=self.run_progress_bar) - # thread.start() + def start(self): + thread = threading.Thread(target=self.run) + thread.start() # Wait for messages from the client async for message in websocket: message_from_client = json.loads(message) if message_from_client["command"] == "start": - progress_bar = WebSocketProgressBar(request_id=message_from_client["request_id"]) - progress_bar.start() + web_socket_progress_bar = WebSocketProgressBar(request_id=message_from_client["request_id"]) + web_socket_progress_bar.start() async def spawn_server() -> None: diff --git a/src/tqdm_publisher/_demos/_single_bar/_server.py b/src/tqdm_publisher/_demos/_single_bar/_server.py index c8e739b..a29c89b 100644 --- a/src/tqdm_publisher/_demos/_single_bar/_server.py +++ b/src/tqdm_publisher/_demos/_single_bar/_server.py @@ -12,7 +12,7 @@ def start_progress_bar(*, progress_callback: callable) -> None: """ Emulate running the specified number of tasks by sleeping the specified amount of time on each iteration. - Defaults are chosen for a deterministic and regular update period of one second for a total time of one minute. + Defaults are chosen for a deterministic and regular update period of one second for a total time of 10 seconds. """ all_task_durations_in_seconds = [1.0 for _ in range(10)] # Ten seconds at one second per task progress_bar = tqdm_publisher.TQDMPublisher(iterable=all_task_durations_in_seconds) @@ -29,7 +29,7 @@ def run_function_on_progress_update(format_dict: dict) -> None: This specifically requires the `id` of the progress bar and the `format_dict` of the TQDM instance. """ - progress_callback(id=progress_bar.id, format_dict=format_dict) + progress_callback(format_dict=format_dict, progress_bar_id=progress_bar.id) progress_bar.subscribe(callback=run_function_on_progress_update) @@ -37,34 +37,26 @@ def run_function_on_progress_update(format_dict: dict) -> None: time.sleep(task_duration) -def send_message_to_client(*, websocket: websockets.WebSocketServerProtocol, message: dict) -> None: - """ - Send a message to a specific client. - - This expects a WebSocket connection and a message (dict) to send. - """ - - asyncio.run(websocket.send(message=json.dumps(obj=message))) - - async def handler(websocket: websockets.WebSocketServerProtocol) -> None: """Handle messages from the client and manage the client connections.""" + def send_progress_update_to_client(*, format_dict: dict, progress_bar_id: str) -> None: + """ + This is the callback that actually sends the updated `format_dict` to the front end webpage. + + It must be defined within the scope of the handler so that the `websocket` is inherited from the higher level. + """ + message = json.dumps(obj=dict(format_dict=format_dict, progress_bar_id=progress_bar_id)) + asyncio.run(websocket.send(message=message)) + # Wait for messages from the client async for message in websocket: message_from_client = json.loads(message) if message_from_client["command"] == "start": - # Start the progress bar in a separate thread thread = threading.Thread( - target=start_progress_bar, - # On each update of the progress bar, send this update to the requesting client - kwargs=dict( - progress_callback=lambda id, format_dict: send_message_to_client( - websocket=websocket, message=dict(id=id, format_dict=format_dict) - ) - ), + target=start_progress_bar, kwargs=dict(progress_callback=send_progress_update_to_client) ) thread.start() diff --git a/src/tqdm_publisher/_publisher.py b/src/tqdm_publisher/_publisher.py index d5cc3b3..81a7ee8 100644 --- a/src/tqdm_publisher/_publisher.py +++ b/src/tqdm_publisher/_publisher.py @@ -8,7 +8,7 @@ class TQDMPublisher(base_tqdm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.id = str(uuid4()) - self.callbacks = {} + self.callbacks = dict() # Override the update method to run callbacks def update(self, n: int = 1) -> Union[bool, None]: