Skip to content

Commit

Permalink
suggestions for readability
Browse files Browse the repository at this point in the history
  • Loading branch information
CodyCBakerPhD committed Mar 11, 2024
1 parent ed1422a commit 74a0a05
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 125 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ demo = [
"Bug Tracker" = "https://github.com/catalystneuro/tqdm_publisher/issues"

[project.scripts]
tqdm_publisher = "tqdm_publisher.demo.demo_command_line_interface:main"
tqdm_publisher = "tqdm_publisher._demo._demo_command_line_interface:_command_line_interface"

[tool.black]
line-length = 120
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ <h1>tqdm_progress</h1>
const { element, progress } = createProgressBar();
barElements.appendChild(element);

const id = Math.random().toString(36).substring(7);
bars[id] = progress;
const progress_bar_id = Math.random().toString(36).substring(7);
bars[progress_bar_id] = progress;

client.socket.send(JSON.stringify({ command: 'start', id }));
client.socket.send(JSON.stringify({ command: 'start', progress_bar_id }));
})

</script>
Expand Down
43 changes: 43 additions & 0 deletions src/tqdm_publisher/_demo/_demo_command_line_interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import os
import subprocess
import sys
from pathlib import Path

from ._server import run_demo

DEMO_BASE_FOLDER_PATH = Path(__file__).parent

CLIENT_FILE_PATH = DEMO_BASE_FOLDER_PATH / "_client.html"
SERVER_FILE_PATH = DEMO_BASE_FOLDER_PATH / "_server.py"


def _command_line_interface():
"""A simple command line interface for running the demo for TQDM Publisher."""
if len(sys.argv) <= 1:
print("No input provided. Please specify a command (e.g. 'demo').")
return

command = sys.argv[1]
if "-" in command:
print(
f"No command provided, but flag {command} was received. "
"Please specify a command before the flag (e.g. 'demo')."
)
return

flags_list = sys.argv[2:]
if len(flags_list) > 0:
print(f"No flags are accepted at this time, but flags {flags_list} were received.")
return

if command == "demo":
# For convenience - automatically pop-up a browser window on the locally hosted HTML page
if sys.platform == "win32":
os.system(f'start "" "{CLIENT_FILE_PATH}"')
else:
subprocess.run(["open", CLIENT_FILE_PATH])

run_demo()

else:
print(f"{command} is an invalid command.")
89 changes: 89 additions & 0 deletions src/tqdm_publisher/_demo/_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import asyncio
import json
import threading
import time
from typing import Dict, Any, List
from uuid import uuid4

import websockets

from tqdm_publisher import TQDMPublisher


def start_progress_bar(*, client_id: str, progress_bar_id: str, client_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.
"""
all_task_durations_in_seconds = [1.0 for _ in range(60)] # One minute at one second per update
progress_bar = TQDMPublisher(iterable=all_task_durations_in_seconds)

def run_function_on_progress_update(format_dict: dict) -> None:
"""
This is the injected callback that will be run on each update of the TQDM object.
Its first and only positional argument must be the `format_dict` of the TQDM instance. Additional customization
on outside parameters must be achieved by defining those fields at an outer scope and defining this
server-specific callback inside the local scope.
In this demo, we will execute the `client_callback` whose protocol is known only to the WebSocketHandler.
It has
"""
client_callback(client_id=client_id, progress_bar_id=progress_bar_id, format_dict=format_dict)

progress_bar.subscribe(callback=run_function_on_progress_update)

for task_duration in progress_bar:
time.sleep(task_duration)


class WebSocketHandler:
"""Describe this class."""

def __init__(self) -> None:
"""Initialize the mapping of client IDs to ."""
self.clients: Dict[str, Any] = dict()

def function_to_run_on_progress_update(self, *, client_id: str, progress_bar_id: str, format_dict: dict) -> None:
"""This is..."""
asyncio.run(self.send(client_id=client_id, data=dict(progress_bar_id=progress_bar_id, format_dict=format_dict)))

async def send(self, client_id: str, data: dict) -> None:
"""Send an arbitrary JSON object `data` to the client identifier by `client_id`."""
await self.clients[client_id].send(json.dumps(obj=data))

async def handler(self, websocket) -> None:
"""Describe what the handler does."""
client_id = str(uuid4())
self.clients[client_id] = websocket # Register client connection

try:
async for message in websocket:
message_from_client = json.loads(message)

if message_from_client["command"] == "start":
thread = threading.Thread(
target=start_progress_bar,
kwargs=dict(
client_id=client_id,
progress_bar_id=message_from_client["progress_bar_id"],
client_callback=self.function_to_run_on_progress_update,
),
)
thread.start()
finally: # This is called when the connection is closed
if client_id in self.clients:
del self.clients[client_id]


async def spawn_server() -> None:
"""Spawn the server asynchronously."""
handler = WebSocketHandler().handler
async with websockets.serve(handler, "", 8000):
await asyncio.Future()


def run_demo() -> None:
"""Trigger the execution of the asynchronous spawn."""
asyncio.run(spawn_server())
12 changes: 0 additions & 12 deletions src/tqdm_publisher/demo/client.py

This file was deleted.

41 changes: 0 additions & 41 deletions src/tqdm_publisher/demo/demo_command_line_interface.py

This file was deleted.

68 changes: 0 additions & 68 deletions src/tqdm_publisher/demo/server.py

This file was deleted.

0 comments on commit 74a0a05

Please sign in to comment.