diff --git a/openadapt/app/main.py b/openadapt/app/main.py
index ab5d68a81..fac1f3f77 100644
--- a/openadapt/app/main.py
+++ b/openadapt/app/main.py
@@ -8,12 +8,14 @@
run_app()
"""
+from functools import partial
+from subprocess import Popen
import base64
import os
from nicegui import app, ui
-from openadapt import config, replay, visualize
+from openadapt import config, replay
from openadapt.app.cards import recording_prompt, select_import, settings
from openadapt.app.objects.console import Console
from openadapt.app.util import clear_db, on_export, on_import
@@ -31,62 +33,57 @@
logger = None
-# Add logo
-# right align icon
-with ui.row().classes("w-full justify-right"):
- # settings
- # alignment trick
- with ui.avatar(color="white" if dark else "black", size=128):
- logo_base64 = base64.b64encode(
- open(os.path.join(FPATH, "assets/logo.png"), "rb").read()
+def start(fullscreen: bool = False) -> None:
+ """Start the OpenAdapt application."""
+ with ui.row().classes("w-full justify-right"):
+ with ui.avatar(color="white" if dark else "black", size=128):
+ logo_base64 = base64.b64encode(
+ open(os.path.join(FPATH, "assets/logo.png"), "rb").read()
+ )
+ img = bytes(
+ f"data:image/png;base64,{(logo_base64.decode('utf-8'))}",
+ encoding="utf-8",
+ )
+ ui.image(img.decode("utf-8"))
+ ui.icon("settings").tooltip("Settings").on("click", lambda: settings(dark))
+ ui.icon("delete").on("click", lambda: clear_db(log=logger)).tooltip(
+ "Clear all recorded data"
)
- img = bytes(
- f"data:image/png;base64,{(logo_base64.decode('utf-8'))}",
- encoding="utf-8",
+ ui.icon("upload").tooltip("Export Data").on("click", lambda: on_export(SERVER))
+ ui.icon("download").tooltip("Import Data").on(
+ "click", lambda: select_import(on_import)
+ )
+ ui.icon("share").tooltip("Share").on(
+ "click", lambda: (_ for _ in ()).throw(Exception(NotImplementedError))
)
- ui.image(img.decode("utf-8"))
- ui.icon("settings").tooltip("Settings").on("click", lambda: settings(dark))
- ui.icon("delete").on("click", lambda: clear_db(log=logger)).tooltip(
- "Clear all recorded data"
- )
- ui.icon("upload").tooltip("Export Data").on("click", lambda: on_export(SERVER))
- ui.icon("download").tooltip("Import Data").on(
- "click", lambda: select_import(on_import)
- )
- ui.icon("share").tooltip("Share").on(
- "click", lambda: (_ for _ in ()).throw(Exception(NotImplementedError))
- )
- with ui.splitter(value=20) as splitter:
- splitter.classes("w-full h-full")
- with splitter.before:
- with ui.column().classes("w-full h-full"):
- record_button = (
- ui.icon("radio_button_checked", size="64px")
- .on(
- "click",
- lambda: recording_prompt(OPTIONS, record_button),
+ with ui.splitter(value=20) as splitter:
+ splitter.classes("w-full h-full")
+ with splitter.before:
+ with ui.column().classes("w-full h-full"):
+ record_button = (
+ ui.icon("radio_button_checked", size="64px")
+ .on(
+ "click",
+ lambda: recording_prompt(OPTIONS, record_button),
+ )
+ .tooltip("Record a new replay / Stop recording")
)
- .tooltip("Record a new replay / Stop recording")
- )
- ui.icon("visibility", size="64px").on("click", visualize.main).tooltip(
- "Visualize the latest replay"
- )
-
- ui.icon("play_arrow", size="64px").on(
- "click",
- lambda: replay.replay("NaiveReplayStrategy"),
- ).tooltip("Play the latest replay")
- with splitter.after:
- logger = Console()
- logger.log.style("height: 250px;, width: 300px;")
+ ui.icon("visibility", size="64px").on(
+ "click", partial(Popen, ["python", "-m", "openadapt.visualize"])
+ ).tooltip("Visualize the latest replay")
- splitter.enabled = False
+ ui.icon("play_arrow", size="64px").on(
+ "click",
+ lambda: replay.replay("NaiveReplayStrategy"),
+ ).tooltip("Play the latest replay")
+ with splitter.after:
+ logger = Console()
+ logger.log.style("height: 250px;, width: 300px;")
+ splitter.enabled = False
-def start(fullscreen: bool = False) -> None:
- """Start the OpenAdapt application."""
ui.run(
title="OpenAdapt Client",
native=True,
diff --git a/openadapt/app/tray.py b/openadapt/app/tray.py
index 34d63bc3e..90ac5eb3f 100644
--- a/openadapt/app/tray.py
+++ b/openadapt/app/tray.py
@@ -2,11 +2,13 @@
usage: `python -m openadapt.app.tray` or `poetry run app`
"""
+
from functools import partial
-from threading import Thread
+from subprocess import Popen
import os
import sys
+from loguru import logger
from notifypy import Notify
from PySide6.QtCore import QTimer
from PySide6.QtGui import QAction, QIcon
@@ -18,7 +20,6 @@
from openadapt.extensions.thread import Thread as oaThread
from openadapt.models import Recording
from openadapt.replay import replay
-from openadapt.visualize import main as visualize
# hide dock icon on macos
if sys.platform == "darwin":
@@ -78,6 +79,8 @@ def __init__(self) -> None:
self.timer.timeout.connect(self.update_tray_icon)
self.timer.start()
+ self.visualize_proc = None
+
Notify("Status", "OpenAdapt is running in the background.", "OpenAdapt").send()
def update_tray_icon(self) -> None:
@@ -117,11 +120,16 @@ def _visualize(self, recording: Recording) -> None:
recording (Recording): The recording to visualize.
"""
Notify("Status", "Starting visualization...", "OpenAdapt").send()
- vthread = oaThread(target=visualize, args=(recording,))
- vthread.run()
- if vthread.join():
- Notify("Status", "Visualization finished", "OpenAdapt").send()
- else:
+ try:
+ if self.visualize_proc is not None:
+ self.visualize_proc.kill()
+ self.visualize_proc = Popen(
+ f"python -m openadapt.visualize --timestamp {recording.timestamp}",
+ shell=True,
+ )
+
+ except Exception as e:
+ logger.error(e)
Notify("Status", "Visualization failed", "OpenAdapt").send()
def _replay(self, recording: Recording) -> None:
@@ -163,7 +171,7 @@ def populate_menu(self, menu: QMenu, action: QAction, action_type: str) -> None:
def show_app(self) -> None:
"""Show the main application window."""
if self.app_thread is None or not self.app_thread.is_alive():
- self.app_thread = Thread(target=start, daemon=True, args=(True,))
+ self.app_thread = oaThread(target=start, daemon=True, args=(True,))
self.app_thread.start()
def run(self) -> None:
diff --git a/openadapt/config.py b/openadapt/config.py
index 9aab3fa92..5c424c1c9 100644
--- a/openadapt/config.py
+++ b/openadapt/config.py
@@ -88,6 +88,13 @@
"children",
],
"PLOT_PERFORMANCE": True,
+ # VISUALIZATION CONFIGURATIONS
+ "VISUALIZE_DARK_MODE": False,
+ "VISUALIZE_RUN_NATIVELY": True,
+ "VISUALIZE_DENSE_TREES": True,
+ "VISUALIZE_ANIMATIONS": True,
+ "VISUALIZE_EXPAND_ALL": False, # not recommended for large trees
+ "VISUALIZE_MAX_TABLE_CHILDREN": 10,
# Calculate and save the difference between 2 neighboring screenshots
"SAVE_SCREENSHOT_DIFF": False,
"SPACY_MODEL_NAME": "en_core_web_trf",
@@ -132,6 +139,8 @@ def getenv_fallback(var_name: str) -> str:
"0",
):
rval = rval.lower() == "true" or rval == "1"
+ if type(rval) is str and rval.isnumeric():
+ rval = int(rval)
if rval is None:
raise ValueError(f"{var_name=} not defined")
return rval
diff --git a/openadapt/deprecated/__init__.py b/openadapt/deprecated/__init__.py
new file mode 100644
index 000000000..f4f6adfcf
--- /dev/null
+++ b/openadapt/deprecated/__init__.py
@@ -0,0 +1,4 @@
+"""Deprecated modules.
+
+Module: __init__.py
+"""
diff --git a/openadapt/deprecated/visualize.py b/openadapt/deprecated/visualize.py
new file mode 100644
index 000000000..bad2753ef
--- /dev/null
+++ b/openadapt/deprecated/visualize.py
@@ -0,0 +1,336 @@
+"""Implements visualization utilities for OpenAdapt."""
+
+from pprint import pformat
+from threading import Timer
+import html
+import os
+import string
+
+from bokeh.io import output_file, show
+from bokeh.layouts import layout, row
+from bokeh.models.widgets import Div
+from loguru import logger
+from tqdm import tqdm
+
+from openadapt import config
+from openadapt.crud import get_latest_recording
+from openadapt.events import get_events
+from openadapt.models import Recording
+from openadapt.privacy.providers.presidio import PresidioScrubbingProvider
+from openadapt.utils import (
+ EMPTY,
+ configure_logging,
+ display_event,
+ evenly_spaced,
+ image2utf8,
+ row2dict,
+ rows2dicts,
+)
+
+SCRUB = config.SCRUB_ENABLED
+if SCRUB:
+ scrub = PresidioScrubbingProvider()
+
+LOG_LEVEL = "INFO"
+MAX_EVENTS = None
+MAX_TABLE_CHILDREN = 5
+MAX_TABLE_STR_LEN = 1024
+PROCESS_EVENTS = True
+IMG_WIDTH_PCT = 60
+CSS = string.Template("""
+ table {
+ outline: 1px solid black;
+ }
+ table th {
+ vertical-align: top;
+ }
+ .screenshot img {
+ display: none;
+ width: ${IMG_WIDTH_PCT}vw;
+ }
+ .screenshot img:nth-child(1) {
+ display: block;
+ }
+
+ .screenshot:hover img:nth-child(1) {
+ display: none;
+ }
+ .screenshot:hover img:nth-child(2) {
+ display: block;
+ }
+ .screenshot:hover img:nth-child(3) {
+ display: none;
+ }
+
+ .screenshot:active img:nth-child(1) {
+ display: none;
+ }
+ .screenshot:active img:nth-child(2) {
+ display: none;
+ }
+ .screenshot:active img:nth-child(3) {
+ display: block;
+ }
+""").substitute(
+ IMG_WIDTH_PCT=IMG_WIDTH_PCT,
+)
+
+
+def recursive_len(lst: list, key: str) -> int:
+ """Calculate the recursive length of a list based on a key.
+
+ Args:
+ lst (list): The list to calculate the length of.
+ key: The key to access the sublists.
+
+ Returns:
+ int: The recursive length of the list.
+ """
+ try:
+ _len = len(lst)
+ except TypeError:
+ return 0
+ for obj in lst:
+ try:
+ _len += recursive_len(obj.get(key), key)
+ except AttributeError:
+ continue
+ return _len
+
+
+def format_key(key: str, value: list) -> str:
+ """Format a key and value for display.
+
+ Args:
+ key: The key to format.
+ value: The value associated with the key.
+
+ Returns:
+ str: The formatted key and value.
+ """
+ if isinstance(value, list):
+ return f"{key} ({len(value)}; {recursive_len(value, key)})"
+ else:
+ return key
+
+
+def indicate_missing(some: list, every: list, indicator: str) -> list:
+ """Indicate missing elements in a list.
+
+ Args:
+ some (list): The list with potentially missing elements.
+ every (list): The reference list with all elements.
+ indicator (str): The indicator to use for missing elements.
+
+ Returns:
+ list: The list with indicators for missing elements.
+ """
+ rval = []
+ some_idx = 0
+ every_idx = 0
+ while some_idx < len(some):
+ skipped = False
+ while some[some_idx] != every[every_idx]:
+ every_idx += 1
+ skipped = True
+ if skipped:
+ rval.append(indicator)
+ rval.append(some[some_idx])
+ some_idx += 1
+ every_idx += 1
+ return rval
+
+
+def dict2html(
+ obj: dict,
+ max_children: int = MAX_TABLE_CHILDREN,
+ max_len: int = MAX_TABLE_STR_LEN,
+) -> str:
+ """Convert a dictionary to an HTML representation.
+
+ Args:
+ obj (dict): The dictionary to convert.
+ max_children (int): The maximum number of child elements to display in a table.
+ max_len (int): The maximum length of a string value in the HTML representation.
+
+ Returns:
+ str: The HTML representation of the dictionary.
+ """
+ if isinstance(obj, list):
+ children = [dict2html(value, max_children) for value in obj]
+ if max_children is not None and len(children) > max_children:
+ all_children = children
+ children = evenly_spaced(children, max_children)
+ children = indicate_missing(children, all_children, "...")
+ html_str = "\n".join(children)
+ elif isinstance(obj, dict):
+ rows_html = "\n".join([f"""
+
+ {format_key(key, value)} |
+ {dict2html(value, max_children)} |
+
+ """ for key, value in obj.items() if value not in EMPTY])
+ html_str = f""
+ else:
+ html_str = html.escape(str(obj))
+ if len(html_str) > max_len:
+ n = max_len // 2
+ head = html_str[:n]
+ tail = html_str[-n:]
+ snipped = html_str[n:-n]
+ middle = f"
...(snipped {len(snipped):,})...
"
+ html_str = head + middle + tail
+ return html_str
+
+
+@logger.catch
+def main(recording: Recording = None) -> bool:
+ """Visualize a recording.
+
+ Args:
+ recording (Recording, optional): The recording to visualize.
+
+ Returns:
+ bool: True if visualization was successful, None otherwise.
+ """
+ configure_logging(logger, LOG_LEVEL)
+
+ if recording is None:
+ recording = get_latest_recording()
+ if SCRUB:
+ scrub.scrub_text(recording.task_description)
+ logger.debug(f"{recording=}")
+
+ meta = {}
+ action_events = get_events(recording, process=PROCESS_EVENTS, meta=meta)
+ event_dicts = rows2dicts(action_events)
+
+ if SCRUB:
+ event_dicts = scrub.scrub_list_dicts(event_dicts)
+ logger.info(f"event_dicts=\n{pformat(event_dicts)}")
+
+ recording_dict = row2dict(recording)
+ if SCRUB:
+ recording_dict = scrub.scrub_dict(recording_dict)
+
+ rows = [
+ row(
+ Div(
+ text=f"",
+ ),
+ ),
+ row(
+ Div(
+ text=f"{dict2html(recording_dict)}",
+ ),
+ ),
+ row(
+ Div(
+ text=f"{dict2html(meta)}",
+ width_policy="max",
+ ),
+ ),
+ ]
+ logger.info(f"{len(action_events)=}")
+
+ num_events = (
+ min(MAX_EVENTS, len(action_events))
+ if MAX_EVENTS is not None
+ else len(action_events)
+ )
+ with tqdm(
+ total=num_events,
+ desc="Preparing HTML",
+ unit="event",
+ colour="green",
+ dynamic_ncols=True,
+ ) as progress:
+ for idx, action_event in enumerate(action_events):
+ if idx == MAX_EVENTS:
+ break
+ image = display_event(action_event)
+ diff = display_event(action_event, diff=True)
+ mask = action_event.screenshot.diff_mask
+
+ if SCRUB:
+ image = scrub.scrub_image(image)
+ diff = scrub.scrub_image(diff)
+ mask = scrub.scrub_image(mask)
+
+ image_utf8 = image2utf8(image)
+ diff_utf8 = image2utf8(diff)
+ mask_utf8 = image2utf8(mask)
+ width, height = image.size
+
+ action_event_dict = row2dict(action_event)
+ window_event_dict = row2dict(action_event.window_event)
+
+ if SCRUB:
+ action_event_dict = scrub.scrub_dict(action_event_dict)
+ window_event_dict = scrub.scrub_dict(window_event_dict)
+
+ rows.append(
+ [
+ row(
+ Div(
+ text=f"""
+
+
+ {dict2html(window_event_dict , None)}
+
+ """,
+ ),
+ Div(text=f"""
+
+ {dict2html(action_event_dict)}
+
+ """),
+ ),
+ ]
+ )
+
+ progress.update()
+
+ progress.close()
+
+ title = f"recording-{recording.id}"
+ fname_out = f"recording-{recording.id}.html"
+ logger.info(f"{fname_out=}")
+ output_file(fname_out, title=title)
+
+ result = show( # noqa: F841
+ layout(
+ rows,
+ )
+ )
+
+ def cleanup() -> None:
+ os.remove(fname_out)
+ removed = not os.path.exists(fname_out)
+ logger.info(f"{removed=}")
+
+ Timer(1, cleanup).start()
+ return True
+
+
+if __name__ == "__main__":
+ main()
diff --git a/openadapt/extensions/thread.py b/openadapt/extensions/thread.py
index fba3090bf..872d986c1 100644
--- a/openadapt/extensions/thread.py
+++ b/openadapt/extensions/thread.py
@@ -8,9 +8,9 @@
class Thread(Thread):
"""Thread class that allows for the return value of a thread to be accessed."""
- def __init__(self, target: callable, args: tuple | list) -> None:
+ def __init__(self, daemon: bool, target: callable, args: tuple | list) -> None:
"""Initialize the Thread class."""
- super().__init__(target=target, args=args)
+ super().__init__(target=target, daemon=daemon, args=args)
self._return = None
def run(self) -> None:
diff --git a/openadapt/utils.py b/openadapt/utils.py
index 49a0f0cdf..7b936991b 100644
--- a/openadapt/utils.py
+++ b/openadapt/utils.py
@@ -655,17 +655,30 @@ def get_strategy_class_by_name() -> dict:
return class_by_name
-def plot_performance(recording_timestamp: float = None) -> None:
+def plot_performance(
+ recording_timestamp: float = None,
+ view_file: bool = True,
+ save_file: bool = True,
+ dark_mode: bool = False,
+) -> str:
"""Plot the performance of the event processing and writing.
Args:
- recording_timestamp (float): The timestamp of the recording
- (defaults to latest).
+ recording_timestamp: The timestamp of the recording (defaults to latest)
+ view_file: Whether to view the file after saving it.
+ save_file: Whether to save the file.
+ dark_mode: Whether to use dark mode.
+
+ Returns:
+ str: a base64-encoded image of the plot, if not viewing the file
"""
type_to_proc_times = defaultdict(list)
type_to_timestamps = defaultdict(list)
event_types = set()
+ if dark_mode:
+ plt.style.use("dark_background")
+
# avoid circular import
from openadapt import crud
@@ -718,13 +731,26 @@ def plot_performance(recording_timestamp: float = None) -> None:
ax.set_title(f"{recording_timestamp=}")
# TODO: add PROC_WRITE_BY_EVENT_TYPE
- fname_parts = ["performance", str(recording_timestamp)]
- fname = "-".join(fname_parts) + ".png"
- os.makedirs(config.DIRNAME_PERFORMANCE_PLOTS, exist_ok=True)
- fpath = os.path.join(config.DIRNAME_PERFORMANCE_PLOTS, fname)
- logger.info(f"{fpath=}")
- plt.savefig(fpath)
- os.system(f"open {fpath}")
+ if save_file:
+ fname_parts = ["performance", str(recording_timestamp)]
+ fname = "-".join(fname_parts) + ".png"
+ os.makedirs(config.DIRNAME_PERFORMANCE_PLOTS, exist_ok=True)
+ fpath = os.path.join(config.DIRNAME_PERFORMANCE_PLOTS, fname)
+ logger.info(f"{fpath=}")
+ plt.savefig(fpath)
+ if view_file:
+ os.system(f"open {fpath}")
+ else:
+ plt.savefig(BytesIO(), format="png") # save fig to void
+ if view_file:
+ plt.show()
+ else:
+ plt.close()
+ return image2utf8(
+ Image.frombytes(
+ "RGB", fig.canvas.get_width_height(), fig.canvas.tostring_rgb()
+ )
+ )
def strip_element_state(action_event: ActionEvent) -> ActionEvent:
diff --git a/openadapt/visualize.py b/openadapt/visualize.py
index bad2753ef..653fb1b01 100644
--- a/openadapt/visualize.py
+++ b/openadapt/visualize.py
@@ -1,202 +1,148 @@
"""Implements visualization utilities for OpenAdapt."""
+from base64 import b64encode
+from functools import partial
+from os import path, sep
from pprint import pformat
-from threading import Timer
-import html
-import os
-import string
-
-from bokeh.io import output_file, show
-from bokeh.layouts import layout, row
-from bokeh.models.widgets import Div
+
from loguru import logger
+from nicegui import events, ui
+from notifypy import Notify
from tqdm import tqdm
+import click
from openadapt import config
-from openadapt.crud import get_latest_recording
+from openadapt.crud import get_latest_recording, get_recording
from openadapt.events import get_events
-from openadapt.models import Recording
-from openadapt.privacy.providers.presidio import PresidioScrubbingProvider
from openadapt.utils import (
EMPTY,
configure_logging,
display_event,
- evenly_spaced,
image2utf8,
+ plot_performance,
row2dict,
rows2dicts,
)
SCRUB = config.SCRUB_ENABLED
+
if SCRUB:
+ # too many warnings from scrubbing
+ __import__("warnings").filterwarnings("ignore", category=DeprecationWarning)
+ from openadapt.privacy.providers.presidio import PresidioScrubbingProvider
+
scrub = PresidioScrubbingProvider()
+
LOG_LEVEL = "INFO"
MAX_EVENTS = None
-MAX_TABLE_CHILDREN = 5
-MAX_TABLE_STR_LEN = 1024
PROCESS_EVENTS = True
-IMG_WIDTH_PCT = 60
-CSS = string.Template("""
- table {
- outline: 1px solid black;
- }
- table th {
- vertical-align: top;
- }
- .screenshot img {
- display: none;
- width: ${IMG_WIDTH_PCT}vw;
- }
- .screenshot img:nth-child(1) {
- display: block;
- }
-
- .screenshot:hover img:nth-child(1) {
- display: none;
- }
- .screenshot:hover img:nth-child(2) {
- display: block;
- }
- .screenshot:hover img:nth-child(3) {
- display: none;
- }
-
- .screenshot:active img:nth-child(1) {
- display: none;
- }
- .screenshot:active img:nth-child(2) {
- display: none;
- }
- .screenshot:active img:nth-child(3) {
- display: block;
- }
-""").substitute(
- IMG_WIDTH_PCT=IMG_WIDTH_PCT,
-)
+
+performance_plot_img: ui.interactive_image = None
-def recursive_len(lst: list, key: str) -> int:
- """Calculate the recursive length of a list based on a key.
+def create_tree(
+ tree_dict: dict, max_children: str = config.VISUALIZE_MAX_TABLE_CHILDREN
+) -> list[dict]:
+ """Recursively creates a tree from a dictionary.
Args:
- lst (list): The list to calculate the length of.
- key: The key to access the sublists.
+ tree_dict (dict): The dictionary to create a tree from.
+ max_children (str, optional): The maximum number of children to display.
+ Defaults to MAX_TABLE_CHILDREN.
Returns:
- int: The recursive length of the list.
+ list[dict]: Data for a Quasar Tree.
"""
- try:
- _len = len(lst)
- except TypeError:
- return 0
- for obj in lst:
- try:
- _len += recursive_len(obj.get(key), key)
- except AttributeError:
+ tree_data = []
+ for key, value in tree_dict.items():
+ if value in EMPTY:
continue
- return _len
-
-
-def format_key(key: str, value: list) -> str:
- """Format a key and value for display.
+ node = {
+ "id": (
+ str(key)
+ + f"{(': ' + str(value)) if not isinstance(value, (dict, list)) else ''}" # noqa
+ )
+ }
+ if isinstance(value, dict):
+ node["children"] = create_tree(value)
+ elif isinstance(value, list):
+ if max_children is not None and len(value) > max_children:
+ node["children"] = create_tree(
+ {i: v for i, v in enumerate(value[:max_children])}
+ )
+ node["children"].append({"id": "..."})
+ else:
+ node["children"] = create_tree({i: v for i, v in enumerate(value)})
+ tree_data.append(node)
+ return tree_data
+
+
+def set_tree_props(tree: ui.tree) -> None:
+ """Sets properties for a UI tree based on values from config.
Args:
- key: The key to format.
- value: The value associated with the key.
-
- Returns:
- str: The formatted key and value.
+ tree (ui.tree): A Quasar Tree.
"""
- if isinstance(value, list):
- return f"{key} ({len(value)}; {recursive_len(value, key)})"
- else:
- return key
+ tree._props["dense"] = config.VISUALIZE_DENSE_TREES
+ tree._props["no-transition"] = not config.VISUALIZE_ANIMATIONS
+ tree._props["default-expand-all"] = config.VISUALIZE_EXPAND_ALL
+ tree._props["filter"] = ""
-def indicate_missing(some: list, every: list, indicator: str) -> list:
- """Indicate missing elements in a list.
+def set_filter(
+ text: str,
+ tree: ui.tree,
+) -> None:
+ """Sets filter for UI trees.
Args:
- some (list): The list with potentially missing elements.
- every (list): The reference list with all elements.
- indicator (str): The indicator to use for missing elements.
-
- Returns:
- list: The list with indicators for missing elements.
+ tree (ui.tree): A Quasar Tree.
+ text (str): The text to filter by.
"""
- rval = []
- some_idx = 0
- every_idx = 0
- while some_idx < len(some):
- skipped = False
- while some[some_idx] != every[every_idx]:
- every_idx += 1
- skipped = True
- if skipped:
- rval.append(indicator)
- rval.append(some[some_idx])
- some_idx += 1
- every_idx += 1
- return rval
-
-
-def dict2html(
- obj: dict,
- max_children: int = MAX_TABLE_CHILDREN,
- max_len: int = MAX_TABLE_STR_LEN,
-) -> str:
- """Convert a dictionary to an HTML representation.
+ tree._props["filter"] = text
+ tree.update()
- Args:
- obj (dict): The dictionary to convert.
- max_children (int): The maximum number of child elements to display in a table.
- max_len (int): The maximum length of a string value in the HTML representation.
- Returns:
- str: The HTML representation of the dictionary.
+def toggle_dark_mode(
+ ui_dark: ui.dark_mode, plots: tuple[str], curr_logo: ui.image, images: tuple[str]
+) -> None:
+ """Handles dark mode toggle.
+
+ Args:
+ ui_dark (ui.dark_mode): The dark mode switch.
+ plots (tuple[str]): The performance plots.
+ curr_logo (ui.image): The current logo.
+ images (tuple[str]): The light and dark mode logos (decoded)
"""
- if isinstance(obj, list):
- children = [dict2html(value, max_children) for value in obj]
- if max_children is not None and len(children) > max_children:
- all_children = children
- children = evenly_spaced(children, max_children)
- children = indicate_missing(children, all_children, "...")
- html_str = "\n".join(children)
- elif isinstance(obj, dict):
- rows_html = "\n".join([f"""
-
- {format_key(key, value)} |
- {dict2html(value, max_children)} |
-
- """ for key, value in obj.items() if value not in EMPTY])
- html_str = f""
- else:
- html_str = html.escape(str(obj))
- if len(html_str) > max_len:
- n = max_len // 2
- head = html_str[:n]
- tail = html_str[-n:]
- snipped = html_str[n:-n]
- middle = f"
...(snipped {len(snipped):,})...
"
- html_str = head + middle + tail
- return html_str
+ global performance_plot_img
+ ui_dark.toggle()
+ ui_dark.update()
+ config.persist_env("VISUALIZE_DARK_MODE", ui_dark.value)
+ curr_logo.source = images[int(ui_dark.value)]
+ curr_logo.update()
+ performance_plot_img.source = plots[int(ui_dark.value)]
+ performance_plot_img.update()
@logger.catch
-def main(recording: Recording = None) -> bool:
- """Visualize a recording.
-
- Args:
- recording (Recording, optional): The recording to visualize.
-
- Returns:
- bool: True if visualization was successful, None otherwise.
- """
+@click.command()
+@click.option(
+ "--timestamp",
+ type=str,
+ help="The timestamp of the recording to visualize.",
+)
+def main(timestamp: str, notify: bool = True) -> None:
+ """Visualize a recording."""
configure_logging(logger, LOG_LEVEL)
- if recording is None:
+ ui_dark = ui.dark_mode(config.VISUALIZE_DARK_MODE)
+
+ if timestamp is None:
recording = get_latest_recording()
+ else:
+ recording = get_recording(timestamp)
+
if SCRUB:
scrub.scrub_text(recording.task_description)
logger.debug(f"{recording=}")
@@ -210,27 +156,109 @@ def main(recording: Recording = None) -> bool:
logger.info(f"event_dicts=\n{pformat(event_dicts)}")
recording_dict = row2dict(recording)
+
if SCRUB:
recording_dict = scrub.scrub_dict(recording_dict)
- rows = [
- row(
- Div(
- text=f"",
- ),
- ),
- row(
- Div(
- text=f"{dict2html(recording_dict)}",
- ),
- ),
- row(
- Div(
- text=f"{dict2html(meta)}",
- width_policy="max",
- ),
- ),
+ # setup tables for recording / metadata
+ recording_column = [
+ (
+ {
+ "name": key,
+ "field": key,
+ "label": key,
+ "sortable": False,
+ "required": False,
+ "align": "left",
+ }
+ )
+ for key in recording_dict.keys()
+ ]
+
+ meta_col = [
+ {
+ "name": key,
+ "field": key,
+ "label": key,
+ "sortable": False,
+ "required": False,
+ "align": "left",
+ }
+ for key in meta.keys()
]
+
+ plots = (
+ plot_performance(recording.timestamp, save_file=False, view_file=False),
+ plot_performance(
+ recording.timestamp, save_file=False, view_file=False, dark_mode=True
+ ),
+ )
+
+ with ui.row():
+ with ui.avatar(color="auto", size=128):
+ images = ()
+
+ # generate base64 encoded images for light and dark mode
+ for i in range(2):
+ fp = f"{path.dirname(__file__)}{sep}app{sep}assets{sep}logo"
+ logo_base64 = b64encode(
+ open(
+ f"{fp}{'_inverted' if i > 0 else ''}.png",
+ "rb",
+ ).read()
+ )
+ images += (
+ bytes(
+ f"data:image/png;base64,{(logo_base64.decode('utf-8'))}",
+ encoding="utf-8",
+ ).decode("utf-8"),
+ )
+ curr_logo = ui.image(images[int(ui_dark.value)])
+ ui.switch(
+ text="Dark Mode",
+ value=ui_dark.value,
+ on_change=partial(toggle_dark_mode, ui_dark, plots, curr_logo, images),
+ )
+
+ # create splitter with recording info on left and performance plot on right
+ with ui.splitter(value=20).style("flex-wrap: nowrap;") as splitter:
+ splitter._props["limits"] = [20, 80]
+
+ # TODO: find a way to set "overflow: hidden;" for the splitter
+ with splitter.before:
+ ui.table(rows=[meta], columns=meta_col).style("min-width: 50em;")._props[
+ "grid"
+ ] = True
+ with splitter.after:
+ global performance_plot_img
+ performance_plot_img = ui.interactive_image(
+ source=plots[int(ui_dark.value)]
+ )
+ with performance_plot_img:
+ # ui.button(
+ # on_click=lambda: plot_performance(
+ # recording.timestamp, view_file=True, save_file=False
+ # ),
+ # icon="visibility",
+ # ).props("flat fab").tooltip("View")
+
+ ui.button(
+ on_click=lambda: plot_performance(
+ recording.timestamp,
+ save_file=True,
+ view_file=False,
+ dark_mode=ui_dark.value,
+ ),
+ icon="save",
+ ).props("flat fab").tooltip("Save as PNG")
+
+ ui.table(rows=[recording_dict], columns=recording_column)
+
+ interactive_images = []
+ action_event_trees = []
+ window_event_trees = []
+ text_inputs = []
+
logger.info(f"{len(action_events)=}")
num_events = (
@@ -238,9 +266,32 @@ def main(recording: Recording = None) -> bool:
if MAX_EVENTS is not None
else len(action_events)
)
+
+ # global search
+ def on_change_closure(e: events.ValueChangeEventArguments) -> None:
+ for tree in range(len(action_event_trees)):
+ set_filter(
+ e.value,
+ action_event_trees[tree],
+ )
+ set_filter(
+ e.value,
+ window_event_trees[tree],
+ )
+
+ text_inputs.append(
+ ui.input(
+ label="search all",
+ placeholder="filter all",
+ on_change=partial(on_change_closure),
+ ).tooltip(
+ "this will search all trees, but can be overridden by individual filters"
+ )
+ )
+
with tqdm(
total=num_events,
- desc="Preparing HTML",
+ desc="Generating Visualization" if not SCRUB else "Scrubbing Visualization",
unit="event",
colour="green",
dynamic_ncols=True,
@@ -248,18 +299,19 @@ def main(recording: Recording = None) -> bool:
for idx, action_event in enumerate(action_events):
if idx == MAX_EVENTS:
break
+
image = display_event(action_event)
- diff = display_event(action_event, diff=True)
- mask = action_event.screenshot.diff_mask
+ # diff = display_event(action_event, diff=True)
+ # mask = action_event.screenshot.diff_mask
if SCRUB:
image = scrub.scrub_image(image)
- diff = scrub.scrub_image(diff)
- mask = scrub.scrub_image(mask)
+ # diff = scrub.scrub_image(diff)
+ # mask = scrub.scrub_image(mask)
image_utf8 = image2utf8(image)
- diff_utf8 = image2utf8(diff)
- mask_utf8 = image2utf8(mask)
+ # diff_utf8 = image2utf8(diff)
+ # mask_utf8 = image2utf8(mask)
width, height = image.size
action_event_dict = row2dict(action_event)
@@ -269,68 +321,101 @@ def main(recording: Recording = None) -> bool:
action_event_dict = scrub.scrub_dict(action_event_dict)
window_event_dict = scrub.scrub_dict(window_event_dict)
- rows.append(
- [
- row(
- Div(
- text=f"""
-
-
- {dict2html(window_event_dict , None)}
-
- """,
- ),
- Div(text=f"""
-
- {dict2html(action_event_dict)}
-
- """),
- ),
- ]
- )
+ with ui.column():
+ with ui.row():
+ interactive_images.append(
+ ui.interactive_image(
+ source=image_utf8,
+ ).classes("drop-shadow-md rounded")
+ )
+ with ui.splitter(value=60) as splitter:
+ splitter.classes("w-full h-full")
+ with splitter.after:
+ ui.label("action_event_dict").style("font-weight: bold;")
+
+ def on_change_closure(
+ e: events.ValueChangeEventArguments, idx: int
+ ) -> None:
+ return set_filter(
+ e.value,
+ action_event_trees[idx],
+ )
+
+ text_inputs.append(
+ ui.input(
+ label="search",
+ placeholder="filter",
+ on_change=partial(
+ on_change_closure,
+ idx=idx,
+ ),
+ )
+ )
+ ui.html("
")
+ action_event_tree = create_tree(action_event_dict)
+ action_event_trees.append(
+ ui.tree(
+ action_event_tree,
+ label_key="id",
+ # on_select=lambda e: ui.notify(e.value),
+ )
+ )
+ set_tree_props(action_event_trees[idx])
+ with splitter.before:
+ ui.label("window_event_dict").style("font-weight: bold;")
+
+ def on_change_closure(
+ e: events.ValueChangeEventArguments, idx: int
+ ) -> None:
+ return set_filter(
+ e.value,
+ window_event_trees[idx],
+ )
+
+ text_inputs.append(
+ ui.input(
+ label="search",
+ placeholder="filter",
+ on_change=partial(
+ on_change_closure,
+ idx=idx,
+ ),
+ )
+ )
+ ui.html("
")
+ window_event_tree = create_tree(window_event_dict, None)
+
+ window_event_trees.append(
+ ui.tree(
+ window_event_tree,
+ label_key="id",
+ # on_select=lambda e: ui.notify(e.value),
+ )
+ )
+
+ set_tree_props(window_event_trees[idx])
progress.update()
progress.close()
- title = f"recording-{recording.id}"
- fname_out = f"recording-{recording.id}.html"
- logger.info(f"{fname_out=}")
- output_file(fname_out, title=title)
-
- result = show( # noqa: F841
- layout(
- rows,
- )
+ if notify:
+ Notify("Status", "Visualization finished", "OpenAdapt").send()
+ if not config.VISUALIZE_RUN_NATIVELY:
+ Notify(
+ "Status",
+ "Press Ctrl+C in the terminal to stop the visualization",
+ "OpenAdapt",
+ ).send()
+
+ ui.run(
+ reload=False,
+ title=f"OpenAdapt: recording-{recording.id}",
+ favicon="📊",
+ native=config.VISUALIZE_RUN_NATIVELY,
+ fullscreen=config.VISUALIZE_RUN_NATIVELY,
)
- def cleanup() -> None:
- os.remove(fname_out)
- removed = not os.path.exists(fname_out)
- logger.info(f"{removed=}")
-
- Timer(1, cleanup).start()
- return True
-
if __name__ == "__main__":
main()
diff --git a/poetry.lock b/poetry.lock
index c3ff6abc7..00a1c87d7 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1024,18 +1024,21 @@ test = ["pytest"]
[[package]]
name = "filelock"
-version = "3.12.2"
+version = "3.12.3"
description = "A platform independent file lock."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"},
- {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"},
+ {file = "filelock-3.12.3-py3-none-any.whl", hash = "sha256:f067e40ccc40f2b48395a80fcbd4728262fab54e232e090a4063ab804179efeb"},
+ {file = "filelock-3.12.3.tar.gz", hash = "sha256:0ecc1dd2ec4672a10c8550a8182f1bd0c0a5088470ecd5a125e45f49472fac3d"},
]
+[package.dependencies]
+typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.11\""}
+
[package.extras]
-docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
-testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"]
+docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"]
[[package]]
name = "fire"
@@ -1110,45 +1113,45 @@ files = [
[[package]]
name = "fonttools"
-version = "4.42.0"
+version = "4.42.1"
description = "Tools to manipulate font files"
optional = false
python-versions = ">=3.8"
files = [
- {file = "fonttools-4.42.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9c456d1f23deff64ffc8b5b098718e149279abdea4d8692dba69172fb6a0d597"},
- {file = "fonttools-4.42.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:150122ed93127a26bc3670ebab7e2add1e0983d30927733aec327ebf4255b072"},
- {file = "fonttools-4.42.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48e82d776d2e93f88ca56567509d102266e7ab2fb707a0326f032fe657335238"},
- {file = "fonttools-4.42.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58c1165f9b2662645de9b19a8c8bdd636b36294ccc07e1b0163856b74f10bafc"},
- {file = "fonttools-4.42.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2d6dc3fa91414ff4daa195c05f946e6a575bd214821e26d17ca50f74b35b0fe4"},
- {file = "fonttools-4.42.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fae4e801b774cc62cecf4a57b1eae4097903fced00c608d9e2bc8f84cd87b54a"},
- {file = "fonttools-4.42.0-cp310-cp310-win32.whl", hash = "sha256:b8600ae7dce6ec3ddfb201abb98c9d53abbf8064d7ac0c8a0d8925e722ccf2a0"},
- {file = "fonttools-4.42.0-cp310-cp310-win_amd64.whl", hash = "sha256:57b68eab183fafac7cd7d464a7bfa0fcd4edf6c67837d14fb09c1c20516cf20b"},
- {file = "fonttools-4.42.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0a1466713e54bdbf5521f2f73eebfe727a528905ff5ec63cda40961b4b1eea95"},
- {file = "fonttools-4.42.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3fb2a69870bfe143ec20b039a1c8009e149dd7780dd89554cc8a11f79e5de86b"},
- {file = "fonttools-4.42.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae881e484702efdb6cf756462622de81d4414c454edfd950b137e9a7352b3cb9"},
- {file = "fonttools-4.42.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27ec3246a088555629f9f0902f7412220c67340553ca91eb540cf247aacb1983"},
- {file = "fonttools-4.42.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8ece1886d12bb36c48c00b2031518877f41abae317e3a55620d38e307d799b7e"},
- {file = "fonttools-4.42.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:10dac980f2b975ef74532e2a94bb00e97a95b4595fb7f98db493c474d5f54d0e"},
- {file = "fonttools-4.42.0-cp311-cp311-win32.whl", hash = "sha256:83b98be5d291e08501bd4fc0c4e0f8e6e05b99f3924068b17c5c9972af6fff84"},
- {file = "fonttools-4.42.0-cp311-cp311-win_amd64.whl", hash = "sha256:e35bed436726194c5e6e094fdfb423fb7afaa0211199f9d245e59e11118c576c"},
- {file = "fonttools-4.42.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c36c904ce0322df01e590ba814d5d69e084e985d7e4c2869378671d79662a7d4"},
- {file = "fonttools-4.42.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d54e600a2bcfa5cdaa860237765c01804a03b08404d6affcd92942fa7315ffba"},
- {file = "fonttools-4.42.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01cfe02416b6d416c5c8d15e30315cbcd3e97d1b50d3b34b0ce59f742ef55258"},
- {file = "fonttools-4.42.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f81ed9065b4bd3f4f3ce8e4873cd6a6b3f4e92b1eddefde35d332c6f414acc3"},
- {file = "fonttools-4.42.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:685a4dd6cf31593b50d6d441feb7781a4a7ef61e19551463e14ed7c527b86f9f"},
- {file = "fonttools-4.42.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:329341ba3d86a36e482610db56b30705384cb23bd595eac8cbb045f627778e9d"},
- {file = "fonttools-4.42.0-cp38-cp38-win32.whl", hash = "sha256:4655c480a1a4d706152ff54f20e20cf7609084016f1df3851cce67cef768f40a"},
- {file = "fonttools-4.42.0-cp38-cp38-win_amd64.whl", hash = "sha256:6bd7e4777bff1dcb7c4eff4786998422770f3bfbef8be401c5332895517ba3fa"},
- {file = "fonttools-4.42.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a9b55d2a3b360e0c7fc5bd8badf1503ca1c11dd3a1cd20f2c26787ffa145a9c7"},
- {file = "fonttools-4.42.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0df8ef75ba5791e873c9eac2262196497525e3f07699a2576d3ab9ddf41cb619"},
- {file = "fonttools-4.42.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd2363ea7728496827658682d049ffb2e98525e2247ca64554864a8cc945568"},
- {file = "fonttools-4.42.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d40673b2e927f7cd0819c6f04489dfbeb337b4a7b10fc633c89bf4f34ecb9620"},
- {file = "fonttools-4.42.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c8bf88f9e3ce347c716921804ef3a8330cb128284eb6c0b6c4b3574f3c580023"},
- {file = "fonttools-4.42.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:703101eb0490fae32baf385385d47787b73d9ea55253df43b487c89ec767e0d7"},
- {file = "fonttools-4.42.0-cp39-cp39-win32.whl", hash = "sha256:f0290ea7f9945174bd4dfd66e96149037441eb2008f3649094f056201d99e293"},
- {file = "fonttools-4.42.0-cp39-cp39-win_amd64.whl", hash = "sha256:ae7df0ae9ee2f3f7676b0ff6f4ebe48ad0acaeeeaa0b6839d15dbf0709f2c5ef"},
- {file = "fonttools-4.42.0-py3-none-any.whl", hash = "sha256:dfe7fa7e607f7e8b58d0c32501a3a7cac148538300626d1b930082c90ae7f6bd"},
- {file = "fonttools-4.42.0.tar.gz", hash = "sha256:614b1283dca88effd20ee48160518e6de275ce9b5456a3134d5f235523fc5065"},
+ {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed1a13a27f59d1fc1920394a7f596792e9d546c9ca5a044419dca70c37815d7c"},
+ {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c9b1ce7a45978b821a06d375b83763b27a3a5e8a2e4570b3065abad240a18760"},
+ {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f720fa82a11c0f9042376fd509b5ed88dab7e3cd602eee63a1af08883b37342b"},
+ {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db55cbaea02a20b49fefbd8e9d62bd481aaabe1f2301dabc575acc6b358874fa"},
+ {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a35981d90feebeaef05e46e33e6b9e5b5e618504672ca9cd0ff96b171e4bfff"},
+ {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:68a02bbe020dc22ee0540e040117535f06df9358106d3775e8817d826047f3fd"},
+ {file = "fonttools-4.42.1-cp310-cp310-win32.whl", hash = "sha256:12a7c247d1b946829bfa2f331107a629ea77dc5391dfd34fdcd78efa61f354ca"},
+ {file = "fonttools-4.42.1-cp310-cp310-win_amd64.whl", hash = "sha256:a398bdadb055f8de69f62b0fc70625f7cbdab436bbb31eef5816e28cab083ee8"},
+ {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:689508b918332fb40ce117131633647731d098b1b10d092234aa959b4251add5"},
+ {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e36344e48af3e3bde867a1ca54f97c308735dd8697005c2d24a86054a114a71"},
+ {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19b7db825c8adee96fac0692e6e1ecd858cae9affb3b4812cdb9d934a898b29e"},
+ {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:113337c2d29665839b7d90b39f99b3cac731f72a0eda9306165a305c7c31d341"},
+ {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37983b6bdab42c501202500a2be3a572f50d4efe3237e0686ee9d5f794d76b35"},
+ {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6ed2662a3d9c832afa36405f8748c250be94ae5dfc5283d668308391f2102861"},
+ {file = "fonttools-4.42.1-cp311-cp311-win32.whl", hash = "sha256:179737095eb98332a2744e8f12037b2977f22948cf23ff96656928923ddf560a"},
+ {file = "fonttools-4.42.1-cp311-cp311-win_amd64.whl", hash = "sha256:f2b82f46917d8722e6b5eafeefb4fb585d23babd15d8246c664cd88a5bddd19c"},
+ {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:62f481ac772fd68901573956231aea3e4b1ad87b9b1089a61613a91e2b50bb9b"},
+ {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2f806990160d1ce42d287aa419df3ffc42dfefe60d473695fb048355fe0c6a0"},
+ {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db372213d39fa33af667c2aa586a0c1235e88e9c850f5dd5c8e1f17515861868"},
+ {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d18fc642fd0ac29236ff88ecfccff229ec0386090a839dd3f1162e9a7944a40"},
+ {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8708b98c278012ad267ee8a7433baeb809948855e81922878118464b274c909d"},
+ {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c95b0724a6deea2c8c5d3222191783ced0a2f09bd6d33f93e563f6f1a4b3b3a4"},
+ {file = "fonttools-4.42.1-cp38-cp38-win32.whl", hash = "sha256:4aa79366e442dbca6e2c8595645a3a605d9eeabdb7a094d745ed6106816bef5d"},
+ {file = "fonttools-4.42.1-cp38-cp38-win_amd64.whl", hash = "sha256:acb47f6f8680de24c1ab65ebde39dd035768e2a9b571a07c7b8da95f6c8815fd"},
+ {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5fb289b7a815638a7613d46bcf324c9106804725b2bb8ad913c12b6958ffc4ec"},
+ {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:53eb5091ddc8b1199330bb7b4a8a2e7995ad5d43376cadce84523d8223ef3136"},
+ {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46a0ec8adbc6ff13494eb0c9c2e643b6f009ce7320cf640de106fb614e4d4360"},
+ {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cc7d685b8eeca7ae69dc6416833fbfea61660684b7089bca666067cb2937dcf"},
+ {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:be24fcb80493b2c94eae21df70017351851652a37de514de553435b256b2f249"},
+ {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:515607ec756d7865f23070682622c49d922901943697871fc292277cf1e71967"},
+ {file = "fonttools-4.42.1-cp39-cp39-win32.whl", hash = "sha256:0eb79a2da5eb6457a6f8ab904838454accc7d4cccdaff1fd2bd3a0679ea33d64"},
+ {file = "fonttools-4.42.1-cp39-cp39-win_amd64.whl", hash = "sha256:7286aed4ea271df9eab8d7a9b29e507094b51397812f7ce051ecd77915a6e26b"},
+ {file = "fonttools-4.42.1-py3-none-any.whl", hash = "sha256:9398f244e28e0596e2ee6024f808b06060109e33ed38dcc9bded452fd9bbb853"},
+ {file = "fonttools-4.42.1.tar.gz", hash = "sha256:c391cd5af88aacaf41dd7cfb96eeedfad297b5899a39e12f4c2c3706d0a3329d"},
]
[package.extras]
@@ -1378,6 +1381,27 @@ files = [
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
]
+[[package]]
+name = "httpcore"
+version = "0.17.3"
+description = "A minimal low-level HTTP client."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "httpcore-0.17.3-py3-none-any.whl", hash = "sha256:c2789b767ddddfa2a5782e3199b2b7f6894540b17b16ec26b2c4d8e103510b87"},
+ {file = "httpcore-0.17.3.tar.gz", hash = "sha256:a6f30213335e34c1ade7be6ec7c47f19f50c56db36abef1a9dfa3815b1cb3888"},
+]
+
+[package.dependencies]
+anyio = ">=3.0,<5.0"
+certifi = "*"
+h11 = ">=0.13,<0.15"
+sniffio = "==1.*"
+
+[package.extras]
+http2 = ["h2 (>=3,<5)"]
+socks = ["socksio (==1.*)"]
+
[[package]]
name = "httptools"
version = "0.6.0"
@@ -1425,6 +1449,29 @@ files = [
[package.extras]
test = ["Cython (>=0.29.24,<0.30.0)"]
+[[package]]
+name = "httpx"
+version = "0.24.1"
+description = "The next generation HTTP client."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "httpx-0.24.1-py3-none-any.whl", hash = "sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd"},
+ {file = "httpx-0.24.1.tar.gz", hash = "sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd"},
+]
+
+[package.dependencies]
+certifi = "*"
+httpcore = ">=0.15.0,<0.18.0"
+idna = "*"
+sniffio = "*"
+
+[package.extras]
+brotli = ["brotli", "brotlicffi"]
+cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
+http2 = ["h2 (>=3,<5)"]
+socks = ["socksio (==1.*)"]
+
[[package]]
name = "huggingface-hub"
version = "0.16.4"
@@ -1473,13 +1520,13 @@ pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_ve
[[package]]
name = "identify"
-version = "2.5.26"
+version = "2.5.27"
description = "File identification library for Python"
optional = false
python-versions = ">=3.8"
files = [
- {file = "identify-2.5.26-py2.py3-none-any.whl", hash = "sha256:c22a8ead0d4ca11f1edd6c9418c3220669b3b7533ada0a0ffa6cc0ef85cf9b54"},
- {file = "identify-2.5.26.tar.gz", hash = "sha256:7243800bce2f58404ed41b7c002e53d4d22bcf3ae1b7900c2d7aefd95394bf7f"},
+ {file = "identify-2.5.27-py2.py3-none-any.whl", hash = "sha256:fdb527b2dfe24602809b2201e033c2a113d7bdf716db3ca8e3243f735dcecaba"},
+ {file = "identify-2.5.27.tar.gz", hash = "sha256:287b75b04a0e22d727bc9a41f0d4f3c1bcada97490fa6eabb5b28f0e9097e733"},
]
[package.extras]
@@ -1498,13 +1545,13 @@ files = [
[[package]]
name = "imageio"
-version = "2.31.1"
+version = "2.31.2"
description = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats."
optional = false
python-versions = ">=3.7"
files = [
- {file = "imageio-2.31.1-py3-none-any.whl", hash = "sha256:4106fb395ef7f8dc0262d6aa1bb03daba818445c381ca8b7d5dfc7a2089b04df"},
- {file = "imageio-2.31.1.tar.gz", hash = "sha256:f8436a02af02fd63f272dab50f7d623547a38f0e04a4a73e2b02ae1b8b180f27"},
+ {file = "imageio-2.31.2-py3-none-any.whl", hash = "sha256:a78fbcb33432042a4d6993c87f3ea1f136d908318ce7dda857846ccff73294de"},
+ {file = "imageio-2.31.2.tar.gz", hash = "sha256:ae19221f4a8f118f1c9451e8f5357faeeacdf956198cf374bc8ab00f1ff7d525"},
]
[package.dependencies]
@@ -1553,25 +1600,6 @@ files = [
{file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"},
]
-[[package]]
-name = "importlib-metadata"
-version = "6.8.0"
-description = "Read metadata from Python packages"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"},
- {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"},
-]
-
-[package.dependencies]
-zipp = ">=0.5"
-
-[package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
-perf = ["ipython"]
-testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"]
-
[[package]]
name = "iniconfig"
version = "2.0.0"
@@ -1729,79 +1757,115 @@ files = [
[[package]]
name = "kiwisolver"
-version = "1.4.4"
+version = "1.4.5"
description = "A fast implementation of the Cassowary constraint solver"
optional = false
python-versions = ">=3.7"
files = [
- {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"},
- {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"},
- {file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"},
- {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"},
- {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"},
- {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"},
- {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"},
- {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"},
- {file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"},
- {file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"},
- {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"},
- {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"},
- {file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"},
- {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"},
- {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"},
- {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"},
- {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"},
- {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"},
- {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"},
- {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"},
- {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"},
- {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"},
- {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"},
- {file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"},
- {file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"},
- {file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"},
- {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"},
- {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"},
- {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"},
- {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"},
- {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"},
- {file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"},
- {file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"},
- {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"},
- {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"},
- {file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"},
- {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"},
- {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"},
- {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"},
- {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"},
- {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"},
- {file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"},
- {file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"},
- {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"},
- {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"},
- {file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"},
- {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"},
- {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"},
- {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"},
- {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"},
- {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"},
- {file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"},
- {file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"},
- {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"},
- {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"},
- {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"},
- {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"},
- {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"},
- {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"},
- {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"},
- {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"},
- {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"},
- {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"},
- {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"},
- {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"},
- {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"},
- {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"},
- {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"},
+ {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"},
+ {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"},
+ {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"},
+ {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"},
+ {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"},
+ {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"},
+ {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"},
+ {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"},
+ {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"},
+ {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"},
+ {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"},
+ {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"},
+ {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"},
+ {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"},
+ {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"},
+ {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"},
]
[[package]]
@@ -2491,33 +2555,37 @@ test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"]
[[package]]
name = "nicegui"
-version = "1.2.24"
+version = "1.3.12"
description = "Create web-based user interfaces with Python. The nice way."
optional = false
-python-versions = ">=3.7,<4.0"
+python-versions = ">=3.8,<4.0"
files = [
- {file = "nicegui-1.2.24-py3-none-any.whl", hash = "sha256:f649e1e84012af4d9e6723fbb559df665ac2c798158dee61657257955657d477"},
- {file = "nicegui-1.2.24.tar.gz", hash = "sha256:8d3973ec359c0cc2534712c25b92447878dc6ed394cb9a9a491396c6e04c2dbd"},
+ {file = "nicegui-1.3.12-py3-none-any.whl", hash = "sha256:7bd6fdfc5b0856ee8e3fd9f75edb822ff74ccf94033bd5962e453dacd0dd6636"},
+ {file = "nicegui-1.3.12.tar.gz", hash = "sha256:2454c0f0a98b5dbb798e0d6452545e38ecf1577a2c8d72c6f7be2667eca9b18a"},
]
[package.dependencies]
aiofiles = ">=23.1.0,<24.0.0"
+aiohttp = ">=3.8.5,<4.0.0"
fastapi = ">=0.92,<1.0.0"
fastapi-socketio = ">=0.0.10,<0.0.11"
-importlib_metadata = {version = ">=6.0.0,<7.0.0", markers = "python_version ~= \"3.7\""}
+httpx = ">=0.24.1,<0.25.0"
itsdangerous = ">=2.1.2,<3.0.0"
jinja2 = ">=3.1.2,<4.0.0"
markdown2 = ">=2.4.7,<3.0.0"
-matplotlib = {version = ">=3.5.0,<4.0.0", markers = "python_version ~= \"3.7\""}
orjson = {version = ">=3.8.6,<4.0.0", markers = "platform_machine != \"i386\" and platform_machine != \"i686\""}
-plotly = ">=5.13.0,<6.0.0"
Pygments = ">=2.9.0,<3.0.0"
python-multipart = ">=0.0.6,<0.0.7"
-pywebview = ">=4.0.2,<5.0.0"
typing-extensions = ">=3.10.0"
-uvicorn = {version = ">=0.20.0,<0.21.0", extras = ["standard"]}
-vbuild = ">=0.8.1,<0.9.0"
-watchfiles = ">=0.18.1,<0.19.0"
+uvicorn = {version = ">=0.22.0,<0.23.0", extras = ["standard"]}
+vbuild = ">=0.8.2"
+watchfiles = ">=0.18.1,<1.0.0"
+
+[package.extras]
+matplotlib = ["matplotlib (>=3.5.0,<4.0.0)"]
+native = ["pywebview (>=4.0.2,<5.0.0)"]
+netifaces = ["netifaces (>=0.11.0,<0.12.0)"]
+plotly = ["plotly (>=5.13.0,<6.0.0)"]
[[package]]
name = "nltk"
@@ -2971,13 +3039,13 @@ ptyprocess = ">=0.5"
[[package]]
name = "phonenumbers"
-version = "8.13.18"
+version = "8.13.19"
description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers."
optional = false
python-versions = "*"
files = [
- {file = "phonenumbers-8.13.18-py2.py3-none-any.whl", hash = "sha256:3d802739a22592e4127139349937753dee9b6a20bdd5d56847cd885bdc766b1f"},
- {file = "phonenumbers-8.13.18.tar.gz", hash = "sha256:b360c756252805d44b447b5bca6d250cf6bd6c69b6f0f4258f3bfe5ab81bef69"},
+ {file = "phonenumbers-8.13.19-py2.py3-none-any.whl", hash = "sha256:ba542f20f6dc83be8f127f240f9b5b7e7c1dec42aceff1879400d4dc0c781d81"},
+ {file = "phonenumbers-8.13.19.tar.gz", hash = "sha256:38180247697240ccedd74dec4bfbdbc22bb108b9c5f991f270ca3e41395e6f96"},
]
[[package]]
@@ -3085,30 +3153,15 @@ files = [
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"]
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"]
-[[package]]
-name = "plotly"
-version = "5.16.1"
-description = "An open-source, interactive data visualization library for Python"
-optional = false
-python-versions = ">=3.6"
-files = [
- {file = "plotly-5.16.1-py2.py3-none-any.whl", hash = "sha256:19cc34f339acd4e624177806c14df22f388f23fb70658b03aad959a0e650a0dc"},
- {file = "plotly-5.16.1.tar.gz", hash = "sha256:295ac25edeb18c893abb71dcadcea075b78fd6fdf07cee4217a4e1009667925b"},
-]
-
-[package.dependencies]
-packaging = "*"
-tenacity = ">=6.2.0"
-
[[package]]
name = "pluggy"
-version = "1.2.0"
+version = "1.3.0"
description = "plugin and hook calling mechanisms for python"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"},
- {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"},
+ {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"},
+ {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"},
]
[package.extras]
@@ -3255,24 +3308,24 @@ wcwidth = "*"
[[package]]
name = "protobuf"
-version = "4.24.0"
+version = "4.24.2"
description = ""
optional = false
python-versions = ">=3.7"
files = [
- {file = "protobuf-4.24.0-cp310-abi3-win32.whl", hash = "sha256:81cb9c4621d2abfe181154354f63af1c41b00a4882fb230b4425cbaed65e8f52"},
- {file = "protobuf-4.24.0-cp310-abi3-win_amd64.whl", hash = "sha256:6c817cf4a26334625a1904b38523d1b343ff8b637d75d2c8790189a4064e51c3"},
- {file = "protobuf-4.24.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:ae97b5de10f25b7a443b40427033e545a32b0e9dda17bcd8330d70033379b3e5"},
- {file = "protobuf-4.24.0-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:567fe6b0647494845d0849e3d5b260bfdd75692bf452cdc9cb660d12457c055d"},
- {file = "protobuf-4.24.0-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:a6b1ca92ccabfd9903c0c7dde8876221dc7d8d87ad5c42e095cc11b15d3569c7"},
- {file = "protobuf-4.24.0-cp37-cp37m-win32.whl", hash = "sha256:a38400a692fd0c6944c3c58837d112f135eb1ed6cdad5ca6c5763336e74f1a04"},
- {file = "protobuf-4.24.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5ab19ee50037d4b663c02218a811a5e1e7bb30940c79aac385b96e7a4f9daa61"},
- {file = "protobuf-4.24.0-cp38-cp38-win32.whl", hash = "sha256:e8834ef0b4c88666ebb7c7ec18045aa0f4325481d724daa624a4cf9f28134653"},
- {file = "protobuf-4.24.0-cp38-cp38-win_amd64.whl", hash = "sha256:8bb52a2be32db82ddc623aefcedfe1e0eb51da60e18fcc908fb8885c81d72109"},
- {file = "protobuf-4.24.0-cp39-cp39-win32.whl", hash = "sha256:ae7a1835721086013de193311df858bc12cd247abe4ef9710b715d930b95b33e"},
- {file = "protobuf-4.24.0-cp39-cp39-win_amd64.whl", hash = "sha256:44825e963008f8ea0d26c51911c30d3e82e122997c3c4568fd0385dd7bacaedf"},
- {file = "protobuf-4.24.0-py3-none-any.whl", hash = "sha256:82e6e9ebdd15b8200e8423676eab38b774624d6a1ad696a60d86a2ac93f18201"},
- {file = "protobuf-4.24.0.tar.gz", hash = "sha256:5d0ceb9de6e08311832169e601d1fc71bd8e8c779f3ee38a97a78554945ecb85"},
+ {file = "protobuf-4.24.2-cp310-abi3-win32.whl", hash = "sha256:58e12d2c1aa428ece2281cef09bbaa6938b083bcda606db3da4e02e991a0d924"},
+ {file = "protobuf-4.24.2-cp310-abi3-win_amd64.whl", hash = "sha256:77700b55ba41144fc64828e02afb41901b42497b8217b558e4a001f18a85f2e3"},
+ {file = "protobuf-4.24.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:237b9a50bd3b7307d0d834c1b0eb1a6cd47d3f4c2da840802cd03ea288ae8880"},
+ {file = "protobuf-4.24.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:25ae91d21e3ce8d874211110c2f7edd6384816fb44e06b2867afe35139e1fd1c"},
+ {file = "protobuf-4.24.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:c00c3c7eb9ad3833806e21e86dca448f46035242a680f81c3fe068ff65e79c74"},
+ {file = "protobuf-4.24.2-cp37-cp37m-win32.whl", hash = "sha256:4e69965e7e54de4db989289a9b971a099e626f6167a9351e9d112221fc691bc1"},
+ {file = "protobuf-4.24.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c5cdd486af081bf752225b26809d2d0a85e575b80a84cde5172a05bbb1990099"},
+ {file = "protobuf-4.24.2-cp38-cp38-win32.whl", hash = "sha256:6bd26c1fa9038b26c5c044ee77e0ecb18463e957fefbaeb81a3feb419313a54e"},
+ {file = "protobuf-4.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb7aa97c252279da65584af0456f802bd4b2de429eb945bbc9b3d61a42a8cd16"},
+ {file = "protobuf-4.24.2-cp39-cp39-win32.whl", hash = "sha256:2b23bd6e06445699b12f525f3e92a916f2dcf45ffba441026357dea7fa46f42b"},
+ {file = "protobuf-4.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:839952e759fc40b5d46be319a265cf94920174d88de31657d5622b5d8d6be5cd"},
+ {file = "protobuf-4.24.2-py3-none-any.whl", hash = "sha256:3b7b170d3491ceed33f723bbf2d5a260f8a4e23843799a3906f16ef736ef251e"},
+ {file = "protobuf-4.24.2.tar.gz", hash = "sha256:7fda70797ddec31ddfa3576cbdcc3ddbb6b3078b737a1a87ab9136af0570cd6e"},
]
[[package]]
@@ -3621,23 +3674,23 @@ plugins = ["importlib-metadata"]
[[package]]
name = "pyinstaller"
-version = "5.13.0"
+version = "5.13.1"
description = "PyInstaller bundles a Python application and all its dependencies into a single package."
optional = false
python-versions = "<3.13,>=3.7"
files = [
- {file = "pyinstaller-5.13.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:7fdd319828de679f9c5e381eff998ee9b4164bf4457e7fca56946701cf002c3f"},
- {file = "pyinstaller-5.13.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0df43697c4914285ecd333be968d2cd042ab9b2670124879ee87931d2344eaf5"},
- {file = "pyinstaller-5.13.0-py3-none-manylinux2014_i686.whl", hash = "sha256:28d9742c37e9fb518444b12f8c8ab3cb4ba212d752693c34475c08009aa21ccf"},
- {file = "pyinstaller-5.13.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e5fb17de6c325d3b2b4ceaeb55130ad7100a79096490e4c5b890224406fa42f4"},
- {file = "pyinstaller-5.13.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:78975043edeb628e23a73fb3ef0a273cda50e765f1716f75212ea3e91b09dede"},
- {file = "pyinstaller-5.13.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:cd7d5c06f2847195a23d72ede17c60857d6f495d6f0727dc6c9bc1235f2eb79c"},
- {file = "pyinstaller-5.13.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:24009eba63cfdbcde6d2634e9c87f545eb67249ddf3b514e0cd3b2cdaa595828"},
- {file = "pyinstaller-5.13.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:1fde4381155f21d6354dc450dcaa338cd8a40aaacf6bd22b987b0f3e1f96f3ee"},
- {file = "pyinstaller-5.13.0-py3-none-win32.whl", hash = "sha256:2d03419904d1c25c8968b0ad21da0e0f33d8d65716e29481b5bd83f7f342b0c5"},
- {file = "pyinstaller-5.13.0-py3-none-win_amd64.whl", hash = "sha256:9fc27c5a853b14a90d39c252707673c7a0efec921cd817169aff3af0fca8c127"},
- {file = "pyinstaller-5.13.0-py3-none-win_arm64.whl", hash = "sha256:3a331951f9744bc2379ea5d65d36f3c828eaefe2785f15039592cdc08560b262"},
- {file = "pyinstaller-5.13.0.tar.gz", hash = "sha256:5e446df41255e815017d96318e39f65a3eb807e74a796c7e7ff7f13b6366a2e9"},
+ {file = "pyinstaller-5.13.1-py3-none-macosx_10_13_universal2.whl", hash = "sha256:3c9cfe6d5d2f392d5d47389f6d377a8f225db460cdd01048b5a3de1d99c24ebe"},
+ {file = "pyinstaller-5.13.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:29341d2e86d5ce7df993e797ee96ef679041fc85376d31c35c7b714085a21299"},
+ {file = "pyinstaller-5.13.1-py3-none-manylinux2014_i686.whl", hash = "sha256:ad6e31a8f35a463c6140e4cf979859197edc9831a1039253408b0fe5eec274dc"},
+ {file = "pyinstaller-5.13.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:5d801db3ceee58d01337473ea897e96e4bb21421a169dd7cf8716754617ff7fc"},
+ {file = "pyinstaller-5.13.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:2519db3edec87d8c33924c2c4b7e176d8c1bbd9ba892d77efb67281925e621d6"},
+ {file = "pyinstaller-5.13.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e033218c8922f0342b6095fb444ecb3bc6747dfa58cac5eac2b985350f4b681e"},
+ {file = "pyinstaller-5.13.1-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:086e68aa1e72f6aa13b9d170a395755e2b194b8ab410caeed02d16b432410c8c"},
+ {file = "pyinstaller-5.13.1-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:aa609aca62edd8cdcf7740677a21525e6c23b5e9a8f821ec8a80c68947771b5d"},
+ {file = "pyinstaller-5.13.1-py3-none-win32.whl", hash = "sha256:b8d4000af72bf72f8185d420cd0a0aee0961f03a5c3511dc3ff08cdaef0583de"},
+ {file = "pyinstaller-5.13.1-py3-none-win_amd64.whl", hash = "sha256:b70ebc10811b30bbea4cf5b81fd1477db992c2614cf215edc987cda9c5468911"},
+ {file = "pyinstaller-5.13.1-py3-none-win_arm64.whl", hash = "sha256:78d1601a11475b95dceff6eaf0c9cd74d93e3f47b5ce4ad63cd76e7a369d3d04"},
+ {file = "pyinstaller-5.13.1.tar.gz", hash = "sha256:a2e7a1d76a7ac26f1db849d691a374f2048b0e204233028d25d79a90ecd1fec8"},
]
[package.dependencies]
@@ -3654,13 +3707,13 @@ hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"]
[[package]]
name = "pyinstaller-hooks-contrib"
-version = "2023.6"
+version = "2023.7"
description = "Community maintained hooks for PyInstaller"
optional = false
python-versions = ">=3.7"
files = [
- {file = "pyinstaller-hooks-contrib-2023.6.tar.gz", hash = "sha256:596a72009d8692b043e0acbf5e1b476d93149900142ba01845dded91a0770cb5"},
- {file = "pyinstaller_hooks_contrib-2023.6-py2.py3-none-any.whl", hash = "sha256:aa6d7d038814df6aa7bec7bdbebc7cb4c693d3398df858f6062957f0797d397b"},
+ {file = "pyinstaller-hooks-contrib-2023.7.tar.gz", hash = "sha256:0c436a4c3506020e34116a8a7ddfd854c1ad6ddca9a8cd84500bd6e69c9e68f9"},
+ {file = "pyinstaller_hooks_contrib-2023.7-py2.py3-none-any.whl", hash = "sha256:3c10df14c0f71ab388dfbf1625375b087e7330d9444cbfd2b310ba027fa0cff0"},
]
[[package]]
@@ -4103,13 +4156,13 @@ cli = ["click (>=5.0)"]
[[package]]
name = "python-engineio"
-version = "4.5.1"
+version = "4.6.1"
description = "Engine.IO server and client for Python"
optional = false
python-versions = ">=3.6"
files = [
- {file = "python-engineio-4.5.1.tar.gz", hash = "sha256:b167a1b208fcdce5dbe96a61a6ca22391cfa6715d796c22de93e3adf9c07ae0c"},
- {file = "python_engineio-4.5.1-py3-none-any.whl", hash = "sha256:67a675569f3e9bb274a8077f3c2068a8fe79cbfcb111cf31ca27b968484fe6c7"},
+ {file = "python-engineio-4.6.1.tar.gz", hash = "sha256:83fee966bec427e74b23a8c5d261655ed780bec147ff01cadc9f48ae9b8b6220"},
+ {file = "python_engineio-4.6.1-py3-none-any.whl", hash = "sha256:eed1ffa9b003104b92c7760de5ac43d074abce28fd28a511d5268da82bfb8644"},
]
[package.extras]
@@ -4712,17 +4765,17 @@ dev = ["black", "flake8", "isort", "mypy"]
[[package]]
name = "setuptools"
-version = "68.1.0"
+version = "68.1.2"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.8"
files = [
- {file = "setuptools-68.1.0-py3-none-any.whl", hash = "sha256:e13e1b0bc760e9b0127eda042845999b2f913e12437046e663b833aa96d89715"},
- {file = "setuptools-68.1.0.tar.gz", hash = "sha256:d59c97e7b774979a5ccb96388efc9eb65518004537e85d52e81eaee89ab6dd91"},
+ {file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"},
+ {file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"},
]
[package.extras]
-docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
+docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
@@ -5186,13 +5239,13 @@ test = ["pytest"]
[[package]]
name = "sphinxcontrib-serializinghtml"
-version = "1.1.8"
+version = "1.1.9"
description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)"
optional = false
python-versions = ">=3.9"
files = [
- {file = "sphinxcontrib_serializinghtml-1.1.8-py3-none-any.whl", hash = "sha256:27849e7227277333d3d32f17c138ee148a51fa01f888a41cd6d4e73bcabe2d06"},
- {file = "sphinxcontrib_serializinghtml-1.1.8.tar.gz", hash = "sha256:aaf3026335146e688fd209b72320314b1b278320cf232e3cda198f873838511a"},
+ {file = "sphinxcontrib_serializinghtml-1.1.9-py3-none-any.whl", hash = "sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1"},
+ {file = "sphinxcontrib_serializinghtml-1.1.9.tar.gz", hash = "sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54"},
]
[package.dependencies]
@@ -5394,20 +5447,6 @@ files = [
[package.dependencies]
mpmath = ">=0.19"
-[[package]]
-name = "tenacity"
-version = "8.2.3"
-description = "Retry code until it succeeds"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "tenacity-8.2.3-py3-none-any.whl", hash = "sha256:ce510e327a630c9e1beaf17d42e6ffacc88185044ad85cf74c0a8887c6a0f88c"},
- {file = "tenacity-8.2.3.tar.gz", hash = "sha256:5398ef0d78e63f40007c1fb4c0bff96e1911394d2fa8d194f77619c05ff6cc8a"},
-]
-
-[package.extras]
-doc = ["reno", "sphinx", "tornado (>=4.5)"]
-
[[package]]
name = "termcolor"
version = "2.3.0"
@@ -5908,13 +5947,13 @@ zstd = ["zstandard (>=0.18.0)"]
[[package]]
name = "uvicorn"
-version = "0.20.0"
+version = "0.22.0"
description = "The lightning-fast ASGI server."
optional = false
python-versions = ">=3.7"
files = [
- {file = "uvicorn-0.20.0-py3-none-any.whl", hash = "sha256:c3ed1598a5668208723f2bb49336f4509424ad198d6ab2615b7783db58d919fd"},
- {file = "uvicorn-0.20.0.tar.gz", hash = "sha256:a4e12017b940247f836bc90b72e725d7dfd0c8ed1c51eb365f5ba30d9f5127d8"},
+ {file = "uvicorn-0.22.0-py3-none-any.whl", hash = "sha256:e9434d3bbf05f310e762147f769c9f21235ee118ba2d2bf1155a7196448bd996"},
+ {file = "uvicorn-0.22.0.tar.gz", hash = "sha256:79277ae03db57ce7d9aa0567830bbb51d7a612f54d6e1e3e92da3ef24c2c8ed8"},
]
[package.dependencies]
@@ -6025,29 +6064,33 @@ colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\" and python
[[package]]
name = "watchfiles"
-version = "0.18.1"
+version = "0.20.0"
description = "Simple, modern and high performance file watching and code reload in python."
optional = false
python-versions = ">=3.7"
files = [
- {file = "watchfiles-0.18.1-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:9891d3c94272108bcecf5597a592e61105279def1313521e637f2d5acbe08bc9"},
- {file = "watchfiles-0.18.1-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:7102342d60207fa635e24c02a51c6628bf0472e5fef067f78a612386840407fc"},
- {file = "watchfiles-0.18.1-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:00ea0081eca5e8e695cffbc3a726bb90da77f4e3f78ce29b86f0d95db4e70ef7"},
- {file = "watchfiles-0.18.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b8e6db99e49cd7125d8a4c9d33c0735eea7b75a942c6ad68b75be3e91c242fb"},
- {file = "watchfiles-0.18.1-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc7c726855f04f22ac79131b51bf0c9f728cb2117419ed830a43828b2c4a5fcb"},
- {file = "watchfiles-0.18.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbaff354d12235002e62d9d3fa8bcf326a8490c1179aa5c17195a300a9e5952f"},
- {file = "watchfiles-0.18.1-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:888db233e06907c555eccd10da99b9cd5ed45deca47e41766954292dc9f7b198"},
- {file = "watchfiles-0.18.1-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:dde79930d1b28f15994ad6613aa2865fc7a403d2bb14585a8714a53233b15717"},
- {file = "watchfiles-0.18.1-cp37-abi3-win32.whl", hash = "sha256:e2b2bdd26bf8d6ed90763e6020b475f7634f919dbd1730ea1b6f8cb88e21de5d"},
- {file = "watchfiles-0.18.1-cp37-abi3-win_amd64.whl", hash = "sha256:c541e0f2c3e95e83e4f84561c893284ba984e9d0025352057396d96dceb09f44"},
- {file = "watchfiles-0.18.1-cp37-abi3-win_arm64.whl", hash = "sha256:9a26272ef3e930330fc0c2c148cc29706cc2c40d25760c7ccea8d768a8feef8b"},
- {file = "watchfiles-0.18.1-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:9fb12a5e2b42e0b53769455ff93546e6bc9ab14007fbd436978d827a95ca5bd1"},
- {file = "watchfiles-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:548d6b42303d40264118178053c78820533b683b20dfbb254a8706ca48467357"},
- {file = "watchfiles-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0d8fdfebc50ac7569358f5c75f2b98bb473befccf9498cf23b3e39993bb45a"},
- {file = "watchfiles-0.18.1-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:0f9a22fff1745e2bb930b1e971c4c5b67ea3b38ae17a6adb9019371f80961219"},
- {file = "watchfiles-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b02e7fa03cd4059dd61ff0600080a5a9e7a893a85cb8e5178943533656eec65e"},
- {file = "watchfiles-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a868ce2c7565137f852bd4c863a164dc81306cae7378dbdbe4e2aca51ddb8857"},
- {file = "watchfiles-0.18.1.tar.gz", hash = "sha256:4ec0134a5e31797eb3c6c624dbe9354f2a8ee9c720e0b46fc5b7bab472b7c6d4"},
+ {file = "watchfiles-0.20.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:3796312bd3587e14926013612b23066912cf45a14af71cf2b20db1c12dadf4e9"},
+ {file = "watchfiles-0.20.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:d0002d81c89a662b595645fb684a371b98ff90a9c7d8f8630c82f0fde8310458"},
+ {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:570848706440373b4cd8017f3e850ae17f76dbdf1e9045fc79023b11e1afe490"},
+ {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a0351d20d03c6f7ad6b2e8a226a5efafb924c7755ee1e34f04c77c3682417fa"},
+ {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:007dcc4a401093010b389c044e81172c8a2520dba257c88f8828b3d460c6bb38"},
+ {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d82dbc1832da83e441d112069833eedd4cf583d983fb8dd666fbefbea9d99c0"},
+ {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99f4c65fd2fce61a571b2a6fcf747d6868db0bef8a934e8ca235cc8533944d95"},
+ {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5392dd327a05f538c56edb1c6ebba6af91afc81b40822452342f6da54907bbdf"},
+ {file = "watchfiles-0.20.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:08dc702529bb06a2b23859110c214db245455532da5eaea602921687cfcd23db"},
+ {file = "watchfiles-0.20.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7d4e66a857621584869cfbad87039e65dadd7119f0d9bb9dbc957e089e32c164"},
+ {file = "watchfiles-0.20.0-cp37-abi3-win32.whl", hash = "sha256:a03d1e6feb7966b417f43c3e3783188167fd69c2063e86bad31e62c4ea794cc5"},
+ {file = "watchfiles-0.20.0-cp37-abi3-win_amd64.whl", hash = "sha256:eccc8942bcdc7d638a01435d915b913255bbd66f018f1af051cd8afddb339ea3"},
+ {file = "watchfiles-0.20.0-cp37-abi3-win_arm64.whl", hash = "sha256:b17d4176c49d207865630da5b59a91779468dd3e08692fe943064da260de2c7c"},
+ {file = "watchfiles-0.20.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d97db179f7566dcf145c5179ddb2ae2a4450e3a634eb864b09ea04e68c252e8e"},
+ {file = "watchfiles-0.20.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:835df2da7a5df5464c4a23b2d963e1a9d35afa422c83bf4ff4380b3114603644"},
+ {file = "watchfiles-0.20.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:608cd94a8767f49521901aff9ae0c92cc8f5a24d528db7d6b0295290f9d41193"},
+ {file = "watchfiles-0.20.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89d1de8218874925bce7bb2ae9657efc504411528930d7a83f98b1749864f2ef"},
+ {file = "watchfiles-0.20.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:13f995d5152a8ba4ed7c2bbbaeee4e11a5944defc7cacd0ccb4dcbdcfd78029a"},
+ {file = "watchfiles-0.20.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:9b5c8d3be7b502f8c43a33c63166ada8828dbb0c6d49c8f9ce990a96de2f5a49"},
+ {file = "watchfiles-0.20.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e43af4464daa08723c04b43cf978ab86cc55c684c16172622bdac64b34e36af0"},
+ {file = "watchfiles-0.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87d9e1f75c4f86c93d73b5bd1ebe667558357548f11b4f8af4e0e272f79413ce"},
+ {file = "watchfiles-0.20.0.tar.gz", hash = "sha256:728575b6b94c90dd531514677201e8851708e6e4b5fe7028ac506a200b622019"},
]
[package.dependencies]
@@ -6328,22 +6371,7 @@ files = [
idna = ">=2.0"
multidict = ">=4.0"
-[[package]]
-name = "zipp"
-version = "3.16.2"
-description = "Backport of pathlib-compatible object wrapper for zip files"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"},
- {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"},
-]
-
-[package.extras]
-docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
-testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"]
-
[metadata]
lock-version = "2.0"
python-versions = "3.10.x"
-content-hash = "d3acb4546f8f64132f405b1ca14d9441cb92708de4ff0ff7912bdfb2f08c1544"
+content-hash = "caeb002c4b61267ed221eb8208be297c45b76c1d75313ed4791d079dfd06f7a9"
diff --git a/pyproject.toml b/pyproject.toml
index 37de6eee3..7a3f72de1 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -53,7 +53,7 @@ python-dotenv = "1.0.0"
pyinstaller = "^5.12.0"
setuptools-lint = "^0.6.0"
sphinx = "7.0.1"
-nicegui = "1.2.24"
+nicegui = "^1.2.24"
spacy = "^3.5.3"
fuzzywuzzy = "0.18.0"
segment-anything = "^1.0"
@@ -78,6 +78,8 @@ fastapi = "0.98.0"
oa-pynput = "^1.7.7"
oa-atomacos = {version = "3.2.0", markers = "sys_platform == 'darwin'"}
presidio-image-redactor = "^0.0.48"
+pywebview = "^4.2.2"
+click = "^8.1.6"
spacy-transformers = "^1.2.5"
[tool.pytest.ini_options]