From ab01d8f75e8b402d168ef084908a276d2547454d Mon Sep 17 00:00:00 2001 From: DerGrumpf Date: Sat, 1 Mar 2025 14:30:36 +0100 Subject: [PATCH] Added: HTML Viewer for Class Graph --- learnlytics/gui/analyzer/__init__.py | 10 +- learnlytics/gui/analyzer/class_graph.py | 76 ++++++++++++++ learnlytics/gui/analyzer/group_graph.py | 2 +- learnlytics/gui/analyzer/plotter.py | 65 +++++++++--- learnlytics/gui/gui.py | 2 +- poetry.lock | 125 +++++++++++++++++++++++- pyproject.toml | 1 + 7 files changed, 265 insertions(+), 16 deletions(-) create mode 100644 learnlytics/gui/analyzer/class_graph.py diff --git a/learnlytics/gui/analyzer/__init__.py b/learnlytics/gui/analyzer/__init__.py index 9c0dbff..d591881 100644 --- a/learnlytics/gui/analyzer/__init__.py +++ b/learnlytics/gui/analyzer/__init__.py @@ -4,6 +4,8 @@ from typing import List from .student_list import student_list from .student_graph import student_graph from .group_graph import group_graph +from .class_graph import class_graph + def analyzer_docking_splits() -> List[hello_imgui.DockingSplit]: split_main_misc = hello_imgui.DockingSplit() @@ -45,6 +47,11 @@ def set_analyzer_layout() -> List[hello_imgui.DockableWindow]: group_info.dock_space_name = "MainDockSpace" group_info.gui_function = lambda: group_graph() + class_info = hello_imgui.DockableWindow() + class_info.label = "Class Analyzer" + class_info.dock_space_name = "MainDockSpace" + class_info.gui_function = lambda: class_graph() + #student_ranking = hello_imgui.DockableWindow() #student_ranking.label = "Ranking" #student_ranking.dock_space_name = "MainDockSpace" @@ -53,7 +60,8 @@ def set_analyzer_layout() -> List[hello_imgui.DockableWindow]: return [ student_selector, student_info, - group_info + group_info, + class_info ] def analyzer_layout() -> hello_imgui.DockingParams: diff --git a/learnlytics/gui/analyzer/class_graph.py b/learnlytics/gui/analyzer/class_graph.py new file mode 100644 index 0000000..3879761 --- /dev/null +++ b/learnlytics/gui/analyzer/class_graph.py @@ -0,0 +1,76 @@ +from imgui_bundle import ( + imgui, + immapp, + imgui_md, + ImVec2 +) + +from peewee import fn +from pathlib import Path +import subprocess, os, platform +from dbmodel import * +from .analyzer_state import AnalyzerState +from .plotter import plot_html + +state = AnalyzerState() + + +@immapp.static(inited=False) +def ranking(class_id: int) -> None: + if class_id < 1: + return + + statics = ranking + + if not statics.inited: + statics.class_id = class_id + statics.data = [ + (student, Submission.select(fn.SUM(Submission.points)).where(Submission.student_id == student.id).scalar()) + for student in Student.select().where(Student.class_id == class_id) + ] + statics.data.sort(key = lambda tup: tup[1], reverse=True) + statics.inited = True + + if statics.class_id != class_id: + statics.inited = False + + imgui_md.render(f"# Ranking - {Class.get_by_id(statics.class_id).name}") + imgui.text("") + + if imgui.begin_table("Ranking1", len(statics.data), imgui.TableFlags_.sizing_fixed_fit.value): + for n, d in enumerate(statics.data, start=1): + student, points = d + if points.is_integer(): + points = int(points) + imgui.table_next_row() + imgui.table_next_column() + #imgui.set_next_item_width(-1) + imgui.text(f"{n}. {student.prename} {student.surname} - {points} Points") + imgui.end_table() + +def class_graph() -> None: + if db.is_closed(): + imgui.text("No DB loaded") + return + + w, h = imgui.get_content_region_avail() + + if imgui.begin_child("Ranking", ImVec2(w*0.3, h*0.5), imgui.ChildFlags_.borders.value): + ranking(state.class_id) + imgui.end_child() + + imgui.same_line() + + if imgui.begin_child("Presentations", ImVec2(w*0.7, h*0.7), imgui.ChildFlags_.borders.value): + html = Path("/storage/programming/Learnlytics/assets/covid_faelle_MeWi_2.html") + plot_html(html) + imgui.same_line() + if imgui.button("Open in Browser"): + # I Hate everything about it + if platform.system() == 'Darwin': # MacOS + subprocess.Popen(('open', html)) + elif platform.system() == 'Windows': # Windows + os.startfile(html) + else: # Linux & Variants + subprocess.Popen(('xdg-open', html)) + imgui.end_child() diff --git a/learnlytics/gui/analyzer/group_graph.py b/learnlytics/gui/analyzer/group_graph.py index c6f476f..1123fb1 100644 --- a/learnlytics/gui/analyzer/group_graph.py +++ b/learnlytics/gui/analyzer/group_graph.py @@ -47,7 +47,7 @@ def header(group_id: int) -> None: statics.group.has_passed = not statics.group.has_passed statics.group.save() - if imgui.begin_table("Students", len(statics.data), imgui.TableFlags_.sizing_fixed_fit): + if imgui.begin_table("Students", len(statics.data), imgui.TableFlags_.sizing_fixed_fit.value): for n, d in enumerate(statics.data, start=1): s, points = d if points.is_integer(): diff --git a/learnlytics/gui/analyzer/plotter.py b/learnlytics/gui/analyzer/plotter.py index c2f42ad..9a0c867 100644 --- a/learnlytics/gui/analyzer/plotter.py +++ b/learnlytics/gui/analyzer/plotter.py @@ -3,14 +3,17 @@ from imgui_bundle import ( imgui, immapp, immvision, + imgui_toggle, ImVec4, ImVec2 ) from PIL import Image +import io import numpy as np from pdf2image import convert_from_path from pathlib import Path +from playwright.sync_api import sync_playwright as pw immvision.use_rgb_color_order() @@ -63,6 +66,56 @@ def plot_pie(data: np.array, labels: list, title: str = "Group Performance") -> implot.end_plot() +@immapp.static(inited=False) +def plot_html(html: Path, label: str = "Presentation") -> None: + if not html.exists(): + return + + statics = plot_html + if not statics.inited: + statics.html = html + statics.quality = 10 + statics.high_quality = False + statics.flags = imgui_toggle.glowing_style() + statics.reload = True + statics.inited = True + + if statics.reload: + with pw() as p: + browser_type = p.chromium + browser = browser_type.launch() + page = browser.new_page() + page.set_content(html.read_text()) + statics.buffer = page.screenshot(quality=statics.quality, type='jpeg') + browser.close() + statics.image = Image.open(io.BytesIO(statics.buffer)) + statics.image = np.array(statics.image.convert('RGB')) + statics.reload = False + + if statics.html != html: + statics.inited = False + + h = imgui.get_window_size().y + size = (0, int(h*0.8)) + immvision.image_display(label, statics.image, size, True) + + changed, _ = imgui_toggle.toggle("High Quality", statics.high_quality, statics.flags) + if changed: + statics.high_quality = not statics.high_quality + statics.quality = 100 if statics.high_quality else 10 + statics.reload = True + + + imgui.same_line() + + if imgui.button("Back"): + pass + + imgui.same_line() + + if imgui.button("Next"): + pass + @immapp.static(inited=False) def plot_pdf(pdf: Path, label: str = "Presentation") -> None: if not pdf.exists(): @@ -73,18 +126,6 @@ def plot_pdf(pdf: Path, label: str = "Presentation") -> None: statics.pdf = pdf statics.images = convert_from_path(statics.pdf.resolve(), size=720, fmt='jpeg') - statics.params = immvision.ImageParams( - refresh_image = True, - show_image_info = False, - show_pixel_info = False, - show_zoom_buttons = False, - show_options_button = False, - can_resize = False, - zoom_pan_matrix = None, - pan_with_mouse = False, - zoom_with_mouse_wheel = False, - image_display_size = (500, 0) - ) statics.selected = 0 statics.inited = True diff --git a/learnlytics/gui/gui.py b/learnlytics/gui/gui.py index 5b68b65..2a78b68 100644 --- a/learnlytics/gui/gui.py +++ b/learnlytics/gui/gui.py @@ -25,6 +25,6 @@ def menu_bar(runner_params: hello_imgui.RunnerParams) -> None: def status_bar() -> None: """Displays the status bar information.""" - imgui.text("Student Analyzer by @DerGrumpf") + imgui.text("Learnlytics by @DerGrumpf") diff --git a/poetry.lock b/poetry.lock index 07e8f53..06ddd47 100644 --- a/poetry.lock +++ b/poetry.lock @@ -64,6 +64,92 @@ files = [ [package.extras] preview = ["glfw-preview"] +[[package]] +name = "greenlet" +version = "3.1.1" +description = "Lightweight in-process concurrent programming" +optional = false +python-versions = ">=3.7" +files = [ + {file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6"}, + {file = "greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80"}, + {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395"}, + {file = "greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39"}, + {file = "greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942"}, + {file = "greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01"}, + {file = "greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c"}, + {file = "greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af"}, + {file = "greenlet-3.1.1-cp37-cp37m-win32.whl", hash = "sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798"}, + {file = "greenlet-3.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef"}, + {file = "greenlet-3.1.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7"}, + {file = "greenlet-3.1.1-cp38-cp38-win32.whl", hash = "sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef"}, + {file = "greenlet-3.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d"}, + {file = "greenlet-3.1.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e"}, + {file = "greenlet-3.1.1-cp39-cp39-win32.whl", hash = "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c"}, + {file = "greenlet-3.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22"}, + {file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"}, +] + +[package.extras] +docs = ["Sphinx", "furo"] +test = ["objgraph", "psutil"] + [[package]] name = "imgui-bundle" version = "1.6.2" @@ -384,6 +470,26 @@ tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "ole typing = ["typing-extensions"] xmp = ["defusedxml"] +[[package]] +name = "playwright" +version = "1.50.0" +description = "A high-level API to automate web browsers" +optional = false +python-versions = ">=3.9" +files = [ + {file = "playwright-1.50.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:f36d754a6c5bd9bf7f14e8f57a2aea6fd08f39ca4c8476481b9c83e299531148"}, + {file = "playwright-1.50.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:40f274384591dfd27f2b014596250b2250c843ed1f7f4ef5d2960ecb91b4961e"}, + {file = "playwright-1.50.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:9922ef9bcd316995f01e220acffd2d37a463b4ad10fd73e388add03841dfa230"}, + {file = "playwright-1.50.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:8fc628c492d12b13d1f347137b2ac6c04f98197ff0985ef0403a9a9ee0d39131"}, + {file = "playwright-1.50.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcff35f72db2689a79007aee78f1b0621a22e6e3d6c1f58aaa9ac805bf4497c"}, + {file = "playwright-1.50.0-py3-none-win32.whl", hash = "sha256:3b906f4d351260016a8c5cc1e003bb341651ae682f62213b50168ed581c7558a"}, + {file = "playwright-1.50.0-py3-none-win_amd64.whl", hash = "sha256:1859423da82de631704d5e3d88602d755462b0906824c1debe140979397d2e8d"}, +] + +[package.dependencies] +greenlet = ">=3.1.1,<4.0.0" +pyee = ">=12,<13" + [[package]] name = "pydantic" version = "2.10.6" @@ -516,6 +622,23 @@ files = [ [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" +[[package]] +name = "pyee" +version = "12.1.1" +description = "A rough port of Node.js's EventEmitter to Python with a few tricks of its own" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyee-12.1.1-py3-none-any.whl", hash = "sha256:18a19c650556bb6b32b406d7f017c8f513aceed1ef7ca618fb65de7bd2d347ef"}, + {file = "pyee-12.1.1.tar.gz", hash = "sha256:bbc33c09e2ff827f74191e3e5bbc6be7da02f627b7ec30d86f5ce1a6fb2424a3"}, +] + +[package.dependencies] +typing-extensions = "*" + +[package.extras] +dev = ["black", "build", "flake8", "flake8-black", "isort", "jupyter-console", "mkdocs", "mkdocs-include-markdown-plugin", "mkdocstrings[python]", "pytest", "pytest-asyncio", "pytest-trio", "sphinx", "toml", "tox", "trio", "trio", "trio-typing", "twine", "twisted", "validate-pyproject[all]"] + [[package]] name = "pyopengl" version = "3.1.9" @@ -693,4 +816,4 @@ devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3) [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "7112b24c85d31e228e464b5c9621e985ae19504e26e1fa6c7f32d8afbf33b86d" +content-hash = "bb8a55ca695106ae590ae540a5261bed6905ea6686e6d38a3e0487e5ebb16d1d" diff --git a/pyproject.toml b/pyproject.toml index c5cdf6e..587fc2d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ colour = "^0.1.5" pytz = "^2025.1" tzlocal = "^5.3" pdf2image = "^1.17.0" +playwright = "^1.50.0" [build-system]