From a9afc1cf7207340c706e50e6c4d2d6f91d7fc262 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 9 Oct 2024 19:41:32 +0100 Subject: [PATCH 01/43] new demo WIP --- src/textual/demo2/__main__.py | 5 ++ src/textual/demo2/demo_app.py | 41 ++++++++++++ src/textual/demo2/page.py | 11 ++++ src/textual/demo2/projects.py | 89 ++++++++++++++++++++++++++ src/textual/demo2/welcome.py | 115 ++++++++++++++++++++++++++++++++++ src/textual/widget.py | 18 ++++++ 6 files changed, 279 insertions(+) create mode 100644 src/textual/demo2/__main__.py create mode 100644 src/textual/demo2/demo_app.py create mode 100644 src/textual/demo2/page.py create mode 100644 src/textual/demo2/projects.py create mode 100644 src/textual/demo2/welcome.py diff --git a/src/textual/demo2/__main__.py b/src/textual/demo2/__main__.py new file mode 100644 index 0000000000..d254f85c41 --- /dev/null +++ b/src/textual/demo2/__main__.py @@ -0,0 +1,5 @@ +from textual.demo2.demo_app import DemoApp + +if __name__ == "__main__": + app = DemoApp() + app.run() diff --git a/src/textual/demo2/demo_app.py b/src/textual/demo2/demo_app.py new file mode 100644 index 0000000000..383d325b6d --- /dev/null +++ b/src/textual/demo2/demo_app.py @@ -0,0 +1,41 @@ +from textual.app import App, ComposeResult +from textual.binding import Binding +from textual.demo2.page import Page +from textual.demo2.projects import ProjectsPage +from textual.demo2.welcome import WelcomePage +from textual.screen import Screen +from textual.widgets import Footer + + +class DemoScreen(Screen): + DEFAULT_CSS = """ + DemoScreen { + layout: horizontal; + } + """ + + BINDINGS = [ + Binding("1", "page(1)", "page 1", tooltip="Go to page 1"), + Binding("2", "page(2)", "page 2", tooltip="Go to page 2"), + Binding("3", "page(3)", "page 3", tooltip="Go to page 3"), + Binding("4", "page(4)", "page 4", tooltip="Go to page 4"), + ] + + def compose(self) -> ComposeResult: + yield Footer() + yield WelcomePage(id="page1") + yield ProjectsPage(id="page2") + yield Page(id="page3") + yield Page(id="page4") + + @property + def allow_horizontal_scroll(self) -> bool: + return True + + def action_page(self, page: int) -> None: + self.query_one(f"#page{page}").scroll_visible() + + +class DemoApp(App): + def get_default_screen(self) -> Screen: + return DemoScreen() diff --git a/src/textual/demo2/page.py b/src/textual/demo2/page.py new file mode 100644 index 0000000000..f38837e172 --- /dev/null +++ b/src/textual/demo2/page.py @@ -0,0 +1,11 @@ +from textual.containers import Vertical + + +class Page(Vertical): + DEFAULT_CSS = """ + Page { + width: 100%; + height: 1fr; + overflow-y: auto; + } + """ diff --git a/src/textual/demo2/projects.py b/src/textual/demo2/projects.py new file mode 100644 index 0000000000..24fbeede5f --- /dev/null +++ b/src/textual/demo2/projects.py @@ -0,0 +1,89 @@ +from dataclasses import dataclass + +from textual.app import ComposeResult +from textual.containers import Grid, Horizontal, Vertical +from textual.demo2.page import Page +from textual.widgets import Label, Static + + +@dataclass +class ProjectInfo: + title: str + url: str + description: str + + +PROJECTS = [ + ProjectInfo( + "Posting", + "https://posting.sh/", + "Posting is a beautiful open-source terminal app for developing and testing APIs.", + ) +] * 4 + + +class Project(Vertical, can_focus=True): + DEFAULT_CSS = """ + Project { + + # margin: 1 2; + width: 1fr; + + padding: 1 2; + # background: $boost; + + border: tall transparent; + + &:focus-within { + border: tall $accent; + background: $boost; + } + #title { + text-style: bold; + } + .stars { + color: $secondary; + text-align: right; + width: 1fr; + } + } + """ + + def __init__(self, project_info: ProjectInfo) -> None: + self.project_info = project_info + super().__init__() + + def compose(self) -> ComposeResult: + with Horizontal(): + yield Label(self.project_info.title, id="title") + yield Label("★ 23K", classes="stars") + yield Static(self.project_info.description) + + +class ProjectsPage(Page): + DEFAULT_CSS = """ + ProjectsPage { + layout: grid; + + margin: 1; + Grid { + + margin: 1 2; + padding: 1 2; + background: $boost; + width: 1fr; + height: 1fr; + grid-size: 2; + grid-gutter: 1 1; + + + # keyline:thin $success; + + } + } + """ + + def compose(self) -> ComposeResult: + with Grid(): + for project in PROJECTS: + yield Project(project) diff --git a/src/textual/demo2/welcome.py b/src/textual/demo2/welcome.py new file mode 100644 index 0000000000..65b4b68d2e --- /dev/null +++ b/src/textual/demo2/welcome.py @@ -0,0 +1,115 @@ +from importlib.metadata import version + +import httpx + +from textual import work +from textual.app import ComposeResult +from textual.containers import Center, Horizontal, Vertical +from textual.demo2.page import Page +from textual.reactive import reactive +from textual.widgets import Digits, Label, Markdown + +WHAT_IS_TEXTUAL = """\ +### Turbo charge your developers! + +* Build sophisticated applications — fast! +* No front-end skills required. +* Elegant Python API from the developer of [Rich](https://github.com/Textualize/rich). + + +* Deploy Textual as a terminal application, over SSH, *or* a [web application](https://github.com/Textualize/textual-web)! +""" + + +class StarCount(Vertical): + DEFAULT_CSS = """ + StarCount { + dock: top; + height: 5; + border-bottom: hkey $background; + border-top: hkey $background; + layout: horizontal; + Layout { + margin-top: 1; + } + background: $boost; + padding: 0 1; + color: $warning; + Label { + text-style: bold; + } + LoadingIndicator { + background: transparent !important; + } + } + """ + stars = reactive(25251, recompose=True) + forks = reactive(776, recompose=True) + + @work + async def get_stars(self): + try: + async with httpx.AsyncClient() as client: + repository_json = ( + await client.get("https://api.github.com/repos/textualize/textual") + ).json() + self.stars = repository_json["stargazers_count"] + self.forks = repository_json["forks"] + except Exception: + self.notify( + "Unable to get star count (maybe rate-limited)", + title="GitHub stars", + severity="error", + ) + + self.loading = False + + def on_mount(self) -> None: + self.loading = True + self.get_stars() + + def compose(self) -> ComposeResult: + def thousands(number: int) -> str: + if number > 2000: + return f"{number / 1000:.1f}K " + return str(number) + + with Horizontal(): + yield Label("GitHub ★ ") + yield Digits(thousands(self.stars)).with_tooltip( + f"{self.stars} GitHub stars" + ) + yield Label("Forks ") + yield Digits(str(self.forks)).with_tooltip(f"{self.forks} Forks") + + +class WelcomePage(Page): + DEFAULT_CSS = """ + WelcomePage { + align: center middle; + Digits { + width: auto; + + } + Collapsible { + margin: 2 4; + } + Markdown { + background: $boost; + margin: 2 2; + padding: 1 2 0 2; + max-width: 80; + } + } + """ + + def compose(self) -> ComposeResult: + yield StarCount() + with Center(): + yield Label("Textual") + with Center(): + yield Digits(version("textual")) + with Center(): + yield Label("The [i]lean application[/i] framework") + with Center(): + yield Markdown(WHAT_IS_TEXTUAL) diff --git a/src/textual/widget.py b/src/textual/widget.py index 989d9762ce..711aec057d 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -665,6 +665,24 @@ def tooltip(self, tooltip: RenderableType | None): except NoScreen: pass + def with_tooltip(self, tooltip: RenderableType | None) -> Self: + """Chainable method to set a tooltip. + + Example: + ```python + def compose(self) -> ComposeResult: + yield Label("Hello").with_tooltip("A greeting") + ``` + + Args: + tooltip: New tooltip, or `None` to clear the tooltip. + + Returns: + Self. + """ + self.tooltip = tooltip + return self + def allow_focus(self) -> bool: """Check if the widget is permitted to focus. From 42489797371b4958dc578594adca7058f848c09c Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 10 Oct 2024 17:24:15 +0100 Subject: [PATCH 02/43] projects page --- src/textual/app.py | 8 ++- src/textual/css/_styles_builder.py | 14 ++++- src/textual/css/constants.py | 1 + src/textual/demo2/demo_app.py | 54 +++++++------------ src/textual/demo2/page.py | 84 +++++++++++++++++++++++++++++- src/textual/demo2/projects.py | 80 ++++++++++++++++++++-------- src/textual/demo2/welcome.py | 31 ++++++----- src/textual/dom.py | 9 +++- src/textual/widget.py | 8 +++ 9 files changed, 211 insertions(+), 78 deletions(-) diff --git a/src/textual/app.py b/src/textual/app.py index b49cca30d8..0ac65b9fbf 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -372,6 +372,7 @@ class App(Generic[ReturnType], DOMNode): align: center middle; .-maximized { dock: initial !important; + margin: 2 4; } } /* Fade the header title when app is blurred */ @@ -413,6 +414,9 @@ class MyApp(App[None]): ... ``` """ + DEFAULT_MODE: ClassVar[str] = "_default" + """Name of the default mode.""" + SCREENS: ClassVar[dict[str, Callable[[], Screen[Any]]]] = {} """Screens associated with the app for the lifetime of the app.""" @@ -574,9 +578,9 @@ def __init__( self._workers = WorkerManager(self) self.error_console = Console(markup=False, highlight=False, stderr=True) self.driver_class = driver_class or self.get_driver_class() - self._screen_stacks: dict[str, list[Screen[Any]]] = {"_default": []} + self._screen_stacks: dict[str, list[Screen[Any]]] = {self.DEFAULT_MODE: []} """A stack of screens per mode.""" - self._current_mode: str = "_default" + self._current_mode: str = self.DEFAULT_MODE """The current mode the app is in.""" self._sync_available = False diff --git a/src/textual/css/_styles_builder.py b/src/textual/css/_styles_builder.py index 6d1baf45e8..b11cc4810d 100644 --- a/src/textual/css/_styles_builder.py +++ b/src/textual/css/_styles_builder.py @@ -540,10 +540,11 @@ def process_outline_left(self, name: str, tokens: list[Token]) -> None: def process_keyline(self, name: str, tokens: list[Token]) -> None: if not tokens: return - if len(tokens) > 2: + if len(tokens) > 3: self.error(name, tokens[0], keyline_help_text()) keyline_style = "none" keyline_color = Color.parse("green") + keyline_alpha = 1.0 for token in tokens: if token.name == "color": try: @@ -562,7 +563,16 @@ def process_keyline(self, name: str, tokens: list[Token]) -> None: if keyline_style not in VALID_KEYLINE: self.error(name, token, keyline_help_text()) - self.styles._rules["keyline"] = (keyline_style, keyline_color) + elif token.name == "scalar": + alpha_scalar = Scalar.parse(token.value) + if alpha_scalar.unit != Unit.PERCENT: + self.error(name, token, "alpha must be given as a percentage.") + keyline_alpha = alpha_scalar.value / 100.0 + + self.styles._rules["keyline"] = ( + keyline_style, + keyline_color.multiply_alpha(keyline_alpha), + ) def process_offset(self, name: str, tokens: list[Token]) -> None: def offset_error(name: str, token: Token) -> None: diff --git a/src/textual/css/constants.py b/src/textual/css/constants.py index 026e78be45..9189efa0ea 100644 --- a/src/textual/css/constants.py +++ b/src/textual/css/constants.py @@ -69,6 +69,7 @@ "focus-within", "focus", "hover", + "hover-within", "inline", "light", "nocolor", diff --git a/src/textual/demo2/demo_app.py b/src/textual/demo2/demo_app.py index 383d325b6d..09f31e3cf8 100644 --- a/src/textual/demo2/demo_app.py +++ b/src/textual/demo2/demo_app.py @@ -1,41 +1,27 @@ -from textual.app import App, ComposeResult +from textual.app import App from textual.binding import Binding -from textual.demo2.page import Page -from textual.demo2.projects import ProjectsPage -from textual.demo2.welcome import WelcomePage -from textual.screen import Screen -from textual.widgets import Footer +from textual.demo2.projects import ProjectsScreen +from textual.demo2.welcome import WelcomeScreen -class DemoScreen(Screen): - DEFAULT_CSS = """ - DemoScreen { - layout: horizontal; - } - """ +class DemoApp(App): + MODES = {"welcome": WelcomeScreen, "projects": ProjectsScreen} + # DEFAULT_MODE = "welcome" BINDINGS = [ - Binding("1", "page(1)", "page 1", tooltip="Go to page 1"), - Binding("2", "page(2)", "page 2", tooltip="Go to page 2"), - Binding("3", "page(3)", "page 3", tooltip="Go to page 3"), - Binding("4", "page(4)", "page 4", tooltip="Go to page 4"), + Binding( + "w", + "app.switch_mode('welcome')", + "welcome", + tooltip="Show the welcome screen", + ), + Binding( + "p", + "app.switch_mode('projects')", + "projects", + tooltip="A selection of Textual projects", + ), ] - def compose(self) -> ComposeResult: - yield Footer() - yield WelcomePage(id="page1") - yield ProjectsPage(id="page2") - yield Page(id="page3") - yield Page(id="page4") - - @property - def allow_horizontal_scroll(self) -> bool: - return True - - def action_page(self, page: int) -> None: - self.query_one(f"#page{page}").scroll_visible() - - -class DemoApp(App): - def get_default_screen(self) -> Screen: - return DemoScreen() + def on_mount(self) -> None: + self.switch_mode("welcome") diff --git a/src/textual/demo2/page.py b/src/textual/demo2/page.py index f38837e172..b3463b0a27 100644 --- a/src/textual/demo2/page.py +++ b/src/textual/demo2/page.py @@ -1,7 +1,51 @@ -from textual.containers import Vertical +import inspect +from rich.syntax import Syntax -class Page(Vertical): +from textual import work +from textual.app import ComposeResult +from textual.binding import Binding +from textual.containers import ScrollableContainer +from textual.screen import ModalScreen, Screen +from textual.widgets import Static + + +class CodeScreen(ModalScreen): + DEFAULT_CSS = """ + CodeScreen { + #code { + border: heavy $accent; + margin: 2 4; + scrollbar-gutter: stable; + Static { + width: auto; + } + } + } + """ + BINDINGS = [("escape", "dismiss", "Dismiss code")] + + def __init__(self, title: str, code: str) -> None: + super().__init__() + self.code = code + self.title = title + + def compose(self) -> ComposeResult: + with ScrollableContainer(id="code"): + yield Static( + Syntax( + self.code, lexer="python", indent_guides=True, line_numbers=True + ), + expand=True, + ) + + def on_mount(self): + code_widget = self.query_one("#code") + code_widget.border_title = self.title + code_widget.border_subtitle = "Escape to close" + + +class PageScreen(Screen): DEFAULT_CSS = """ Page { width: 100%; @@ -9,3 +53,39 @@ class Page(Vertical): overflow-y: auto; } """ + BINDINGS = [ + Binding( + "c", + "show_code", + "show code", + tooltip="Show the code used to generate this screen", + ) + ] + + @work(thread=True) + def get_code(self, source_file: str) -> str | None: + try: + with open(source_file, "rt") as file_: + return file_.read() + except Exception: + return None + + async def action_show_code(self): + source_file = inspect.getsourcefile(self.__class__) + if source_file is None: + self.notify( + "Could not get the code for this page", + title="Show code", + severity="error", + ) + return + + code = await self.get_code(source_file).wait() + if code is None: + self.notify( + "Could not get the code for this page", + title="Show code", + severity="error", + ) + else: + self.app.push_screen(CodeScreen("Code for this page", code)) diff --git a/src/textual/demo2/projects.py b/src/textual/demo2/projects.py index 24fbeede5f..7043a7b5b5 100644 --- a/src/textual/demo2/projects.py +++ b/src/textual/demo2/projects.py @@ -1,9 +1,10 @@ from dataclasses import dataclass +from textual import events, on from textual.app import ComposeResult -from textual.containers import Grid, Horizontal, Vertical -from textual.demo2.page import Page -from textual.widgets import Label, Static +from textual.containers import Grid, Horizontal, VerticalScroll +from textual.demo2.page import PageScreen +from textual.widgets import Footer, Label, Static @dataclass @@ -19,55 +20,90 @@ class ProjectInfo: "https://posting.sh/", "Posting is a beautiful open-source terminal app for developing and testing APIs.", ) -] * 4 +] * 5 -class Project(Vertical, can_focus=True): +class Link(Label): + """The link in the Project widget.""" + + DEFAULT_CSS = """ + Link { + color: $accent; + text-style: underline; + &:hover { text-style: reverse;} + } + """ + + def __init__(self, url: str) -> None: + super().__init__(url) + self.url = url + self.tooltip = "Click to open Repository URL" + + def on_click(self) -> None: + self.app.open_url(self.url) + + +class Project(VerticalScroll, can_focus=True): + ALLOW_MAXIMIZE = True DEFAULT_CSS = """ Project { - - # margin: 1 2; width: 1fr; - - padding: 1 2; - # background: $boost; - + min-height: 8; + padding: 0 1; border: tall transparent; + opacity: 0.5; &:focus-within { border: tall $accent; background: $boost; + opacity: 1.0; } - #title { - text-style: bold; - } + #title { text-style: bold; } .stars { color: $secondary; text-align: right; width: 1fr; } + .header { height: 1; } + .link { + color: $accent; + text-style: underline; + } + .description { color: $text-muted; } + &.-hover { opacity: 1; } } """ + BINDINGS = [("enter", "open_repository", "open repo")] + def __init__(self, project_info: ProjectInfo) -> None: self.project_info = project_info super().__init__() def compose(self) -> ComposeResult: - with Horizontal(): + with Horizontal(classes="header"): yield Label(self.project_info.title, id="title") yield Label("★ 23K", classes="stars") - yield Static(self.project_info.description) + yield Link(self.project_info.url) + yield Static(self.project_info.description, classes="description") + @on(events.Enter) + @on(events.Leave) + def on_enter(self, event: events.Enter): + event.stop() + self.set_class(self.is_mouse_over, "-hover") -class ProjectsPage(Page): + def action_open_repository(self) -> None: + self.app.open_url(self.project_info.url) + + +class ProjectsScreen(PageScreen): DEFAULT_CSS = """ - ProjectsPage { + ProjectsScreen { layout: grid; margin: 1; Grid { - margin: 1 2; padding: 1 2; background: $boost; @@ -75,9 +111,8 @@ class ProjectsPage(Page): height: 1fr; grid-size: 2; grid-gutter: 1 1; - - - # keyline:thin $success; + hatch: right $primary 50%; + keyline:heavy $background; } } @@ -87,3 +122,4 @@ def compose(self) -> ComposeResult: with Grid(): for project in PROJECTS: yield Project(project) + yield Footer() diff --git a/src/textual/demo2/welcome.py b/src/textual/demo2/welcome.py index 65b4b68d2e..c4b473f5fb 100644 --- a/src/textual/demo2/welcome.py +++ b/src/textual/demo2/welcome.py @@ -5,9 +5,9 @@ from textual import work from textual.app import ComposeResult from textual.containers import Center, Horizontal, Vertical -from textual.demo2.page import Page +from textual.demo2.page import PageScreen from textual.reactive import reactive -from textual.widgets import Digits, Label, Markdown +from textual.widgets import Digits, Footer, Label, Markdown WHAT_IS_TEXTUAL = """\ ### Turbo charge your developers! @@ -29,18 +29,12 @@ class StarCount(Vertical): border-bottom: hkey $background; border-top: hkey $background; layout: horizontal; - Layout { - margin-top: 1; - } + Layout { margin-top: 1; } background: $boost; padding: 0 1; color: $warning; - Label { - text-style: bold; - } - LoadingIndicator { - background: transparent !important; - } + Label { text-style: bold; } + LoadingIndicator { background: transparent !important; } } """ stars = reactive(25251, recompose=True) @@ -66,7 +60,6 @@ async def get_stars(self): def on_mount(self) -> None: self.loading = True - self.get_stars() def compose(self) -> ComposeResult: def thousands(number: int) -> str: @@ -81,11 +74,20 @@ def thousands(number: int) -> str: ) yield Label("Forks ") yield Digits(str(self.forks)).with_tooltip(f"{self.forks} Forks") + self.call_later(self.get_stars) + + def on_click(self) -> None: + self.loading = True + self.refresh(recompose=True) + self.notify( + "Refreshing GitHub stats from API", + title="GitHub stats", + ) -class WelcomePage(Page): +class WelcomeScreen(PageScreen): DEFAULT_CSS = """ - WelcomePage { + WelcomeScreen { align: center middle; Digits { width: auto; @@ -113,3 +115,4 @@ def compose(self) -> ComposeResult: yield Label("The [i]lean application[/i] framework") with Center(): yield Markdown(WHAT_IS_TEXTUAL) + yield Footer() diff --git a/src/textual/dom.py b/src/textual/dom.py index 8cc4e4437b..724505826d 100644 --- a/src/textual/dom.py +++ b/src/textual/dom.py @@ -735,8 +735,13 @@ def screen(self) -> "Screen[object]": from textual.screen import Screen node: MessagePump | None = self - while node is not None and not isinstance(node, Screen): - node = node._parent + try: + while node is not None and not isinstance(node, Screen): + node = node._parent + except AttributeError: + raise RuntimeError( + "Widget is missing attributes; have you called the constructor in your widget class?" + ) from None if not isinstance(node, Screen): raise NoScreen("node has no screen") return node diff --git a/src/textual/widget.py b/src/textual/widget.py index 711aec057d..dc8f7515db 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -340,6 +340,9 @@ class Widget(DOMNode): mouse_hover: Reactive[bool] = Reactive(False, repaint=False) """Is the mouse over this widget? Read only.""" + mouse_hover_within: Reactive[bool] = Reactive(False, repaint=False) + """Is the mouse over this widget or a descendant? Read only.""" + scroll_x: Reactive[float] = Reactive(0.0, repaint=False, layout=False) """The scroll position on the X axis.""" @@ -3259,6 +3262,8 @@ def get_pseudo_classes(self) -> Iterable[str]: app = self.app if self.mouse_hover: yield "hover" + if self.mouse_hover_within: + yield "hover-within" if self.has_focus: yield "focus" else: @@ -3356,6 +3361,9 @@ def post_render(self, renderable: RenderableType) -> ConsoleRenderable: def watch_mouse_hover(self, value: bool) -> None: """Update from CSS if mouse over state changes.""" + for node in self.ancestors_with_self: + if isinstance(node, Widget): + node.mouse_hover_within = value if self._has_hover_style: self._update_styles() From dcea48406749e81129c4df2e68c2f1c67fe516af Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 10 Oct 2024 17:48:27 +0100 Subject: [PATCH 03/43] simplify --- src/textual/demo2/projects.py | 10 ++++++++- src/textual/demo2/welcome.py | 41 +++++++++++++---------------------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/textual/demo2/projects.py b/src/textual/demo2/projects.py index 7043a7b5b5..693c0de4f1 100644 --- a/src/textual/demo2/projects.py +++ b/src/textual/demo2/projects.py @@ -2,6 +2,7 @@ from textual import events, on from textual.app import ComposeResult +from textual.binding import Binding from textual.containers import Grid, Horizontal, VerticalScroll from textual.demo2.page import PageScreen from textual.widgets import Footer, Label, Static @@ -74,7 +75,14 @@ class Project(VerticalScroll, can_focus=True): } """ - BINDINGS = [("enter", "open_repository", "open repo")] + BINDINGS = [ + Binding( + "enter", + "open_repository", + "open repo", + tooltip="Open the GitHub repository in your browser", + ) + ] def __init__(self, project_info: ProjectInfo) -> None: self.project_info = project_info diff --git a/src/textual/demo2/welcome.py b/src/textual/demo2/welcome.py index c4b473f5fb..08116898dc 100644 --- a/src/textual/demo2/welcome.py +++ b/src/textual/demo2/welcome.py @@ -9,7 +9,7 @@ from textual.reactive import reactive from textual.widgets import Digits, Footer, Label, Markdown -WHAT_IS_TEXTUAL = """\ +WHAT_IS_TEXTUAL_MD = """\ ### Turbo charge your developers! * Build sophisticated applications — fast! @@ -22,6 +22,8 @@ class StarCount(Vertical): + """Widget to get and display GitHub star count.""" + DEFAULT_CSS = """ StarCount { dock: top; @@ -29,12 +31,12 @@ class StarCount(Vertical): border-bottom: hkey $background; border-top: hkey $background; layout: horizontal; - Layout { margin-top: 1; } background: $boost; padding: 0 1; color: $warning; Label { text-style: bold; } LoadingIndicator { background: transparent !important; } + Digits { margin-right: 1; } } """ stars = reactive(25251, recompose=True) @@ -42,6 +44,7 @@ class StarCount(Vertical): @work async def get_stars(self): + """Worker to get stars from GitHub API.""" try: async with httpx.AsyncClient() as client: repository_json = ( @@ -55,47 +58,33 @@ async def get_stars(self): title="GitHub stars", severity="error", ) - self.loading = False - def on_mount(self) -> None: - self.loading = True - def compose(self) -> ComposeResult: - def thousands(number: int) -> str: - if number > 2000: - return f"{number / 1000:.1f}K " - return str(number) - with Horizontal(): yield Label("GitHub ★ ") - yield Digits(thousands(self.stars)).with_tooltip( + yield Digits(f"{self.stars / 1000:.1f}K").with_tooltip( f"{self.stars} GitHub stars" ) yield Label("Forks ") yield Digits(str(self.forks)).with_tooltip(f"{self.forks} Forks") + + def update_stars(self) -> None: + self.loading = True self.call_later(self.get_stars) + def on_mount(self) -> None: + self.update_stars() + def on_click(self) -> None: - self.loading = True - self.refresh(recompose=True) - self.notify( - "Refreshing GitHub stats from API", - title="GitHub stats", - ) + self.update_stars() class WelcomeScreen(PageScreen): DEFAULT_CSS = """ WelcomeScreen { align: center middle; - Digits { - width: auto; - - } - Collapsible { - margin: 2 4; - } + Digits { width: auto; } Markdown { background: $boost; margin: 2 2; @@ -114,5 +103,5 @@ def compose(self) -> ComposeResult: with Center(): yield Label("The [i]lean application[/i] framework") with Center(): - yield Markdown(WHAT_IS_TEXTUAL) + yield Markdown(WHAT_IS_TEXTUAL_MD) yield Footer() From f670fbeef4d43dd28e3823410814264901a0637a Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Fri, 11 Oct 2024 19:36:38 +0100 Subject: [PATCH 04/43] regular grid --- src/textual/_arrange.py | 2 +- src/textual/_resolve.py | 6 ++++++ src/textual/color.py | 2 +- src/textual/containers.py | 33 +++++++++++++++++++++++++++++++++ src/textual/demo2/projects.py | 25 ++++++++++++++----------- src/textual/layouts/grid.py | 25 +++++++++++++++++++++++-- src/textual/widget.py | 18 +++++++++++++----- 7 files changed, 91 insertions(+), 20 deletions(-) diff --git a/src/textual/_arrange.py b/src/textual/_arrange.py index 2f2f7fe60d..570a3edd4e 100644 --- a/src/textual/_arrange.py +++ b/src/textual/_arrange.py @@ -90,7 +90,7 @@ def arrange( if layout_widgets: # Arrange layout widgets (i.e. not docked) - layout_placements = widget._layout.arrange( + layout_placements = widget.layout.arrange( widget, layout_widgets, dock_region.size, diff --git a/src/textual/_resolve.py b/src/textual/_resolve.py index 7fbd4751d6..6319adb9c8 100644 --- a/src/textual/_resolve.py +++ b/src/textual/_resolve.py @@ -21,6 +21,7 @@ def resolve( gutter: int, size: Size, viewport: Size, + min_size: int | None = None, ) -> list[tuple[int, int]]: """Resolve a list of dimensions. @@ -62,6 +63,11 @@ def resolve( "list[Fraction]", [fraction for _, fraction in resolved] ) + if min_size is not None: + resolved_fractions = [ + max(Fraction(min_size), fraction) for fraction in resolved_fractions + ] + fraction_gutter = Fraction(gutter) offsets = [0] + [ int(fraction) diff --git a/src/textual/color.py b/src/textual/color.py index a0c2c1a7aa..23c5a4e6dd 100644 --- a/src/textual/color.py +++ b/src/textual/color.py @@ -332,7 +332,7 @@ def __rich_repr__(self) -> rich.repr.Result: yield g yield b yield "a", a, 1.0 - yield "ansi", ansi + yield "ansi", ansi, None def with_alpha(self, alpha: float) -> Color: """Create a new color with the given alpha. diff --git a/src/textual/containers.py b/src/textual/containers.py index 3c2fc1e467..abc4190096 100644 --- a/src/textual/containers.py +++ b/src/textual/containers.py @@ -10,6 +10,8 @@ from typing import ClassVar from textual.binding import Binding, BindingType +from textual.layouts.grid import GridLayout +from textual.reactive import reactive from textual.widget import Widget @@ -155,3 +157,34 @@ class Grid(Widget, inherit_bindings=False): layout: grid; } """ + + min_column_width: reactive[int | None] = reactive(None, layout=True) + + def __init__( + self, + *children: Widget, + name: str | None = None, + id: str | None = None, + classes: str | None = None, + disabled: bool = False, + min_column_width: int | None = None, + ) -> None: + """Initialize a Widget. + + Args: + *children: Child widgets. + name: The name of the widget. + id: The ID of the widget in the DOM. + classes: The CSS classes for the widget. + disabled: Whether the widget is disabled or not. + """ + super().__init__( + *children, name=name, id=id, classes=classes, disabled=disabled + ) + self.min_column_width = min_column_width + + def pre_layout(self) -> None: + if isinstance(self.layout, GridLayout): + if self.layout.min_column_width != self.min_column_width: + self.layout.min_column_width = self.min_column_width + self.refresh(layout=True) diff --git a/src/textual/demo2/projects.py b/src/textual/demo2/projects.py index 693c0de4f1..ea8207140c 100644 --- a/src/textual/demo2/projects.py +++ b/src/textual/demo2/projects.py @@ -3,7 +3,7 @@ from textual import events, on from textual.app import ComposeResult from textual.binding import Binding -from textual.containers import Grid, Horizontal, VerticalScroll +from textual.containers import Grid, Horizontal, Vertical from textual.demo2.page import PageScreen from textual.widgets import Footer, Label, Static @@ -44,25 +44,26 @@ def on_click(self) -> None: self.app.open_url(self.url) -class Project(VerticalScroll, can_focus=True): +class Project(Vertical, can_focus=True): ALLOW_MAXIMIZE = True DEFAULT_CSS = """ Project { width: 1fr; - min-height: 8; + height: auto; padding: 0 1; border: tall transparent; - opacity: 0.5; + opacity: 0.8; &:focus-within { border: tall $accent; - background: $boost; + background: $primary 40%; opacity: 1.0; } #title { text-style: bold; } .stars { color: $secondary; text-align: right; + text-style: bold; width: 1fr; } .header { height: 1; } @@ -108,26 +109,28 @@ def action_open_repository(self) -> None: class ProjectsScreen(PageScreen): DEFAULT_CSS = """ ProjectsScreen { - layout: grid; - + margin: 1; Grid { margin: 1 2; padding: 1 2; background: $boost; width: 1fr; - height: 1fr; + height: auto; grid-size: 2; grid-gutter: 1 1; - hatch: right $primary 50%; - keyline:heavy $background; + hatch: right $accent 80%; + keyline:heavy $secondary; } + Placeholder { + height: auto; + } } """ def compose(self) -> ComposeResult: - with Grid(): + with Grid(min_column_width=40): for project in PROJECTS: yield Project(project) yield Footer() diff --git a/src/textual/layouts/grid.py b/src/textual/layouts/grid.py index 506c45e6d2..5351dedb3d 100644 --- a/src/textual/layouts/grid.py +++ b/src/textual/layouts/grid.py @@ -17,9 +17,13 @@ class GridLayout(Layout): name = "grid" + def __init__(self) -> None: + self.min_column_width: int | None = None + def arrange( self, parent: Widget, children: list[Widget], size: Size ) -> ArrangeResult: + parent.pre_layout() styles = parent.styles row_scalars = styles.grid_rows or ( [Scalar.parse("1fr")] if size.height else [Scalar.parse("auto")] @@ -27,10 +31,21 @@ def arrange( column_scalars = styles.grid_columns or [Scalar.parse("1fr")] gutter_horizontal = styles.grid_gutter_horizontal gutter_vertical = styles.grid_gutter_vertical + table_size_columns = max(1, styles.grid_size_columns) + min_column_width = self.min_column_width + if min_column_width is not None: + container_width = size.width + table_size_columns = max( + 1, + (container_width + gutter_horizontal) + // (min_column_width + gutter_horizontal), + ) + + table_size_columns = min(table_size_columns, len(children)) table_size_rows = styles.grid_size_rows viewport = parent.screen.size - keyline_style, keyline_color = styles.keyline + keyline_style, _keyline_color = styles.keyline offset = (0, 0) gutter_spacing: Spacing | None if keyline_style == "none": @@ -199,7 +214,13 @@ def apply_height_limits(widget: Widget, height: int) -> int: ) column_scalars[column] = Scalar.from_number(width) - columns = resolve(column_scalars, size.width, gutter_vertical, size, viewport) + columns = resolve( + column_scalars, + size.width, + gutter_vertical, + size, + viewport, + ) # Handle any auto rows for row, scalar in enumerate(row_scalars): diff --git a/src/textual/widget.py b/src/textual/widget.py index dc8f7515db..eaddfaf645 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -1417,7 +1417,7 @@ def get_content_width(self, container: Size, viewport: Size) -> int: """ if self.is_container: - width = self._layout.get_content_width(self, container, viewport) + width = self.layout.get_content_width(self, container, viewport) return width cache_key = container.width @@ -1451,8 +1451,8 @@ def get_content_height(self, container: Size, viewport: Size, width: int) -> int The height of the content. """ if self.is_container: - assert self._layout is not None - height = self._layout.get_content_height( + assert self.layout is not None + height = self.layout.get_content_height( self, container, viewport, @@ -2035,7 +2035,7 @@ async def stop_animation(self, attribute: str, complete: bool = True) -> None: await self.app.animator.stop_animation(self, attribute, complete) @property - def _layout(self) -> Layout: + def layout(self) -> Layout: """Get the layout object if set in styles, or a default layout. Returns: @@ -2246,6 +2246,14 @@ def _scroll_to( return scrolled_x or scrolled_y + def pre_layout(self) -> None: + """This method id called prior to a layout operation. + + Implement this method if you want to make updates that should impact + the layout. + + """ + def scroll_to( self, x: float | None = None, @@ -3683,7 +3691,7 @@ def render(self) -> RenderableType: if self.is_container: if self.styles.layout and self.styles.keyline[0] != "none": - return self._layout.render_keyline(self) + return self.layout.render_keyline(self) else: return Blank(self.background_colors[1]) return self.css_identifier_styled From e3665569ce40afe24d61bcd3832bb84573f83c16 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 12 Oct 2024 15:07:00 +0100 Subject: [PATCH 05/43] grid height --- CHANGELOG.md | 6 ++++++ src/textual/css/constants.py | 1 - src/textual/layouts/grid.py | 2 ++ src/textual/widget.py | 5 ----- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2471d5ed43..40e3455332 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## Unreleased + +### Changed + +- Grid will now size children to the maximum height of a row + ## [0.83.0] - 2024-10-10 ### Added diff --git a/src/textual/css/constants.py b/src/textual/css/constants.py index 9189efa0ea..026e78be45 100644 --- a/src/textual/css/constants.py +++ b/src/textual/css/constants.py @@ -69,7 +69,6 @@ "focus-within", "focus", "hover", - "hover-within", "inline", "light", "nocolor", diff --git a/src/textual/layouts/grid.py b/src/textual/layouts/grid.py index 5351dedb3d..07d7fff45e 100644 --- a/src/textual/layouts/grid.py +++ b/src/textual/layouts/grid.py @@ -272,6 +272,8 @@ def apply_height_limits(widget: Widget, height: int) -> int: Fraction(cell_size.width), Fraction(cell_size.height), ) + if column_span == 1 and row_span == 1: + height = cell_height region = ( Region(x, y, int(width + margin.width), int(height + margin.height)) .crop_size(cell_size) diff --git a/src/textual/widget.py b/src/textual/widget.py index eaddfaf645..0d13c6fcac 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -340,9 +340,6 @@ class Widget(DOMNode): mouse_hover: Reactive[bool] = Reactive(False, repaint=False) """Is the mouse over this widget? Read only.""" - mouse_hover_within: Reactive[bool] = Reactive(False, repaint=False) - """Is the mouse over this widget or a descendant? Read only.""" - scroll_x: Reactive[float] = Reactive(0.0, repaint=False, layout=False) """The scroll position on the X axis.""" @@ -3270,8 +3267,6 @@ def get_pseudo_classes(self) -> Iterable[str]: app = self.app if self.mouse_hover: yield "hover" - if self.mouse_hover_within: - yield "hover-within" if self.has_focus: yield "focus" else: From 7451a4d08f956d7a95b483a2448a9624d42f1d22 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 12 Oct 2024 17:14:12 +0100 Subject: [PATCH 06/43] more projects --- src/textual/app.py | 3 +- src/textual/demo2/projects.py | 100 ++++++++++++++++++++++++++++++++-- src/textual/layouts/grid.py | 8 ++- src/textual/widget.py | 3 - 4 files changed, 100 insertions(+), 14 deletions(-) diff --git a/src/textual/app.py b/src/textual/app.py index 0ac65b9fbf..5d60a2eed1 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -371,8 +371,7 @@ class App(Generic[ReturnType], DOMNode): overflow-y: auto !important; align: center middle; .-maximized { - dock: initial !important; - margin: 2 4; + dock: initial !important; } } /* Fade the header title when app is blurred */ diff --git a/src/textual/demo2/projects.py b/src/textual/demo2/projects.py index ea8207140c..ebfe84f6b3 100644 --- a/src/textual/demo2/projects.py +++ b/src/textual/demo2/projects.py @@ -11,17 +11,101 @@ @dataclass class ProjectInfo: title: str + author: str url: str description: str + stars: str PROJECTS = [ ProjectInfo( "Posting", + "Darren Burns", "https://posting.sh/", - "Posting is a beautiful open-source terminal app for developing and testing APIs.", - ) -] * 5 + """A powerful HTTP client that lives in your terminal. + +Posting is an HTTP client, not unlike Postman and Insomnia. As a TUI application, it can be used over SSH and enables efficient keyboard-centric workflows. """, + "4.7k", + ), + ProjectInfo( + "Memray", + "Bloomberg", + "https://github.com/bloomberg/memray", + """Memray is a memory profiler for Python. It can track memory allocations in Python code, in native extension modules, and in the Python interpreter itself. It can generate several different types of reports to help you analyze the captured memory usage data.""", + "13.2k", + ), + ProjectInfo( + "Toolong", + "Will McGugan", + "https://github.com/Textualize/toolong", + """A terminal application to view, tail, merge, and search log files (plus JSONL).""", + "3.1k", + ), + ProjectInfo( + "Dolphie", + "Charles Thompson", + "https://github.com/charles-001/dolphie", + "Your single pane of glass for real-time analytics into MySQL/MariaDB & ProxySQL", + "608", + ), + ProjectInfo( + "Harlequin", + "Ted Conbeer", + "https://harlequin.sh/", + """Portable, powerful, colorful. +An easy, fast, and beautiful database client for the terminal.""", + "3.7k", + ), + ProjectInfo( + "Elia", + "Darren Burns", + "https://github.com/darrenburns/elia", + """A snappy, keyboard-centric terminal user interface for interacting with large language models. +Chat with Claude 3, ChatGPT, and local models like Llama 3, Phi 3, Mistral and Gemma.""", + "1.8k", + ), + ProjectInfo( + "Trogon", + "Textualize", + "https://github.com/Textualize/trogon", + """Auto-generate friendly terminal user interfaces for command line apps. + +Trogon works with the popular Click library for Python, but will support other libraries and languages in the future.""", + "2.5k", + ), + ProjectInfo( + "TFTUI - The Terraform textual UI", + "Ido Avraham", + "https://github.com/idoavrah/terraform-tui", + "TFTUI is a powerful textual UI that empowers users to effortlessly view and interact with their Terraform state.", + "1k", + ), + ProjectInfo( + "RecoverPy", + "Pablo Lecolinet", + "https://github.com/PabloLec/RecoverPy", + """RecoverPy is a powerful tool that leverages your system capabilities to recover lost files. + +Unlike others, you can not only recover deleted files but also overwritten data.""", + "1.3k", + ), + ProjectInfo( + "Frogmouth", + "Dave Pearson", + "https://github.com/Textualize/frogmouth", + """Frogmouth is a Markdown viewer / browser for your terminal, built with Textual. + +Frogmouth can open *.md files locally or via a URL. There is a familiar browser-like navigation stack, history, bookmarks, and table of contents.""", + "2.5k", + ), + ProjectInfo( + "oterm", + "Yiorgis Gozadinos", + "https://github.com/ggozad/oterm", + "The text-based terminal client for Ollama.", + "1k", + ), +] class Link(Label): @@ -53,6 +137,7 @@ class Project(Vertical, can_focus=True): padding: 0 1; border: tall transparent; opacity: 0.8; + box-sizing: border-box; &:focus-within { border: tall $accent; @@ -60,6 +145,7 @@ class Project(Vertical, can_focus=True): opacity: 1.0; } #title { text-style: bold; } + #author { text-style: italic; } .stars { color: $secondary; text-align: right; @@ -92,7 +178,8 @@ def __init__(self, project_info: ProjectInfo) -> None: def compose(self) -> ComposeResult: with Horizontal(classes="header"): yield Label(self.project_info.title, id="title") - yield Label("★ 23K", classes="stars") + yield Label(f"★ {self.project_info.stars}", classes="stars") + yield Label(self.project_info.author, id="author") yield Link(self.project_info.url) yield Static(self.project_info.description, classes="description") @@ -110,15 +197,16 @@ class ProjectsScreen(PageScreen): DEFAULT_CSS = """ ProjectsScreen { - margin: 1; + # margin: 1; Grid { margin: 1 2; padding: 1 2; background: $boost; width: 1fr; height: auto; - grid-size: 2; + # grid-size: 2; grid-gutter: 1 1; + grid-rows: auto; hatch: right $accent 80%; keyline:heavy $secondary; diff --git a/src/textual/layouts/grid.py b/src/textual/layouts/grid.py index 07d7fff45e..df46f88de9 100644 --- a/src/textual/layouts/grid.py +++ b/src/textual/layouts/grid.py @@ -41,8 +41,8 @@ def arrange( (container_width + gutter_horizontal) // (min_column_width + gutter_horizontal), ) + table_size_columns = min(table_size_columns, len(children)) - table_size_columns = min(table_size_columns, len(children)) table_size_rows = styles.grid_size_rows viewport = parent.screen.size keyline_style, _keyline_color = styles.keyline @@ -272,8 +272,10 @@ def apply_height_limits(widget: Widget, height: int) -> int: Fraction(cell_size.width), Fraction(cell_size.height), ) - if column_span == 1 and row_span == 1: - height = cell_height + if len(children) > 1: + height = ( + height if height > cell_size.height else Fraction(cell_size.height) + ) region = ( Region(x, y, int(width + margin.width), int(height + margin.height)) .crop_size(cell_size) diff --git a/src/textual/widget.py b/src/textual/widget.py index 0d13c6fcac..34bad6fa96 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -3364,9 +3364,6 @@ def post_render(self, renderable: RenderableType) -> ConsoleRenderable: def watch_mouse_hover(self, value: bool) -> None: """Update from CSS if mouse over state changes.""" - for node in self.ancestors_with_self: - if isinstance(node, Widget): - node.mouse_hover_within = value if self._has_hover_style: self._update_styles() From ca4af0c41f0c8dce0ea09aa3d3dbed63d38e64e4 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 12 Oct 2024 18:44:24 +0100 Subject: [PATCH 07/43] more projects --- src/textual/demo2/projects.py | 60 +++++++++++++++++------------------ 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/src/textual/demo2/projects.py b/src/textual/demo2/projects.py index ebfe84f6b3..6f88ccfb01 100644 --- a/src/textual/demo2/projects.py +++ b/src/textual/demo2/projects.py @@ -22,16 +22,14 @@ class ProjectInfo: "Posting", "Darren Burns", "https://posting.sh/", - """A powerful HTTP client that lives in your terminal. - -Posting is an HTTP client, not unlike Postman and Insomnia. As a TUI application, it can be used over SSH and enables efficient keyboard-centric workflows. """, + """Posting is an HTTP client, not unlike Postman and Insomnia. As a TUI application, it can be used over SSH and enables efficient keyboard-centric workflows. """, "4.7k", ), ProjectInfo( "Memray", "Bloomberg", "https://github.com/bloomberg/memray", - """Memray is a memory profiler for Python. It can track memory allocations in Python code, in native extension modules, and in the Python interpreter itself. It can generate several different types of reports to help you analyze the captured memory usage data.""", + """Memray is a memory profiler for Python. It can track memory allocations in Python code, in native extension modules, and in the Python interpreter itself.""", "13.2k", ), ProjectInfo( @@ -52,8 +50,7 @@ class ProjectInfo: "Harlequin", "Ted Conbeer", "https://harlequin.sh/", - """Portable, powerful, colorful. -An easy, fast, and beautiful database client for the terminal.""", + """Portable, powerful, colorful. An easy, fast, and beautiful database client for the terminal.""", "3.7k", ), ProjectInfo( @@ -68,9 +65,7 @@ class ProjectInfo: "Trogon", "Textualize", "https://github.com/Textualize/trogon", - """Auto-generate friendly terminal user interfaces for command line apps. - -Trogon works with the popular Click library for Python, but will support other libraries and languages in the future.""", + "Auto-generate friendly terminal user interfaces for command line apps.", "2.5k", ), ProjectInfo( @@ -84,18 +79,14 @@ class ProjectInfo: "RecoverPy", "Pablo Lecolinet", "https://github.com/PabloLec/RecoverPy", - """RecoverPy is a powerful tool that leverages your system capabilities to recover lost files. - -Unlike others, you can not only recover deleted files but also overwritten data.""", + """RecoverPy is a powerful tool that leverages your system capabilities to recover lost files.""", "1.3k", ), ProjectInfo( "Frogmouth", "Dave Pearson", "https://github.com/Textualize/frogmouth", - """Frogmouth is a Markdown viewer / browser for your terminal, built with Textual. - -Frogmouth can open *.md files locally or via a URL. There is a familiar browser-like navigation stack, history, bookmarks, and table of contents.""", + """Frogmouth is a Markdown viewer / browser for your terminal, built with Textual.""", "2.5k", ), ProjectInfo( @@ -105,6 +96,20 @@ class ProjectInfo: "The text-based terminal client for Ollama.", "1k", ), + ProjectInfo( + "logmerger", + "Paul McGuire", + "https://github.com/ptmcg/logmerger", + "logmerger is a TUI for viewing a merged display of multiple log files, merged by timestamp.", + "162", + ), + ProjectInfo( + "doit", + "Murli Tawari", + "https://github.com/kraanzu/dooit", + "A todo manager that you didn't ask for, but needed!", + "2.1k", + ), ] @@ -138,7 +143,6 @@ class Project(Vertical, can_focus=True): border: tall transparent; opacity: 0.8; box-sizing: border-box; - &:focus-within { border: tall $accent; background: $primary 40%; @@ -176,12 +180,13 @@ def __init__(self, project_info: ProjectInfo) -> None: super().__init__() def compose(self) -> ComposeResult: + info = self.project_info with Horizontal(classes="header"): - yield Label(self.project_info.title, id="title") - yield Label(f"★ {self.project_info.stars}", classes="stars") - yield Label(self.project_info.author, id="author") - yield Link(self.project_info.url) - yield Static(self.project_info.description, classes="description") + yield Label(info.title, id="title") + yield Label(f"★ {info.stars}", classes="stars") + yield Label(info.author, id="author") + yield Link(info.url) + yield Static(info.description, classes="description") @on(events.Enter) @on(events.Leave) @@ -195,24 +200,17 @@ def action_open_repository(self) -> None: class ProjectsScreen(PageScreen): DEFAULT_CSS = """ - ProjectsScreen { - - # margin: 1; + ProjectsScreen { Grid { margin: 1 2; padding: 1 2; background: $boost; width: 1fr; - height: auto; - # grid-size: 2; + height: auto; grid-gutter: 1 1; grid-rows: auto; hatch: right $accent 80%; - keyline:heavy $secondary; - - } - Placeholder { - height: auto; + keyline:heavy $secondary; } } """ From 6298acb2a27a3ec0080d8c636c5e3a14baae06b2 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 13 Oct 2024 18:44:33 +0100 Subject: [PATCH 08/43] link widget --- CHANGELOG.md | 5 ++ docs/api/layout.md | 6 +++ docs/examples/widgets/link.py | 23 +++++++++ docs/widget_gallery.md | 7 +++ docs/widgets/link.md | 61 +++++++++++++++++++++++ mkdocs-nav.yml | 2 + src/textual/_arrange.py | 2 +- src/textual/containers.py | 27 ++++++++--- src/textual/css/_style_properties.py | 2 +- src/textual/css/styles.py | 2 +- src/textual/demo2/projects.py | 34 +++---------- src/textual/{_layout.py => layout.py} | 4 +- src/textual/layouts/factory.py | 2 +- src/textual/layouts/grid.py | 11 +++-- src/textual/layouts/horizontal.py | 2 +- src/textual/layouts/vertical.py | 2 +- src/textual/screen.py | 4 +- src/textual/widget.py | 7 ++- src/textual/widgets/__init__.py | 2 + src/textual/widgets/__init__.pyi | 1 + src/textual/widgets/_link.py | 70 +++++++++++++++++++++++++++ tests/test_arrange.py | 2 +- 22 files changed, 229 insertions(+), 49 deletions(-) create mode 100644 docs/api/layout.md create mode 100644 docs/examples/widgets/link.py create mode 100644 docs/widgets/link.md rename src/textual/{_layout.py => layout.py} (97%) create mode 100644 src/textual/widgets/_link.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 40e3455332..387dbcc765 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Grid will now size children to the maximum height of a row + +### Added + +- Added Link widget + ## [0.83.0] - 2024-10-10 ### Added diff --git a/docs/api/layout.md b/docs/api/layout.md new file mode 100644 index 0000000000..06fba9113c --- /dev/null +++ b/docs/api/layout.md @@ -0,0 +1,6 @@ +--- +title: "textual.layout" +--- + + +::: textual.layout diff --git a/docs/examples/widgets/link.py b/docs/examples/widgets/link.py new file mode 100644 index 0000000000..d4d9885622 --- /dev/null +++ b/docs/examples/widgets/link.py @@ -0,0 +1,23 @@ +from textual.app import App, ComposeResult +from textual.widgets import Link + + +class LabelApp(App): + AUTO_FOCUS = None + CSS = """ + Screen { + align: center middle; + } + """ + + def compose(self) -> ComposeResult: + yield Link( + "Go to textualize.io", + url="https://textualize.io", + tooltip="Click me", + ) + + +if __name__ == "__main__": + app = LabelApp() + app.run() diff --git a/docs/widget_gallery.md b/docs/widget_gallery.md index 62d6df383f..f1d26d69fa 100644 --- a/docs/widget_gallery.md +++ b/docs/widget_gallery.md @@ -121,6 +121,13 @@ A simple text label. [Label reference](./widgets/label.md){ .md-button .md-button--primary } +## Link + +A clickable link that opens a URL. + +[Link reference](./widgets/link.md){ .md-button .md-button--primary } + + ## ListView Display a list of items (items may be other widgets). diff --git a/docs/widgets/link.md b/docs/widgets/link.md new file mode 100644 index 0000000000..a719962eec --- /dev/null +++ b/docs/widgets/link.md @@ -0,0 +1,61 @@ +# Link + +!!! tip "Added in version 0.84.0" + +A widget to display a piece of text that opens a URL when clicked, like a web browser link. + +- [x] Focusable +- [ ] Container + + +## Example + +A trivial app with a link. +Clicking the link open's a web-browser—as you might expect! + +=== "Output" + + ```{.textual path="docs/examples/widgets/link.py"} + ``` + +=== "link.py" + + ```python + --8<-- "docs/examples/widgets/link.py" + ``` + + +## Reactive Attributes + +| Name | Type | Default | Description | +| ------ | ----- | ------- | ----------------------------------------- | +| `text` | `str` | `""` | The text of the link. | +| `url` | `str` | `""` | The URL to open when the link is clicked. | + + +## Messages + +This widget sends no messages. + +## Bindings + +The Link widget defines the following bindings: + +::: textual.widgets.Link.BINDINGS + options: + show_root_heading: false + show_root_toc_entry: false + + +## Component classes + +This widget contains no component classes. + + + +--- + + +::: textual.widgets.Link + options: + heading_level: 2 diff --git a/mkdocs-nav.yml b/mkdocs-nav.yml index 53b75f0391..3e5b44f966 100644 --- a/mkdocs-nav.yml +++ b/mkdocs-nav.yml @@ -151,6 +151,7 @@ nav: - "widgets/index.md" - "widgets/input.md" - "widgets/label.md" + - "widgets/link.md" - "widgets/list_item.md" - "widgets/list_view.md" - "widgets/loading_indicator.md" @@ -194,6 +195,7 @@ nav: - "api/filter.md" - "api/fuzzy_matcher.md" - "api/geometry.md" + - "api/layout.md" - "api/lazy.md" - "api/logger.md" - "api/logging.md" diff --git a/src/textual/_arrange.py b/src/textual/_arrange.py index 570a3edd4e..347e8ce09e 100644 --- a/src/textual/_arrange.py +++ b/src/textual/_arrange.py @@ -5,9 +5,9 @@ from operator import attrgetter from typing import TYPE_CHECKING, Iterable, Mapping, Sequence -from textual._layout import DockArrangeResult, WidgetPlacement from textual._partition import partition from textual.geometry import Region, Size, Spacing +from textual.layout import DockArrangeResult, WidgetPlacement if TYPE_CHECKING: from textual.widget import Widget diff --git a/src/textual/containers.py b/src/textual/containers.py index abc4190096..c10e25d275 100644 --- a/src/textual/containers.py +++ b/src/textual/containers.py @@ -10,6 +10,7 @@ from typing import ClassVar from textual.binding import Binding, BindingType +from textual.layout import Layout from textual.layouts.grid import GridLayout from textual.reactive import reactive from textual.widget import Widget @@ -158,6 +159,19 @@ class Grid(Widget, inherit_bindings=False): } """ + +class ItemGrid(Widget, inherit_bindings=False): + """A container with grid layout.""" + + DEFAULT_CSS = """ + ItemGrid { + width: 1fr; + height: 1fr; + layout: grid; + } + """ + + stretch_height: reactive[bool] = reactive(True) min_column_width: reactive[int | None] = reactive(None, layout=True) def __init__( @@ -168,6 +182,7 @@ def __init__( classes: str | None = None, disabled: bool = False, min_column_width: int | None = None, + stretch_height: bool = True, ) -> None: """Initialize a Widget. @@ -181,10 +196,10 @@ def __init__( super().__init__( *children, name=name, id=id, classes=classes, disabled=disabled ) - self.min_column_width = min_column_width + self.set_reactive(ItemGrid.stretch_height, stretch_height) + self.set_reactive(ItemGrid.min_column_width, min_column_width) - def pre_layout(self) -> None: - if isinstance(self.layout, GridLayout): - if self.layout.min_column_width != self.min_column_width: - self.layout.min_column_width = self.min_column_width - self.refresh(layout=True) + def pre_layout(self, layout: Layout) -> None: + if isinstance(layout, GridLayout): + layout.stretch_height = self.stretch_height + layout.min_column_width = self.min_column_width diff --git a/src/textual/css/_style_properties.py b/src/textual/css/_style_properties.py index e8989847eb..3fb548de8a 100644 --- a/src/textual/css/_style_properties.py +++ b/src/textual/css/_style_properties.py @@ -57,7 +57,7 @@ if TYPE_CHECKING: from textual.canvas import CanvasLineType - from textual._layout import Layout + from textual.layout import Layout from textual.css.styles import StylesBase from textual.css.types import AlignHorizontal, AlignVertical, DockEdge, EdgeType diff --git a/src/textual/css/styles.py b/src/textual/css/styles.py index 4e00d74d23..4315c0e2a3 100644 --- a/src/textual/css/styles.py +++ b/src/textual/css/styles.py @@ -69,9 +69,9 @@ from textual.geometry import Offset, Spacing if TYPE_CHECKING: - from textual._layout import Layout from textual.css.types import CSSLocation from textual.dom import DOMNode + from textual.layout import Layout class RulesMap(TypedDict, total=False): diff --git a/src/textual/demo2/projects.py b/src/textual/demo2/projects.py index 6f88ccfb01..60c8ed2f81 100644 --- a/src/textual/demo2/projects.py +++ b/src/textual/demo2/projects.py @@ -3,9 +3,9 @@ from textual import events, on from textual.app import ComposeResult from textual.binding import Binding -from textual.containers import Grid, Horizontal, Vertical +from textual.containers import Horizontal, ItemGrid, Vertical from textual.demo2.page import PageScreen -from textual.widgets import Footer, Label, Static +from textual.widgets import Footer, Label, Link, Static @dataclass @@ -113,27 +113,7 @@ class ProjectInfo: ] -class Link(Label): - """The link in the Project widget.""" - - DEFAULT_CSS = """ - Link { - color: $accent; - text-style: underline; - &:hover { text-style: reverse;} - } - """ - - def __init__(self, url: str) -> None: - super().__init__(url) - self.url = url - self.tooltip = "Click to open Repository URL" - - def on_click(self) -> None: - self.app.open_url(self.url) - - -class Project(Vertical, can_focus=True): +class Project(Vertical, can_focus=True, can_focus_children=False): ALLOW_MAXIMIZE = True DEFAULT_CSS = """ Project { @@ -143,7 +123,7 @@ class Project(Vertical, can_focus=True): border: tall transparent; opacity: 0.8; box-sizing: border-box; - &:focus-within { + &:focus { border: tall $accent; background: $primary 40%; opacity: 1.0; @@ -185,7 +165,7 @@ def compose(self) -> ComposeResult: yield Label(info.title, id="title") yield Label(f"★ {info.stars}", classes="stars") yield Label(info.author, id="author") - yield Link(info.url) + yield Link(info.url, tooltip="Click to open project repository") yield Static(info.description, classes="description") @on(events.Enter) @@ -201,7 +181,7 @@ def action_open_repository(self) -> None: class ProjectsScreen(PageScreen): DEFAULT_CSS = """ ProjectsScreen { - Grid { + ItemGrid { margin: 1 2; padding: 1 2; background: $boost; @@ -216,7 +196,7 @@ class ProjectsScreen(PageScreen): """ def compose(self) -> ComposeResult: - with Grid(min_column_width=40): + with ItemGrid(min_column_width=40): for project in PROJECTS: yield Project(project) yield Footer() diff --git a/src/textual/_layout.py b/src/textual/layout.py similarity index 97% rename from src/textual/_layout.py rename to src/textual/layout.py index 9d261129e1..717197e4d2 100644 --- a/src/textual/_layout.py +++ b/src/textual/layout.py @@ -19,6 +19,8 @@ @dataclass class DockArrangeResult: + """Result of [Layout.arrange][textual.layout.Layout.arrange].""" + placements: list[WidgetPlacement] """A `WidgetPlacement` for every widget to describe its location on screen.""" widgets: set[Widget] @@ -125,7 +127,7 @@ def get_bounds(cls, placements: Iterable[WidgetPlacement]) -> Region: class Layout(ABC): - """Responsible for arranging Widgets in a view and rendering them.""" + """Base class of the object responsible for arranging Widgets within a container.""" name: ClassVar[str] = "" diff --git a/src/textual/layouts/factory.py b/src/textual/layouts/factory.py index e6b0cfb2e1..8667363737 100644 --- a/src/textual/layouts/factory.py +++ b/src/textual/layouts/factory.py @@ -1,6 +1,6 @@ from __future__ import annotations -from textual._layout import Layout +from textual.layout import Layout from textual.layouts.grid import GridLayout from textual.layouts.horizontal import HorizontalLayout from textual.layouts.vertical import VerticalLayout diff --git a/src/textual/layouts/grid.py b/src/textual/layouts/grid.py index df46f88de9..310c8b3128 100644 --- a/src/textual/layouts/grid.py +++ b/src/textual/layouts/grid.py @@ -3,10 +3,10 @@ from fractions import Fraction from typing import TYPE_CHECKING, Iterable -from textual._layout import ArrangeResult, Layout, WidgetPlacement from textual._resolve import resolve from textual.css.scalar import Scalar from textual.geometry import Region, Size, Spacing +from textual.layout import ArrangeResult, Layout, WidgetPlacement if TYPE_CHECKING: from textual.widget import Widget @@ -19,11 +19,12 @@ class GridLayout(Layout): def __init__(self) -> None: self.min_column_width: int | None = None + self.stretch_height: bool = False def arrange( self, parent: Widget, children: list[Widget], size: Size ) -> ArrangeResult: - parent.pre_layout() + parent.pre_layout(self) styles = parent.styles row_scalars = styles.grid_rows or ( [Scalar.parse("1fr")] if size.height else [Scalar.parse("auto")] @@ -272,9 +273,11 @@ def apply_height_limits(widget: Widget, height: int) -> int: Fraction(cell_size.width), Fraction(cell_size.height), ) - if len(children) > 1: + if self.stretch_height and len(children) > 1: height = ( - height if height > cell_size.height else Fraction(cell_size.height) + height + if (height > cell_size.height) + else Fraction(cell_size.height) ) region = ( Region(x, y, int(width + margin.width), int(height + margin.height)) diff --git a/src/textual/layouts/horizontal.py b/src/textual/layouts/horizontal.py index 3ac0d3ca0c..ce032d27a5 100644 --- a/src/textual/layouts/horizontal.py +++ b/src/textual/layouts/horizontal.py @@ -3,9 +3,9 @@ from fractions import Fraction from typing import TYPE_CHECKING -from textual._layout import ArrangeResult, Layout, WidgetPlacement from textual._resolve import resolve_box_models from textual.geometry import Region, Size +from textual.layout import ArrangeResult, Layout, WidgetPlacement if TYPE_CHECKING: from textual.geometry import Spacing diff --git a/src/textual/layouts/vertical.py b/src/textual/layouts/vertical.py index 31c04977a7..c98b0aa35d 100644 --- a/src/textual/layouts/vertical.py +++ b/src/textual/layouts/vertical.py @@ -3,9 +3,9 @@ from fractions import Fraction from typing import TYPE_CHECKING -from textual._layout import ArrangeResult, Layout, WidgetPlacement from textual._resolve import resolve_box_models from textual.geometry import Region, Size +from textual.layout import ArrangeResult, Layout, WidgetPlacement if TYPE_CHECKING: from textual.geometry import Spacing diff --git a/src/textual/screen.py b/src/textual/screen.py index 1f1c3b1d22..ac452ba03f 100644 --- a/src/textual/screen.py +++ b/src/textual/screen.py @@ -34,7 +34,6 @@ from textual._callback import invoke from textual._compositor import Compositor, MapGeometry from textual._context import active_message_pump, visible_screen_stack -from textual._layout import DockArrangeResult from textual._path import ( CSSPathType, _css_path_type_as_list, @@ -50,6 +49,7 @@ from textual.errors import NoWidget from textual.geometry import Offset, Region, Size from textual.keys import key_to_character +from textual.layout import DockArrangeResult from textual.reactive import Reactive from textual.renderables.background_screen import BackgroundScreen from textual.renderables.blank import Blank @@ -1205,8 +1205,8 @@ def _get_inline_height(self, size: Size) -> int: def _screen_resized(self, size: Size): """Called by App when the screen is resized.""" + self._compositor_refresh() self._refresh_layout(size) - self.refresh() def _on_screen_resume(self) -> None: """Screen has resumed.""" diff --git a/src/textual/widget.py b/src/textual/widget.py index 34bad6fa96..f9bca1871a 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -52,7 +52,6 @@ from textual._debug import get_caller_file_and_line from textual._dispatch_key import dispatch_key from textual._easing import DEFAULT_SCROLL_EASING -from textual._layout import Layout from textual._segment_tools import align_lines from textual._styles_cache import StylesCache from textual._types import AnimationLevel @@ -76,6 +75,7 @@ Spacing, clamp, ) +from textual.layout import Layout from textual.layouts.vertical import VerticalLayout from textual.message import Message from textual.messages import CallbackType, Prune @@ -2243,12 +2243,15 @@ def _scroll_to( return scrolled_x or scrolled_y - def pre_layout(self) -> None: + def pre_layout(self, layout: Layout) -> None: """This method id called prior to a layout operation. Implement this method if you want to make updates that should impact the layout. + Args: + layout: The [Layout][textual.layout.Layout] instance that will be used to arrange this widget's children. + """ def scroll_to( diff --git a/src/textual/widgets/__init__.py b/src/textual/widgets/__init__.py index bcaac621c0..ffc861dad1 100644 --- a/src/textual/widgets/__init__.py +++ b/src/textual/widgets/__init__.py @@ -23,6 +23,7 @@ from textual.widgets._input import Input from textual.widgets._key_panel import KeyPanel from textual.widgets._label import Label + from textual.widgets._link import Link from textual.widgets._list_item import ListItem from textual.widgets._list_view import ListView from textual.widgets._loading_indicator import LoadingIndicator @@ -63,6 +64,7 @@ "Input", "KeyPanel", "Label", + "Link", "ListItem", "ListView", "LoadingIndicator", diff --git a/src/textual/widgets/__init__.pyi b/src/textual/widgets/__init__.pyi index b9df9b9195..141c1df46a 100644 --- a/src/textual/widgets/__init__.pyi +++ b/src/textual/widgets/__init__.pyi @@ -12,6 +12,7 @@ from ._help_panel import HelpPanel as HelpPanel from ._input import Input as Input from ._key_panel import KeyPanel as KeyPanel from ._label import Label as Label +from ._link import Link as Link from ._list_item import ListItem as ListItem from ._list_view import ListView as ListView from ._loading_indicator import LoadingIndicator as LoadingIndicator diff --git a/src/textual/widgets/_link.py b/src/textual/widgets/_link.py new file mode 100644 index 0000000000..a7fa41f7e6 --- /dev/null +++ b/src/textual/widgets/_link.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from textual.binding import Binding +from textual.reactive import reactive +from textual.widgets import Static + + +class Link(Static, can_focus=True): + """A simple, clickable link that opens a URL.""" + + DEFAULT_CSS = """ + Link { + width: auto; + height: auto; + min-height: 1; + color: $accent; + text-style: underline; + &:hover { color: $accent-lighten-1; } + &:focus { text-style: bold reverse; } + } + """ + + BINDINGS = [Binding("enter", "select", "Open link")] + """ + | Key(s) | Description | + | :- | :- | + | enter | Open the link in the browser. | + """ + + text: reactive[str] = reactive("", layout=True) + url: reactive[str] = reactive("") + + def __init__( + self, + text: str, + *, + url: str | None = None, + tooltip: str | None = None, + name: str | None = None, + id: str | None = None, + classes: str | None = None, + disabled: bool = False, + ) -> None: + """A link widget. + + Args: + text: Text of the link. + url: A URL to open, when clicked. If `None`, the `text` parameter will also be used as the url. + tooltip: Optional tooltip. + name: Name of widget. + id: ID of Widget. + classes: Space separated list of class names. + disabled: Whether the static is disabled or not. + """ + super().__init__( + text, name=name, id=id, classes=classes, disabled=disabled, markup=False + ) + self.set_reactive(Link.text, text) + self.set_reactive(Link.url, text if url is None else url) + self.tooltip = tooltip + + def watch_text(self, text: str) -> None: + self.update(text) + + def on_click(self) -> None: + self.action_open_link() + + def action_open_link(self) -> None: + if self.url: + self.app.open_url(self.url) diff --git a/tests/test_arrange.py b/tests/test_arrange.py index ffedb6d787..4b671b8334 100644 --- a/tests/test_arrange.py +++ b/tests/test_arrange.py @@ -1,9 +1,9 @@ import pytest from textual._arrange import TOP_Z, arrange -from textual._layout import WidgetPlacement from textual.app import App from textual.geometry import Region, Size, Spacing +from textual.layout import WidgetPlacement from textual.widget import Widget From 5bf30fec7e11d625d560d26a465170dcac0c75c8 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 13 Oct 2024 19:14:50 +0100 Subject: [PATCH 09/43] added text column --- src/textual/demo2/projects.py | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/textual/demo2/projects.py b/src/textual/demo2/projects.py index 60c8ed2f81..266b8cb15b 100644 --- a/src/textual/demo2/projects.py +++ b/src/textual/demo2/projects.py @@ -3,13 +3,15 @@ from textual import events, on from textual.app import ComposeResult from textual.binding import Binding -from textual.containers import Horizontal, ItemGrid, Vertical +from textual.containers import Center, Horizontal, ItemGrid, Vertical, VerticalScroll from textual.demo2.page import PageScreen -from textual.widgets import Footer, Label, Link, Static +from textual.widgets import Footer, Label, Link, Markdown, Static @dataclass class ProjectInfo: + """Dataclass for storing project information.""" + title: str author: str url: str @@ -17,6 +19,15 @@ class ProjectInfo: stars: str +PROJECTS_MD = """\ +# Projects + +There are many amazing Open Source Textual apps available for download. +And many more still in development. + +See below for a small selection! +""" + PROJECTS = [ ProjectInfo( "Posting", @@ -179,8 +190,10 @@ def action_open_repository(self) -> None: class ProjectsScreen(PageScreen): + AUTO_FOCUS = None DEFAULT_CSS = """ - ProjectsScreen { + ProjectsScreen { + align-horizontal: center; ItemGrid { margin: 1 2; padding: 1 2; @@ -192,11 +205,17 @@ class ProjectsScreen(PageScreen): hatch: right $accent 80%; keyline:heavy $secondary; } + Markdown { + max-width: 80; + } } """ def compose(self) -> ComposeResult: - with ItemGrid(min_column_width=40): - for project in PROJECTS: - yield Project(project) + with VerticalScroll(): + with Center(): + yield Markdown(PROJECTS_MD) + with ItemGrid(min_column_width=40): + for project in PROJECTS: + yield Project(project) yield Footer() From dd980b825a43770288834e474dea82d26e8f9fd9 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 14 Oct 2024 12:40:11 +0100 Subject: [PATCH 10/43] fix keyline color --- src/textual/containers.py | 12 ++++++++++++ src/textual/demo2/projects.py | 13 +++++-------- src/textual/demo2/welcome.py | 36 +++++++++++++++++++++-------------- src/textual/layout.py | 2 ++ 4 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/textual/containers.py b/src/textual/containers.py index c10e25d275..2ff19ac3d0 100644 --- a/src/textual/containers.py +++ b/src/textual/containers.py @@ -136,6 +136,18 @@ class Center(Widget, inherit_bindings=False): """ +class Right(Widget, inherit_bindings=False): + """A container which aligns children on the X axis.""" + + DEFAULT_CSS = """ + Right { + align-horizontal: right; + width: 1fr; + height: auto; + } + """ + + class Middle(Widget, inherit_bindings=False): """A container which aligns children on the Y axis.""" diff --git a/src/textual/demo2/projects.py b/src/textual/demo2/projects.py index 266b8cb15b..f39877f865 100644 --- a/src/textual/demo2/projects.py +++ b/src/textual/demo2/projects.py @@ -137,7 +137,7 @@ class Project(Vertical, can_focus=True, can_focus_children=False): &:focus { border: tall $accent; background: $primary 40%; - opacity: 1.0; + opacity: 1.0; } #title { text-style: bold; } #author { text-style: italic; } @@ -195,19 +195,16 @@ class ProjectsScreen(PageScreen): ProjectsScreen { align-horizontal: center; ItemGrid { - margin: 1 2; + margin: 2 4; padding: 1 2; background: $boost; width: 1fr; height: auto; grid-gutter: 1 1; - grid-rows: auto; - hatch: right $accent 80%; - keyline:heavy $secondary; - } - Markdown { - max-width: 80; + grid-rows: auto; + keyline:thin $foreground 50%; } + Markdown { max-width: 80; } } """ diff --git a/src/textual/demo2/welcome.py b/src/textual/demo2/welcome.py index 08116898dc..0730927ca8 100644 --- a/src/textual/demo2/welcome.py +++ b/src/textual/demo2/welcome.py @@ -10,13 +10,18 @@ from textual.widgets import Digits, Footer, Label, Markdown WHAT_IS_TEXTUAL_MD = """\ -### Turbo charge your developers! +# What is Textual? + +**The fastest way to build sophisticated data applications that run *anywhere*.** + +Textual apps can run on virtually anything from a $5 single-board computer upwards. +Deploy as a terminal application, over SSH, or serve as a web application [web application](https://github.com/Textualize/textual-web). + + * Build sophisticated applications — fast! * No front-end skills required. * Elegant Python API from the developer of [Rich](https://github.com/Textualize/rich). - - * Deploy Textual as a terminal application, over SSH, *or* a [web application](https://github.com/Textualize/textual-web)! """ @@ -37,6 +42,9 @@ class StarCount(Vertical): Label { text-style: bold; } LoadingIndicator { background: transparent !important; } Digits { margin-right: 1; } + Label { margin-right: 1; } + #stars { align: center middle; } + #forks { align: right middle; } } """ stars = reactive(25251, recompose=True) @@ -61,19 +69,24 @@ async def get_stars(self): self.loading = False def compose(self) -> ComposeResult: - with Horizontal(): - yield Label("GitHub ★ ") + with Horizontal(id="version"): + yield Label("Version") + yield Digits(version("textual")) + with Horizontal(id="stars"): + yield Label("GitHub ★") yield Digits(f"{self.stars / 1000:.1f}K").with_tooltip( f"{self.stars} GitHub stars" ) - yield Label("Forks ") + with Horizontal(id="forks"): + yield Label("Forks") yield Digits(str(self.forks)).with_tooltip(f"{self.forks} Forks") def update_stars(self) -> None: self.loading = True - self.call_later(self.get_stars) + self.get_stars() def on_mount(self) -> None: + self.tooltip = "Click to refresh" self.update_stars() def on_click(self) -> None: @@ -86,7 +99,7 @@ class WelcomeScreen(PageScreen): align: center middle; Digits { width: auto; } Markdown { - background: $boost; + # background: $boost; margin: 2 2; padding: 1 2 0 2; max-width: 80; @@ -96,12 +109,7 @@ class WelcomeScreen(PageScreen): def compose(self) -> ComposeResult: yield StarCount() - with Center(): - yield Label("Textual") - with Center(): - yield Digits(version("textual")) - with Center(): - yield Label("The [i]lean application[/i] framework") + with Center(): yield Markdown(WHAT_IS_TEXTUAL_MD) yield Footer() diff --git a/src/textual/layout.py b/src/textual/layout.py index 717197e4d2..adb7ab5c2d 100644 --- a/src/textual/layout.py +++ b/src/textual/layout.py @@ -214,6 +214,8 @@ def render_keyline(self, container: Widget) -> StripRenderable: canvas = Canvas(width, height) line_style, keyline_color = container.styles.keyline + if keyline_color: + keyline_color = container.background_colors[0] + keyline_color container_offset = container.content_region.offset From 1e2064a4755cf0d51a13441472d5758a546c965c Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 14 Oct 2024 13:30:35 +0100 Subject: [PATCH 11/43] simplify --- src/textual/demo2/welcome.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/textual/demo2/welcome.py b/src/textual/demo2/welcome.py index 0730927ca8..739eb7d47d 100644 --- a/src/textual/demo2/welcome.py +++ b/src/textual/demo2/welcome.py @@ -53,6 +53,7 @@ class StarCount(Vertical): @work async def get_stars(self): """Worker to get stars from GitHub API.""" + self.loading = True try: async with httpx.AsyncClient() as client: repository_json = ( @@ -74,23 +75,18 @@ def compose(self) -> ComposeResult: yield Digits(version("textual")) with Horizontal(id="stars"): yield Label("GitHub ★") - yield Digits(f"{self.stars / 1000:.1f}K").with_tooltip( - f"{self.stars} GitHub stars" - ) + stars = f"{self.stars / 1000:.1f}K" + yield Digits(stars).with_tooltip(f"{self.stars} GitHub stars") with Horizontal(id="forks"): yield Label("Forks") yield Digits(str(self.forks)).with_tooltip(f"{self.forks} Forks") - def update_stars(self) -> None: - self.loading = True - self.get_stars() - def on_mount(self) -> None: self.tooltip = "Click to refresh" - self.update_stars() + self.get_stars() def on_click(self) -> None: - self.update_stars() + self.get_stars() class WelcomeScreen(PageScreen): @@ -109,7 +105,6 @@ class WelcomeScreen(PageScreen): def compose(self) -> ComposeResult: yield StarCount() - with Center(): yield Markdown(WHAT_IS_TEXTUAL_MD) yield Footer() From bd4688f19dc42b3d22096bbcba615c480e78ab27 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 15 Oct 2024 14:16:35 +0100 Subject: [PATCH 12/43] demo update --- src/textual/demo2/page.py | 6 +- src/textual/demo2/welcome.py | 147 ++++++++++++++++++++++------ src/textual/widgets/_collapsible.py | 2 + src/textual/widgets/_markdown.py | 4 +- 4 files changed, 124 insertions(+), 35 deletions(-) diff --git a/src/textual/demo2/page.py b/src/textual/demo2/page.py index b3463b0a27..f8f85a71f5 100644 --- a/src/textual/demo2/page.py +++ b/src/textual/demo2/page.py @@ -45,7 +45,7 @@ def on_mount(self): code_widget.border_subtitle = "Escape to close" -class PageScreen(Screen): +class PageScreen(Screen, inherit_bindings=True): DEFAULT_CSS = """ Page { width: 100%; @@ -59,7 +59,9 @@ class PageScreen(Screen): "show_code", "show code", tooltip="Show the code used to generate this screen", - ) + ), + Binding("tab", "app.focus_next", "focus next"), + Binding("shift+tab", "app.focus_previous", "focus previous"), ] @work(thread=True) diff --git a/src/textual/demo2/welcome.py b/src/textual/demo2/welcome.py index 739eb7d47d..c97c1db16e 100644 --- a/src/textual/demo2/welcome.py +++ b/src/textual/demo2/welcome.py @@ -4,25 +4,83 @@ from textual import work from textual.app import ComposeResult -from textual.containers import Center, Horizontal, Vertical +from textual.containers import Horizontal, Vertical, VerticalScroll from textual.demo2.page import PageScreen from textual.reactive import reactive -from textual.widgets import Digits, Footer, Label, Markdown +from textual.widgets import Collapsible, Digits, Footer, Label, Markdown WHAT_IS_TEXTUAL_MD = """\ # What is Textual? -**The fastest way to build sophisticated data applications that run *anywhere*.** +**The fastest way to build applications that run *anywhere*.** -Textual apps can run on virtually anything from a $5 single-board computer upwards. -Deploy as a terminal application, over SSH, or serve as a web application [web application](https://github.com/Textualize/textual-web). +Textual apps run on virtually any device from a $5 single-board computer upwards. +Deploy as a terminal application, over SSH, or serve as a [web application](https://github.com/Textualize/textual-web). +""" + + +ABOUT_MD = """\ +The retro look is not just an aesthetic choice! Textual apps have some unique properties that make them preferable for many tasks. + +## Textual interfaces are *snappy* +Even the most modern of web apps can leave the user waiting hundreds of milliseconds or more for a response. +Given their low graphical requirements, Textual interfaces can be far more responsive—no waiting required. +## Reward repeated use +Use the mouse to explore, but Textual apps are keyboard-centric and reward repeated use. +An experience user can operate a Textual app far faster than their web / GUI counterparts. +## Command palette +A builtin command palette with fuzzy searching, puts powerful commands at your fingertips. + +**Try it:** Press `ctrl+p` now. -* Build sophisticated applications — fast! -* No front-end skills required. -* Elegant Python API from the developer of [Rich](https://github.com/Textualize/rich). -* Deploy Textual as a terminal application, over SSH, *or* a [web application](https://github.com/Textualize/textual-web)! +""" + +API_MD = """\ +A modern Python API from the developer of [Rich](https://github.com/Textualize/rich). + +**Hint:** press `C` to view the code for this page. + +## Re-usable components + +Message passing allows widgets to be entirely self contained. + +## Builtin widgets + +A large [library of builtin widgets](https://textual.textualize.io/widget_gallery/), and a growing ecosystem of third party widgets on pyPi +(this content is generated by the builtin [Markdown](https://textual.textualize.io/widget_gallery/#markdown) widget). + + +## Reactive variables + +[Reactivity](https://textual.textualize.io/guide/reactivity/) using Python idioms, keeps your logic separate from display code. + +## Async support + +Built on asyncio, you can easily integrate async libraries while keeping your UI responsive. + +## Concurrency + +Textual's [Workers](https://textual.textualize.io/guide/workers/) provide a far-less error prone interface to +concurrency: both async and threads. +""" + +DEPLOY_MD = """\ +There are a number of ways to deploy and share Textual apps. + +## As a Python library + +Textual apps make be pip installed, via tools such as `pipx` or `uvx`, and other package manager. + +## As a web application + +It takes two lines of code to [serve your Textual app](https://github.com/Textualize/textual-serve) as web application. + +## Managed web application + +With [Textual web](https://github.com/Textualize/textual-serve) you can serve multiple Textual apps on the web, +with zero configuration. Even behind a firewall. """ @@ -41,10 +99,13 @@ class StarCount(Vertical): color: $warning; Label { text-style: bold; } LoadingIndicator { background: transparent !important; } - Digits { margin-right: 1; } + Digits { width: auto; margin-right: 1; } Label { margin-right: 1; } - #stars { align: center middle; } - #forks { align: right middle; } + #stars { align: center top; } + #forks { align: right top; } + align: center top; + &>Horizontal { max-width: 100;} + } """ stars = reactive(25251, recompose=True) @@ -70,16 +131,17 @@ async def get_stars(self): self.loading = False def compose(self) -> ComposeResult: - with Horizontal(id="version"): - yield Label("Version") - yield Digits(version("textual")) - with Horizontal(id="stars"): - yield Label("GitHub ★") - stars = f"{self.stars / 1000:.1f}K" - yield Digits(stars).with_tooltip(f"{self.stars} GitHub stars") - with Horizontal(id="forks"): - yield Label("Forks") - yield Digits(str(self.forks)).with_tooltip(f"{self.forks} Forks") + with Horizontal(): + with Horizontal(id="version"): + yield Label("Version") + yield Digits(version("textual")) + with Horizontal(id="stars"): + yield Label("GitHub ★") + stars = f"{self.stars / 1000:.1f}K" + yield Digits(stars).with_tooltip(f"{self.stars} GitHub stars") + with Horizontal(id="forks"): + yield Label("Forks") + yield Digits(str(self.forks)).with_tooltip(f"{self.forks} Forks") def on_mount(self) -> None: self.tooltip = "Click to refresh" @@ -89,22 +151,47 @@ def on_click(self) -> None: self.get_stars() +class Content(VerticalScroll, can_focus=False): + """Non focusable vertical scroll.""" + + class WelcomeScreen(PageScreen): DEFAULT_CSS = """ WelcomeScreen { - align: center middle; - Digits { width: auto; } - Markdown { - # background: $boost; - margin: 2 2; - padding: 1 2 0 2; - max-width: 80; + align-horizontal: center; + Content { + max-width: 100; + overflow-y: auto; + height: 1fr; + scrollbar-gutter: stable; + MarkdownFence { + height: auto; + max-height: initial; + } + + Collapsible { + padding-right: 0; + &.-collapsed { + padding-bottom: 1; + } + } + Markdown { + margin-right: 1; + padding-right: 1; + } } + } """ def compose(self) -> ComposeResult: yield StarCount() - with Center(): + with Content(): yield Markdown(WHAT_IS_TEXTUAL_MD) + with Collapsible(title="Textual Interfaces"): + yield Markdown(ABOUT_MD) + with Collapsible(title="Textual API"): + yield Markdown(API_MD) + with Collapsible(title="Deploying Textual apps"): + yield Markdown(DEPLOY_MD) yield Footer() diff --git a/src/textual/widgets/_collapsible.py b/src/textual/widgets/_collapsible.py index d7b7359f65..0cb791a7a7 100644 --- a/src/textual/widgets/_collapsible.py +++ b/src/textual/widgets/_collapsible.py @@ -92,6 +92,7 @@ def _watch_collapsed(self, collapsed: bool) -> None: class Collapsible(Widget): """A collapsible container.""" + ALLOW_MAXIMIZE = True collapsed = reactive(True, init=False) title = reactive("Toggle") @@ -202,6 +203,7 @@ def _watch_collapsed(self, collapsed: bool) -> None: self.post_message(self.Collapsed(self)) else: self.post_message(self.Expanded(self)) + self.call_later(self.scroll_visible) def _update_collapsed(self, collapsed: bool) -> None: """Update children to match collapsed state.""" diff --git a/src/textual/widgets/_markdown.py b/src/textual/widgets/_markdown.py index 3e72e4edb3..1e31f5ff30 100644 --- a/src/textual/widgets/_markdown.py +++ b/src/textual/widgets/_markdown.py @@ -421,7 +421,7 @@ class MarkdownOrderedList(MarkdownList): MarkdownOrderedList Vertical { height: auto; - width: 1fr; + width: 1fr; } """ @@ -606,8 +606,6 @@ class MarkdownFence(MarkdownBlock): height: auto; max-height: 20; color: rgb(210,210,210); - - } MarkdownFence > * { From 901db1247a65ebcedafbedd76c83f1e3177cf644 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 15 Oct 2024 16:00:55 +0100 Subject: [PATCH 13/43] Added open links --- CHANGELOG.md | 3 ++- src/textual/demo2/welcome.py | 42 ++++++++++++++++++++------------ src/textual/widgets/_markdown.py | 14 ++++++++++- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 387dbcc765..9620cc02d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,11 +10,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - Grid will now size children to the maximum height of a row - +- Markdown links will be opened with `App.open_url` automatically ### Added - Added Link widget +- Added `open_links` to `Markdown` and `MarkdownViewer` widgets ## [0.83.0] - 2024-10-10 diff --git a/src/textual/demo2/welcome.py b/src/textual/demo2/welcome.py index c97c1db16e..a00a2a36c0 100644 --- a/src/textual/demo2/welcome.py +++ b/src/textual/demo2/welcome.py @@ -33,25 +33,33 @@ ## Command palette A builtin command palette with fuzzy searching, puts powerful commands at your fingertips. -**Try it:** Press `ctrl+p` now. +**Try it:** Press **ctrl+p** now. """ API_MD = """\ A modern Python API from the developer of [Rich](https://github.com/Textualize/rich). -**Hint:** press `C` to view the code for this page. +Well documented, typed, and intuitive. +Textual's API is accessible to Python developers of all skill levels. -## Re-usable components +**Hint:** press **C** to view the code for this page. -Message passing allows widgets to be entirely self contained. +## Built on Rich + +With over 1.4 *billion* downloads, Rich is the most popular terminal library out there. +Textual builds on Rich to add interactivity, and is compatible with Rich renderables. + +## Re-usable widgets + +Textual's widgets are self-contained and re-usable across projects. +Virtually all aspects of a widget's look and feel can be customized to your requirements. ## Builtin widgets A large [library of builtin widgets](https://textual.textualize.io/widget_gallery/), and a growing ecosystem of third party widgets on pyPi (this content is generated by the builtin [Markdown](https://textual.textualize.io/widget_gallery/#markdown) widget). - ## Reactive variables [Reactivity](https://textual.textualize.io/guide/reactivity/) using Python idioms, keeps your logic separate from display code. @@ -64,6 +72,15 @@ Textual's [Workers](https://textual.textualize.io/guide/workers/) provide a far-less error prone interface to concurrency: both async and threads. + +## Testing + +With a comprehensive [testing framework](https://textual.textualize.io/guide/testing/), you can release reliable software, that can be maintained indefinitely. + +## Docs + +Textual has [amazing docs](https://textual.textualize.io/)! + """ DEPLOY_MD = """\ @@ -71,7 +88,7 @@ ## As a Python library -Textual apps make be pip installed, via tools such as `pipx` or `uvx`, and other package manager. +Textual apps make be pip installed, via tools such as `pipx` or `uvx`, and other package managers. ## As a web application @@ -97,15 +114,14 @@ class StarCount(Vertical): background: $boost; padding: 0 1; color: $warning; + #stars { align: center top; } + #forks { align: right top; } Label { text-style: bold; } LoadingIndicator { background: transparent !important; } Digits { width: auto; margin-right: 1; } Label { margin-right: 1; } - #stars { align: center top; } - #forks { align: right top; } align: center top; - &>Horizontal { max-width: 100;} - + &>Horizontal { max-width: 100;} } """ stars = reactive(25251, recompose=True) @@ -168,19 +184,15 @@ class WelcomeScreen(PageScreen): height: auto; max-height: initial; } - Collapsible { padding-right: 0; - &.-collapsed { - padding-bottom: 1; - } + &.-collapsed { padding-bottom: 1; } } Markdown { margin-right: 1; padding-right: 1; } } - } """ diff --git a/src/textual/widgets/_markdown.py b/src/textual/widgets/_markdown.py index 1e31f5ff30..8d0813cfd6 100644 --- a/src/textual/widgets/_markdown.py +++ b/src/textual/widgets/_markdown.py @@ -718,6 +718,7 @@ def __init__( id: str | None = None, classes: str | None = None, parser_factory: Callable[[], MarkdownIt] | None = None, + open_links: bool = True, ): """A Markdown widget. @@ -727,11 +728,13 @@ def __init__( id: The ID of the widget in the DOM. classes: The CSS classes of the widget. parser_factory: A factory function to return a configured MarkdownIt instance. If `None`, a "gfm-like" parser is used. + open_links: Open links automatically. If you set this to `False`, you can handle the [`LinkClicked`][textual.widgets.markdown.Markdown.LinkClicked] events. """ super().__init__(name=name, id=id, classes=classes) self._markdown = markdown self._parser_factory = parser_factory self._table_of_contents: TableOfContentsType | None = None + self._open_links = open_links class TableOfContentsUpdated(Message): """The table of contents was updated.""" @@ -796,6 +799,10 @@ async def _on_mount(self, _: Mount) -> None: if self._markdown is not None: await self.update(self._markdown) + def on_markdown_link_clicked(self, event: LinkClicked) -> None: + if self._open_links: + self.app.open_url(event.href) + def _watch_code_dark_theme(self) -> None: """React to the dark theme being changed.""" if self.app.dark: @@ -1152,6 +1159,7 @@ def __init__( id: str | None = None, classes: str | None = None, parser_factory: Callable[[], MarkdownIt] | None = None, + open_links: bool = True, ): """Create a Markdown Viewer object. @@ -1162,11 +1170,13 @@ def __init__( id: The ID of the widget in the DOM. classes: The CSS classes of the widget. parser_factory: A factory function to return a configured MarkdownIt instance. If `None`, a "gfm-like" parser is used. + open_links: Open links automatically. If you set this to `False`, you can handle the [`LinkClicked`][textual.widgets.markdown.Markdown.LinkClicked] events. """ super().__init__(name=name, id=id, classes=classes) self.show_table_of_contents = show_table_of_contents self._markdown = markdown self._parser_factory = parser_factory + self._open_links = open_links @property def document(self) -> Markdown: @@ -1213,7 +1223,9 @@ def watch_show_table_of_contents(self, show_table_of_contents: bool) -> None: self.set_class(show_table_of_contents, "-show-table-of-contents") def compose(self) -> ComposeResult: - markdown = Markdown(parser_factory=self._parser_factory) + markdown = Markdown( + parser_factory=self._parser_factory, open_links=self._open_links + ) yield MarkdownTableOfContents(markdown) yield markdown From f446576d465136a8cd56795d92356de807530480 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 15 Oct 2024 18:05:11 +0100 Subject: [PATCH 14/43] Added welcome text --- src/textual/demo2/page.py | 6 ++---- src/textual/demo2/welcome.py | 24 ++++++++++++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/textual/demo2/page.py b/src/textual/demo2/page.py index f8f85a71f5..b3463b0a27 100644 --- a/src/textual/demo2/page.py +++ b/src/textual/demo2/page.py @@ -45,7 +45,7 @@ def on_mount(self): code_widget.border_subtitle = "Escape to close" -class PageScreen(Screen, inherit_bindings=True): +class PageScreen(Screen): DEFAULT_CSS = """ Page { width: 100%; @@ -59,9 +59,7 @@ class PageScreen(Screen, inherit_bindings=True): "show_code", "show code", tooltip="Show the code used to generate this screen", - ), - Binding("tab", "app.focus_next", "focus next"), - Binding("shift+tab", "app.focus_previous", "focus previous"), + ) ] @work(thread=True) diff --git a/src/textual/demo2/welcome.py b/src/textual/demo2/welcome.py index a00a2a36c0..e2d0fca456 100644 --- a/src/textual/demo2/welcome.py +++ b/src/textual/demo2/welcome.py @@ -18,6 +18,20 @@ Deploy as a terminal application, over SSH, or serve as a [web application](https://github.com/Textualize/textual-web). """ +WELCOME_MD = """\ +## Welcome keyboard warriors! + +This is a Textual app. Here's what you need to know: + +* **enter** toggles this collapsible widget +* **tab** to focus the next widget +* **shift+tab** to focus the previous widget + +👇 Familiarize yourself with the footer below. + +`Or… click away with the mouse (no judgement).` + +""" ABOUT_MD = """\ The retro look is not just an aesthetic choice! Textual apps have some unique properties that make them preferable for many tasks. @@ -107,7 +121,7 @@ class StarCount(Vertical): DEFAULT_CSS = """ StarCount { dock: top; - height: 5; + height: 6; border-bottom: hkey $background; border-top: hkey $background; layout: horizontal; @@ -148,14 +162,14 @@ async def get_stars(self): def compose(self) -> ComposeResult: with Horizontal(): - with Horizontal(id="version"): + with Vertical(id="version"): yield Label("Version") yield Digits(version("textual")) - with Horizontal(id="stars"): + with Vertical(id="stars"): yield Label("GitHub ★") stars = f"{self.stars / 1000:.1f}K" yield Digits(stars).with_tooltip(f"{self.stars} GitHub stars") - with Horizontal(id="forks"): + with Vertical(id="forks"): yield Label("Forks") yield Digits(str(self.forks)).with_tooltip(f"{self.forks} Forks") @@ -200,6 +214,8 @@ def compose(self) -> ComposeResult: yield StarCount() with Content(): yield Markdown(WHAT_IS_TEXTUAL_MD) + with Collapsible(title="Welcome", collapsed=False): + yield Markdown(WELCOME_MD) with Collapsible(title="Textual Interfaces"): yield Markdown(ABOUT_MD) with Collapsible(title="Textual API"): From 9410b8326a72352317d0dd21734b596f76f6f06b Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 15 Oct 2024 22:00:51 +0100 Subject: [PATCH 15/43] Home screen --- CHANGELOG.md | 1 + src/textual/app.py | 29 ++++++++++++++++++----- src/textual/demo2/demo_app.py | 21 ++++++++-------- src/textual/demo2/{welcome.py => home.py} | 9 +++---- 4 files changed, 40 insertions(+), 20 deletions(-) rename src/textual/demo2/{welcome.py => home.py} (97%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9620cc02d7..ca8f6f1155 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added Link widget - Added `open_links` to `Markdown` and `MarkdownViewer` widgets +- Added `App.DEFAULT_MODE` ## [0.83.0] - 2024-10-10 diff --git a/src/textual/app.py b/src/textual/app.py index 5d60a2eed1..a46ce669e5 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -2176,8 +2176,12 @@ def _init_mode(self, mode: str) -> AwaitMount: stack = self._screen_stacks.get(mode, []) if stack: - await_mount = AwaitMount(stack[0], []) - else: + # Mode already exists + # Return an dummy await + return AwaitMount(stack[0], []) + + if mode in self._modes: + # Mode is defined in MODES _screen = self._modes[mode] if isinstance(_screen, Screen): raise TypeError( @@ -2188,6 +2192,17 @@ def _init_mode(self, mode: str) -> AwaitMount: screen, await_mount = self._get_screen(new_screen) stack.append(screen) self._load_screen_css(screen) + self.refresh_css() + screen.post_message(events.ScreenResume()) + else: + # Mode is not defined + screen = self.get_default_screen() + stack.append(screen) + self._register(self, screen) + screen.post_message(events.ScreenResume()) + await_mount = AwaitMount(stack[0], []) + + screen._screen_resized(self.size) self._screen_stacks[mode] = stack return await_mount @@ -2204,7 +2219,12 @@ def switch_mode(self, mode: str) -> AwaitMount: Raises: UnknownModeError: If trying to switch to an unknown mode. + """ + + if mode == self._current_mode: + return AwaitMount(self.screen, []) + if mode not in self._modes: raise UnknownModeError(f"No known mode {mode!r}") @@ -3506,10 +3526,7 @@ async def on_event(self, event: events.Event) -> None: # Handle input events that haven't been forwarded # If the event has been forwarded it may have bubbled up back to the App if isinstance(event, events.Compose): - screen: Screen[Any] = self.get_default_screen() - self._register(self, screen) - self._screen_stack.append(screen) - screen.post_message(events.ScreenResume()) + await self._init_mode(self._current_mode) await super().on_event(event) elif isinstance(event, events.InputEvent) and not event.is_forwarded: diff --git a/src/textual/demo2/demo_app.py b/src/textual/demo2/demo_app.py index 09f31e3cf8..ea9ec1d364 100644 --- a/src/textual/demo2/demo_app.py +++ b/src/textual/demo2/demo_app.py @@ -1,19 +1,23 @@ from textual.app import App from textual.binding import Binding +from textual.demo2.home import HomeScreen from textual.demo2.projects import ProjectsScreen -from textual.demo2.welcome import WelcomeScreen class DemoApp(App): - MODES = {"welcome": WelcomeScreen, "projects": ProjectsScreen} - # DEFAULT_MODE = "welcome" + """The demo app defines the modes and sets a few bindings.""" + MODES = { + "home": HomeScreen, + "projects": ProjectsScreen, + } + DEFAULT_MODE = "home" BINDINGS = [ Binding( - "w", - "app.switch_mode('welcome')", - "welcome", - tooltip="Show the welcome screen", + "h", + "app.switch_mode('home')", + "home", + tooltip="Show the home screen", ), Binding( "p", @@ -22,6 +26,3 @@ class DemoApp(App): tooltip="A selection of Textual projects", ), ] - - def on_mount(self) -> None: - self.switch_mode("welcome") diff --git a/src/textual/demo2/welcome.py b/src/textual/demo2/home.py similarity index 97% rename from src/textual/demo2/welcome.py rename to src/textual/demo2/home.py index e2d0fca456..a9f0dd543b 100644 --- a/src/textual/demo2/welcome.py +++ b/src/textual/demo2/home.py @@ -26,8 +26,9 @@ * **enter** toggles this collapsible widget * **tab** to focus the next widget * **shift+tab** to focus the previous widget +* **ctrl+p** to summon the command palette -👇 Familiarize yourself with the footer below. +👇 Also see the footer below. `Or… click away with the mouse (no judgement).` @@ -154,7 +155,7 @@ async def get_stars(self): self.forks = repository_json["forks"] except Exception: self.notify( - "Unable to get star count (maybe rate-limited)", + "Unable to update star count (maybe rate-limited)", title="GitHub stars", severity="error", ) @@ -185,9 +186,9 @@ class Content(VerticalScroll, can_focus=False): """Non focusable vertical scroll.""" -class WelcomeScreen(PageScreen): +class HomeScreen(PageScreen): DEFAULT_CSS = """ - WelcomeScreen { + HomeScreen { align-horizontal: center; Content { max-width: 100; From a56225ac47e4612df16013d423053673f35988d6 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 15 Oct 2024 22:05:10 +0100 Subject: [PATCH 16/43] formatting --- src/textual/demo2/home.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/textual/demo2/home.py b/src/textual/demo2/home.py index a9f0dd543b..053880f3e6 100644 --- a/src/textual/demo2/home.py +++ b/src/textual/demo2/home.py @@ -23,10 +23,11 @@ This is a Textual app. Here's what you need to know: -* **enter** toggles this collapsible widget -* **tab** to focus the next widget -* **shift+tab** to focus the previous widget -* **ctrl+p** to summon the command palette +* **enter** `toggle this collapsible widget` +* **tab** `focus the next widget` +* **shift+tab** `focus the previous widget` +* **ctrl+p** `summon the command palette` + 👇 Also see the footer below. From 32cefdffd3d86ee065487412b0e17912d9e67733 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 17 Oct 2024 12:01:44 +0100 Subject: [PATCH 17/43] widgets page --- src/textual/containers.py | 32 +++++++++++-- src/textual/demo2/demo_app.py | 8 ++++ src/textual/demo2/home.py | 9 ++-- src/textual/demo2/page.py | 4 +- src/textual/demo2/projects.py | 7 +-- src/textual/demo2/widgets.py | 86 ++++++++++++++++++++++++++++++++++ src/textual/widget.py | 5 ++ src/textual/widgets/_button.py | 20 ++++++-- 8 files changed, 156 insertions(+), 15 deletions(-) create mode 100644 src/textual/demo2/widgets.py diff --git a/src/textual/containers.py b/src/textual/containers.py index 2ff19ac3d0..3a63368b5e 100644 --- a/src/textual/containers.py +++ b/src/textual/containers.py @@ -75,7 +75,7 @@ class ScrollableContainer(Widget, can_focus=True, inherit_bindings=False): class Vertical(Widget, inherit_bindings=False): - """A container with vertical layout and no scrollbars.""" + """An expanding container with vertical layout and no scrollbars.""" DEFAULT_CSS = """ Vertical { @@ -87,6 +87,19 @@ class Vertical(Widget, inherit_bindings=False): """ +class VerticalGroup(Widget, inherit_bindings=False): + """A non-expanding container with vertical layout and no scrollbars.""" + + DEFAULT_CSS = """ + VerticalGroup { + width: 1fr; + height: auto; + layout: vertical; + overflow: hidden hidden; + } + """ + + class VerticalScroll(ScrollableContainer): """A container with vertical layout and an automatic scrollbar on the Y axis.""" @@ -100,7 +113,7 @@ class VerticalScroll(ScrollableContainer): class Horizontal(Widget, inherit_bindings=False): - """A container with horizontal layout and no scrollbars.""" + """An expanding container with horizontal layout and no scrollbars.""" DEFAULT_CSS = """ Horizontal { @@ -112,6 +125,19 @@ class Horizontal(Widget, inherit_bindings=False): """ +class HorizontalGroup(Widget, inherit_bindings=False): + """A non-expanding container with horizontal layout and no scrollbars.""" + + DEFAULT_CSS = """ + HorizontalGroup { + width: 1fr; + height: auto; + layout: horizontal; + overflow: hidden hidden; + } + """ + + class HorizontalScroll(ScrollableContainer): """A container with horizontal layout and an automatic scrollbar on the X axis.""" @@ -178,7 +204,7 @@ class ItemGrid(Widget, inherit_bindings=False): DEFAULT_CSS = """ ItemGrid { width: 1fr; - height: 1fr; + height: auto; layout: grid; } """ diff --git a/src/textual/demo2/demo_app.py b/src/textual/demo2/demo_app.py index ea9ec1d364..ada9d43fe7 100644 --- a/src/textual/demo2/demo_app.py +++ b/src/textual/demo2/demo_app.py @@ -2,6 +2,7 @@ from textual.binding import Binding from textual.demo2.home import HomeScreen from textual.demo2.projects import ProjectsScreen +from textual.demo2.widgets import WidgetsScreen class DemoApp(App): @@ -10,6 +11,7 @@ class DemoApp(App): MODES = { "home": HomeScreen, "projects": ProjectsScreen, + "widgets": WidgetsScreen, } DEFAULT_MODE = "home" BINDINGS = [ @@ -25,4 +27,10 @@ class DemoApp(App): "projects", tooltip="A selection of Textual projects", ), + Binding( + "w", + "app.switch_mode('widgets')", + "widgets", + tooltip="Test the builtin widgets", + ), ] diff --git a/src/textual/demo2/home.py b/src/textual/demo2/home.py index 053880f3e6..8f24549ec4 100644 --- a/src/textual/demo2/home.py +++ b/src/textual/demo2/home.py @@ -12,10 +12,10 @@ WHAT_IS_TEXTUAL_MD = """\ # What is Textual? -**The fastest way to build applications that run *anywhere*.** +Snappy, keyboard-centric, applications that run in the terminal and [the web](https://github.com/Textualize/textual-web). + +🐍 All you need is Python! -Textual apps run on virtually any device from a $5 single-board computer upwards. -Deploy as a terminal application, over SSH, or serve as a [web application](https://github.com/Textualize/textual-web). """ WELCOME_MD = """\ @@ -191,7 +191,8 @@ class HomeScreen(PageScreen): DEFAULT_CSS = """ HomeScreen { align-horizontal: center; - Content { + Content { + margin: 0 1; max-width: 100; overflow-y: auto; height: 1fr; diff --git a/src/textual/demo2/page.py b/src/textual/demo2/page.py index b3463b0a27..f275c093fb 100644 --- a/src/textual/demo2/page.py +++ b/src/textual/demo2/page.py @@ -47,10 +47,10 @@ def on_mount(self): class PageScreen(Screen): DEFAULT_CSS = """ - Page { + PageScreen { width: 100%; height: 1fr; - overflow-y: auto; + overflow-y: auto; } """ BINDINGS = [ diff --git a/src/textual/demo2/projects.py b/src/textual/demo2/projects.py index f39877f865..b7789237c2 100644 --- a/src/textual/demo2/projects.py +++ b/src/textual/demo2/projects.py @@ -192,7 +192,7 @@ def action_open_repository(self) -> None: class ProjectsScreen(PageScreen): AUTO_FOCUS = None DEFAULT_CSS = """ - ProjectsScreen { + ProjectsScreen { align-horizontal: center; ItemGrid { margin: 2 4; @@ -203,8 +203,9 @@ class ProjectsScreen(PageScreen): grid-gutter: 1 1; grid-rows: auto; keyline:thin $foreground 50%; - } - Markdown { max-width: 80; } + } + Center { background: green; } + Markdown { max-width: 100;} } """ diff --git a/src/textual/demo2/widgets.py b/src/textual/demo2/widgets.py new file mode 100644 index 0000000000..c556fb1060 --- /dev/null +++ b/src/textual/demo2/widgets.py @@ -0,0 +1,86 @@ +from textual import containers +from textual.app import ComposeResult +from textual.demo2.page import PageScreen +from textual.widgets import Button, Footer, Markdown + +WIDGETS_MD = """\ +# Widgets + +The Textual library includes a large number of builtin widgets. + +The following list is *not* exhaustive… + +""" + + +class ButtonsWidget(containers.VerticalGroup): + DEFAULT_CLASSES = "column" + + DEFAULT_CSS = """ + ButtonsWidget { + ItemGrid { width: 100%; margin-bottom: 1; } + Button { width: 1fr; } + } + """ + + BUTTONS_MD = """\ +## Buttons + +A simple button, with a number of semantic styles. +May be rendered unclickable by setting `disabled=True`. + + """ + + def compose(self) -> ComposeResult: + yield Markdown(self.BUTTONS_MD) + with containers.ItemGrid(min_column_width=20): + yield Button( + "Default", + tooltip="The default button style", + action="notify('you pressed Default')", + ) + yield Button( + "Primary", + variant="primary", + tooltip="The primary button style - carry out the core action of the dialog", + action="notify('you pressed Primary')", + ) + yield Button( + "Warning", + variant="warning", + tooltip="The warning button style - warn the user that this isn't a typical button", + action="notify('you pressed Warning')", + ) + yield Button( + "Error", + variant="error", + tooltip="The error button style - clicking is a destructive action", + action="notify('you pressed Error')", + ) + with containers.ItemGrid(min_column_width=20): + yield Button("Default", disabled=True) + yield Button("Primary", variant="primary", disabled=True) + yield Button("Warning", variant="warning", disabled=True) + yield Button("Error", variant="error", disabled=True) + + +class WidgetsScreen(PageScreen): + CSS = """ + WidgetsScreen { + align-horizontal: center; + Markdown { max-width: 100; } + .column { + align:center middle; + &>*{ + max-width: 100; + } + } + } + """ + + def compose(self) -> ComposeResult: + with containers.VerticalScroll(): + with containers.Center(): + yield Markdown(WIDGETS_MD) + yield ButtonsWidget() + yield Footer() diff --git a/src/textual/widget.py b/src/textual/widget.py index f9bca1871a..dd11e47831 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -4145,3 +4145,8 @@ def notify( severity=severity, timeout=timeout, ) + + def action_notify( + self, message: str, title: str = "", severity: str = "information" + ) -> None: + self.notify(message, title=title, severity=severity) diff --git a/src/textual/widgets/_button.py b/src/textual/widgets/_button.py index dc9b4c84f6..67123d8d59 100644 --- a/src/textual/widgets/_button.py +++ b/src/textual/widgets/_button.py @@ -36,7 +36,12 @@ class InvalidButtonVariant(Exception): class Button(Widget, can_focus=True): - """A simple clickable button.""" + """A simple clickable button. + + Clicking the button will send a [Button.Pressed][textual.widgets.Button.Pressed] message, + unless the `action` parameter is provided. + + """ DEFAULT_CSS = """ Button { @@ -155,7 +160,7 @@ class Button(Widget, can_focus=True): """The variant name for the button.""" class Pressed(Message): - """Event sent when a `Button` is pressed. + """Event sent when a `Button` is pressed and there is no Button action. Can be handled using `on_button_pressed` in a subclass of [`Button`][textual.widgets.Button] or in a parent widget in the DOM. @@ -184,6 +189,7 @@ def __init__( classes: str | None = None, disabled: bool = False, tooltip: RenderableType | None = None, + action: str | None = None, ): """Create a Button widget. @@ -195,6 +201,7 @@ def __init__( classes: The CSS classes of the button. disabled: Whether the button is disabled or not. tooltip: Optional tooltip. + action: Optional action to run when clicked. """ super().__init__(name=name, id=id, classes=classes, disabled=disabled) @@ -203,8 +210,10 @@ def __init__( self.label = label self.variant = variant + self.action = action self.active_effect_duration = 0.2 """Amount of time in seconds the button 'press' animation lasts.""" + if tooltip is not None: self.tooltip = tooltip @@ -269,7 +278,12 @@ def press(self) -> Self: # Manage the "active" effect: self._start_active_affect() # ...and let other components know that we've just been clicked: - self.post_message(Button.Pressed(self)) + if self.action is None: + self.post_message(Button.Pressed(self)) + else: + self.call_later( + self.app.run_action, self.action, default_namespace=self._parent + ) return self def _start_active_affect(self) -> None: From 1e2602898c064ed19c80c2b2352449b098b64ada Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 17 Oct 2024 17:07:09 +0100 Subject: [PATCH 18/43] widgets --- CHANGELOG.md | 1 + src/textual/containers.py | 7 ++ src/textual/demo2/demo_app.py | 7 ++ src/textual/demo2/home.py | 2 + src/textual/demo2/projects.py | 9 +-- src/textual/demo2/widgets.py | 116 +++++++++++++++++++++++++++++----- src/textual/layouts/grid.py | 5 ++ 7 files changed, 126 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65c821d873..a9e4a3ca2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `open_links` to `Markdown` and `MarkdownViewer` widgets - Added `background-tint` CSS rule https://github.com/Textualize/textual/pull/5117 - Added `App.DEFAULT_MODE` +- Added `Containers.HorizontalGroup` and `Containers.VerticalGroup` ### Fixed diff --git a/src/textual/containers.py b/src/textual/containers.py index 3a63368b5e..70986b9e47 100644 --- a/src/textual/containers.py +++ b/src/textual/containers.py @@ -211,6 +211,7 @@ class ItemGrid(Widget, inherit_bindings=False): stretch_height: reactive[bool] = reactive(True) min_column_width: reactive[int | None] = reactive(None, layout=True) + regular: reactive[bool] = reactive(False) def __init__( self, @@ -221,6 +222,7 @@ def __init__( disabled: bool = False, min_column_width: int | None = None, stretch_height: bool = True, + regular: bool = False, ) -> None: """Initialize a Widget. @@ -230,14 +232,19 @@ def __init__( id: The ID of the widget in the DOM. classes: The CSS classes for the widget. disabled: Whether the widget is disabled or not. + stretch_height: Expand the height of widgets to the row height. + min_column_width: The smallest permitted column width. + regular: All rows should have the same number of items. """ super().__init__( *children, name=name, id=id, classes=classes, disabled=disabled ) self.set_reactive(ItemGrid.stretch_height, stretch_height) self.set_reactive(ItemGrid.min_column_width, min_column_width) + self.set_reactive(ItemGrid.regular, regular) def pre_layout(self, layout: Layout) -> None: if isinstance(layout, GridLayout): layout.stretch_height = self.stretch_height layout.min_column_width = self.min_column_width + layout.regular = self.regular diff --git a/src/textual/demo2/demo_app.py b/src/textual/demo2/demo_app.py index ada9d43fe7..28307d30b1 100644 --- a/src/textual/demo2/demo_app.py +++ b/src/textual/demo2/demo_app.py @@ -8,6 +8,13 @@ class DemoApp(App): """The demo app defines the modes and sets a few bindings.""" + CSS = """ + .column { + align: center top; + &>*{ max-width: 100; } + } + """ + MODES = { "home": HomeScreen, "projects": ProjectsScreen, diff --git a/src/textual/demo2/home.py b/src/textual/demo2/home.py index 8f24549ec4..989d62cf0a 100644 --- a/src/textual/demo2/home.py +++ b/src/textual/demo2/home.py @@ -1,3 +1,4 @@ +import asyncio from importlib.metadata import version import httpx @@ -148,6 +149,7 @@ async def get_stars(self): """Worker to get stars from GitHub API.""" self.loading = True try: + await asyncio.sleep(1) # Time to admire the loading indicator async with httpx.AsyncClient() as client: repository_json = ( await client.get("https://api.github.com/repos/textualize/textual") diff --git a/src/textual/demo2/projects.py b/src/textual/demo2/projects.py index b7789237c2..045eb24016 100644 --- a/src/textual/demo2/projects.py +++ b/src/textual/demo2/projects.py @@ -125,6 +125,8 @@ class ProjectInfo: class Project(Vertical, can_focus=True, can_focus_children=False): + """Display project information and open repo links.""" + ALLOW_MAXIMIZE = True DEFAULT_CSS = """ Project { @@ -191,7 +193,7 @@ def action_open_repository(self) -> None: class ProjectsScreen(PageScreen): AUTO_FOCUS = None - DEFAULT_CSS = """ + CSS = """ ProjectsScreen { align-horizontal: center; ItemGrid { @@ -203,9 +205,8 @@ class ProjectsScreen(PageScreen): grid-gutter: 1 1; grid-rows: auto; keyline:thin $foreground 50%; - } - Center { background: green; } - Markdown { max-width: 100;} + } + Markdown { margin: 0; padding: 0 2; max-width: 100;} } """ diff --git a/src/textual/demo2/widgets.py b/src/textual/demo2/widgets.py index c556fb1060..cb31b4cf46 100644 --- a/src/textual/demo2/widgets.py +++ b/src/textual/demo2/widgets.py @@ -1,7 +1,7 @@ from textual import containers from textual.app import ComposeResult from textual.demo2.page import PageScreen -from textual.widgets import Button, Footer, Markdown +from textual.widgets import Button, Checkbox, DataTable, Footer, Markdown, RadioSet WIDGETS_MD = """\ # Widgets @@ -13,12 +13,13 @@ """ -class ButtonsWidget(containers.VerticalGroup): - DEFAULT_CLASSES = "column" +class Buttons(containers.VerticalGroup): + """Buttons demo.""" + DEFAULT_CLASSES = "column" DEFAULT_CSS = """ - ButtonsWidget { - ItemGrid { width: 100%; margin-bottom: 1; } + Buttons { + ItemGrid { margin-bottom: 1;} Button { width: 1fr; } } """ @@ -33,7 +34,7 @@ class ButtonsWidget(containers.VerticalGroup): def compose(self) -> ComposeResult: yield Markdown(self.BUTTONS_MD) - with containers.ItemGrid(min_column_width=20): + with containers.ItemGrid(min_column_width=20, regular=True): yield Button( "Default", tooltip="The default button style", @@ -57,30 +58,111 @@ def compose(self) -> ComposeResult: tooltip="The error button style - clicking is a destructive action", action="notify('you pressed Error')", ) - with containers.ItemGrid(min_column_width=20): + with containers.ItemGrid(min_column_width=20, regular=True): yield Button("Default", disabled=True) yield Button("Primary", variant="primary", disabled=True) yield Button("Warning", variant="warning", disabled=True) yield Button("Error", variant="error", disabled=True) +class Checkboxes(containers.VerticalGroup): + DEFAULT_CLASSES = "column" + DEFAULT_CSS = """ + Checkboxes { + height: auto; + Checkbox, RadioButton { width: 1fr; } + ItemGrid { + margin-bottom: 1; + } + } + + """ + + CHECKBOXES_MD = """\ +## Checkboxes + +A checkbox with two states. + + """ + + def compose(self) -> ComposeResult: + yield Markdown(self.CHECKBOXES_MD) + with containers.ItemGrid(min_column_width=20, regular=True): + yield Checkbox("Arrakis") + yield Checkbox("Caladan") + yield Checkbox("Chusuk") + yield Checkbox("Giedi Prime") + + +class RadioSets(containers.VerticalGroup): + DEFAULT_CLASSES = "column" + RADIOSETS_MD = """\ +## Radiosets + +A group of toggles where only once may be active at a time. + +""" + + def compose(self) -> ComposeResult: + yield Markdown(self.RADIOSETS_MD) + yield RadioSet( + "Amanda", + "Connor MacLeod", + "Duncan MacLeod", + "Heather MacLeod", + "Joe Dawson", + "Kurgan, [bold italic red]The[/]", + "Methos", + "Rachel Ellenstein", + "Ramírez", + ) + + +class Datatables(containers.VerticalGroup): + DEFAULT_CLASSES = "column" + DATATABLES_MD = """\ +## Datatables + +A fully-featured + +""" + ROWS = [ + ("lane", "swimmer", "country", "time"), + (4, "Joseph Schooling", "Singapore", 50.39), + (2, "Michael Phelps", "United States", 51.14), + (5, "Chad le Clos", "South Africa", 51.14), + (6, "László Cseh", "Hungary", 51.14), + (3, "Li Zhuhao", "China", 51.26), + (8, "Mehdy Metella", "France", 51.58), + (7, "Tom Shields", "United States", 51.73), + (1, "Aleksandr Sadovnikov", "Russia", 51.84), + (10, "Darren Burns", "Scotland", 51.84), + ] + + def compose(self) -> ComposeResult: + yield Markdown(self.DATATABLES_MD) + with containers.Center(): + yield DataTable() + + def on_mount(self) -> None: + table = self.query_one(DataTable) + table.add_columns(*self.ROWS[0]) + table.add_rows(self.ROWS[1:]) + + class WidgetsScreen(PageScreen): CSS = """ WidgetsScreen { - align-horizontal: center; - Markdown { max-width: 100; } - .column { - align:center middle; - &>*{ - max-width: 100; - } - } + align-horizontal: center; } """ def compose(self) -> ComposeResult: with containers.VerticalScroll(): - with containers.Center(): + with containers.Center(classes="column"): yield Markdown(WIDGETS_MD) - yield ButtonsWidget() + yield Buttons() + yield Checkboxes() + yield RadioSets() + yield Datatables() yield Footer() diff --git a/src/textual/layouts/grid.py b/src/textual/layouts/grid.py index 310c8b3128..d7dfc95896 100644 --- a/src/textual/layouts/grid.py +++ b/src/textual/layouts/grid.py @@ -20,6 +20,7 @@ class GridLayout(Layout): def __init__(self) -> None: self.min_column_width: int | None = None self.stretch_height: bool = False + self.regular = False def arrange( self, parent: Widget, children: list[Widget], size: Size @@ -35,6 +36,7 @@ def arrange( table_size_columns = max(1, styles.grid_size_columns) min_column_width = self.min_column_width + if min_column_width is not None: container_width = size.width table_size_columns = max( @@ -43,6 +45,9 @@ def arrange( // (min_column_width + gutter_horizontal), ) table_size_columns = min(table_size_columns, len(children)) + if self.regular: + while len(children) % table_size_columns and table_size_columns > 1: + table_size_columns -= 1 table_size_rows = styles.grid_size_rows viewport = parent.screen.size From 03e33b8408c1825d0e627e13241afbebe76bbb82 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Fri, 18 Oct 2024 13:38:05 +0100 Subject: [PATCH 19/43] more widgets --- docs/widgets/masked_input.md | 2 +- src/textual/demo2/data.py | 198 +++++++++++++++++++++++++++++++ src/textual/demo2/widgets.py | 134 +++++++++++++++------ src/textual/widgets/__init__.pyi | 1 + 4 files changed, 297 insertions(+), 38 deletions(-) create mode 100644 src/textual/demo2/data.py diff --git a/docs/widgets/masked_input.md b/docs/widgets/masked_input.md index d40350b2c8..426af52937 100644 --- a/docs/widgets/masked_input.md +++ b/docs/widgets/masked_input.md @@ -16,7 +16,7 @@ The example below shows a masked input to ease entering a credit card number. ```{.textual path="docs/examples/widgets/masked_input.py"} ``` -=== "checkbox.py" +=== "masked_input.py" ```python --8<-- "docs/examples/widgets/masked_input.py" diff --git a/src/textual/demo2/data.py b/src/textual/demo2/data.py new file mode 100644 index 0000000000..6023ec83e2 --- /dev/null +++ b/src/textual/demo2/data.py @@ -0,0 +1,198 @@ +COUNTRIES = [ + "Afghanistan", + "Albania", + "Algeria", + "Andorra", + "Angola", + "Antigua and Barbuda", + "Argentina", + "Armenia", + "Australia", + "Austria", + "Azerbaijan", + "Bahamas", + "Bahrain", + "Bangladesh", + "Barbados", + "Belarus", + "Belgium", + "Belize", + "Benin", + "Bhutan", + "Bolivia", + "Bosnia and Herzegovina", + "Botswana", + "Brazil", + "Brunei", + "Bulgaria", + "Burkina Faso", + "Burundi", + "Cabo Verde", + "Cambodia", + "Cameroon", + "Canada", + "Central African Republic", + "Chad", + "Chile", + "China", + "Colombia", + "Comoros", + "Congo", + "Costa Rica", + "Croatia", + "Cuba", + "Cyprus", + "Czech Republic", + "Democratic Republic of the Congo", + "Denmark", + "Djibouti", + "Dominica", + "Dominican Republic", + "East Timor", + "Ecuador", + "Egypt", + "El Salvador", + "Equatorial Guinea", + "Eritrea", + "Estonia", + "Eswatini", + "Ethiopia", + "Fiji", + "Finland", + "France", + "Gabon", + "Gambia", + "Georgia", + "Germany", + "Ghana", + "Greece", + "Grenada", + "Guatemala", + "Guinea", + "Guinea-Bissau", + "Guyana", + "Haiti", + "Honduras", + "Hungary", + "Iceland", + "India", + "Indonesia", + "Iran", + "Iraq", + "Ireland", + "Israel", + "Italy", + "Ivory Coast", + "Jamaica", + "Japan", + "Jordan", + "Kazakhstan", + "Kenya", + "Kiribati", + "Kuwait", + "Kyrgyzstan", + "Laos", + "Latvia", + "Lebanon", + "Lesotho", + "Liberia", + "Libya", + "Liechtenstein", + "Lithuania", + "Luxembourg", + "Madagascar", + "Malawi", + "Malaysia", + "Maldives", + "Mali", + "Malta", + "Marshall Islands", + "Mauritania", + "Mauritius", + "Mexico", + "Micronesia", + "Moldova", + "Monaco", + "Mongolia", + "Montenegro", + "Morocco", + "Mozambique", + "Myanmar", + "Namibia", + "Nauru", + "Nepal", + "Netherlands", + "New Zealand", + "Nicaragua", + "Niger", + "Nigeria", + "North Korea", + "North Macedonia", + "Norway", + "Oman", + "Pakistan", + "Palau", + "Palestine", + "Panama", + "Papua New Guinea", + "Paraguay", + "Peru", + "Philippines", + "Poland", + "Portugal", + "Qatar", + "Romania", + "Russia", + "Rwanda", + "Saint Kitts and Nevis", + "Saint Lucia", + "Saint Vincent and the Grenadines", + "Samoa", + "San Marino", + "Sao Tome and Principe", + "Saudi Arabia", + "Senegal", + "Serbia", + "Seychelles", + "Sierra Leone", + "Singapore", + "Slovakia", + "Slovenia", + "Solomon Islands", + "Somalia", + "South Africa", + "South Korea", + "South Sudan", + "Spain", + "Sri Lanka", + "Sudan", + "Suriname", + "Sweden", + "Switzerland", + "Syria", + "Taiwan", + "Tajikistan", + "Tanzania", + "Thailand", + "Togo", + "Tonga", + "Trinidad and Tobago", + "Tunisia", + "Turkey", + "Turkmenistan", + "Tuvalu", + "Uganda", + "Ukraine", + "United Arab Emirates", + "United Kingdom", + "United States", + "Uruguay", + "Uzbekistan", + "Vanuatu", + "Vatican City", + "Venezuela", + "Vietnam", + "Yemen", + "Zambia", + "Zimbabwe", +] diff --git a/src/textual/demo2/widgets.py b/src/textual/demo2/widgets.py index cb31b4cf46..c31686b85f 100644 --- a/src/textual/demo2/widgets.py +++ b/src/textual/demo2/widgets.py @@ -1,7 +1,20 @@ from textual import containers from textual.app import ComposeResult +from textual.demo2.data import COUNTRIES from textual.demo2.page import PageScreen -from textual.widgets import Button, Checkbox, DataTable, Footer, Markdown, RadioSet +from textual.suggester import SuggestFromList +from textual.widgets import ( + Button, + Checkbox, + DataTable, + Footer, + Input, + Label, + Markdown, + MaskedInput, + RadioButton, + RadioSet, +) WIDGETS_MD = """\ # Widgets @@ -71,51 +84,39 @@ class Checkboxes(containers.VerticalGroup): Checkboxes { height: auto; Checkbox, RadioButton { width: 1fr; } - ItemGrid { - margin-bottom: 1; - } + &>HorizontalGroup > * { width: 1fr; } } """ CHECKBOXES_MD = """\ -## Checkboxes +## Checkboxes, Radio buttons, and Radio sets -A checkbox with two states. +Checkboxes to toggle booleans. +Radio buttons for exclusive booleans. +Radio sets for a managed set of options where only a single option may be selected. """ def compose(self) -> ComposeResult: yield Markdown(self.CHECKBOXES_MD) - with containers.ItemGrid(min_column_width=20, regular=True): - yield Checkbox("Arrakis") - yield Checkbox("Caladan") - yield Checkbox("Chusuk") - yield Checkbox("Giedi Prime") - - -class RadioSets(containers.VerticalGroup): - DEFAULT_CLASSES = "column" - RADIOSETS_MD = """\ -## Radiosets - -A group of toggles where only once may be active at a time. - -""" - - def compose(self) -> ComposeResult: - yield Markdown(self.RADIOSETS_MD) - yield RadioSet( - "Amanda", - "Connor MacLeod", - "Duncan MacLeod", - "Heather MacLeod", - "Joe Dawson", - "Kurgan, [bold italic red]The[/]", - "Methos", - "Rachel Ellenstein", - "Ramírez", - ) + with containers.HorizontalGroup(): + with containers.VerticalGroup(): + yield Checkbox("Arrakis") + yield Checkbox("Caladan") + yield RadioButton("Chusuk") + yield RadioButton("Giedi Prime") + yield RadioSet( + "Amanda", + "Connor MacLeod", + "Duncan MacLeod", + "Heather MacLeod", + "Joe Dawson", + "Kurgan, [bold italic red]The[/]", + "Methos", + "Rachel Ellenstein", + "Ramírez", + ) class Datatables(containers.VerticalGroup): @@ -123,7 +124,8 @@ class Datatables(containers.VerticalGroup): DATATABLES_MD = """\ ## Datatables -A fully-featured +A fully-featured DataTable, with cell, row, and columns cursors. +Cells may be individually styled, and may include Rich renderables. """ ROWS = [ @@ -150,6 +152,59 @@ def on_mount(self) -> None: table.add_rows(self.ROWS[1:]) +class Inputs(containers.VerticalGroup): + DEFAULT_CLASSES = "column" + INPUTS_MD = """\ +## Inputs and MaskedInputs + +Text input fields, with placeholder text, validation, and auto-complete. +Build for intuitive and user-friendly forms. + +""" + DEFAULT_CSS = """ + Inputs { + Grid { + background: $boost; + padding: 1 2; + height: auto; + grid-size: 2; + grid-gutter: 1; + grid-columns: auto 1fr; + border: tall blank; + &:focus-within { + border: tall $accent; + } + Label { + width: 100%; + margin: 1; + text-align: right; + } + } + } + """ + + def compose(self) -> ComposeResult: + yield Markdown(self.INPUTS_MD) + with containers.Grid(): + yield Label("Free") + yield Input(placeholder="Type anything here") + yield Label("Number") + yield Input( + type="number", placeholder="Type a number here", valid_empty=True + ) + yield Label("Credit card") + yield MaskedInput( + "9999-9999-9999-9999;0", + tooltip="Obviously not your real credit card!", + valid_empty=True, + ) + yield Label("Country") + yield Input( + suggester=SuggestFromList(COUNTRIES, case_sensitive=False), + placeholder="Country", + ) + + class WidgetsScreen(PageScreen): CSS = """ WidgetsScreen { @@ -157,12 +212,17 @@ class WidgetsScreen(PageScreen): } """ + BINDINGS = [("escape", "unfocus")] + def compose(self) -> ComposeResult: with containers.VerticalScroll(): with containers.Center(classes="column"): yield Markdown(WIDGETS_MD) yield Buttons() yield Checkboxes() - yield RadioSets() yield Datatables() + yield Inputs() yield Footer() + + def action_unfocus(self) -> None: + self.set_focus(None) diff --git a/src/textual/widgets/__init__.pyi b/src/textual/widgets/__init__.pyi index 141c1df46a..907ae843b8 100644 --- a/src/textual/widgets/__init__.pyi +++ b/src/textual/widgets/__init__.pyi @@ -19,6 +19,7 @@ from ._loading_indicator import LoadingIndicator as LoadingIndicator from ._log import Log as Log from ._markdown import Markdown as Markdown from ._markdown import MarkdownViewer as MarkdownViewer +from ._masked_input import MaskedInput as MaskedInput from ._option_list import OptionList as OptionList from ._placeholder import Placeholder as Placeholder from ._pretty import Pretty as Pretty From f9aba5da970b7c9278330d1514611e1038778e01 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 19 Oct 2024 19:31:27 +0100 Subject: [PATCH 20/43] universal selector now doesn't match scrollbars --- CHANGELOG.md | 1 + src/textual/css/model.py | 2 +- src/textual/css/parse.py | 1 - src/textual/css/stylesheet.py | 1 + src/textual/demo2/widgets.py | 7 ++++++- src/textual/scrollbar.py | 2 ++ 6 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5743d67b9..cb5dda1e16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Grid will now size children to the maximum height of a row - Markdown links will be opened with `App.open_url` automatically +- The universal selector (`*`) will now not match widgets with the class `-textual-system` (scrollbars, notifications etc) ### Added diff --git a/src/textual/css/model.py b/src/textual/css/model.py index e752b3fc1d..05c64d9a79 100644 --- a/src/textual/css/model.py +++ b/src/textual/css/model.py @@ -56,7 +56,7 @@ def _check_universal(name: str, node: DOMNode) -> bool: Returns: `True` if the selector matches. """ - return True + return not node.has_class("-textual-system") def _check_type(name: str, node: DOMNode) -> bool: diff --git a/src/textual/css/parse.py b/src/textual/css/parse.py index e7fd0c0353..d0365c825f 100644 --- a/src/textual/css/parse.py +++ b/src/textual/css/parse.py @@ -170,7 +170,6 @@ def parse_rule_set( while True: token = next(tokens) - token_name = token.name if token_name in ("whitespace", "declaration_end"): continue diff --git a/src/textual/css/stylesheet.py b/src/textual/css/stylesheet.py index 6ad76e44db..b366efe603 100644 --- a/src/textual/css/stylesheet.py +++ b/src/textual/css/stylesheet.py @@ -255,6 +255,7 @@ def _parse_rules( tie_breaker=tie_breaker, ) ) + except TokenError: raise except Exception as error: diff --git a/src/textual/demo2/widgets.py b/src/textual/demo2/widgets.py index c31686b85f..7f943be3dc 100644 --- a/src/textual/demo2/widgets.py +++ b/src/textual/demo2/widgets.py @@ -208,7 +208,12 @@ def compose(self) -> ComposeResult: class WidgetsScreen(PageScreen): CSS = """ WidgetsScreen { - align-horizontal: center; + align-horizontal: center; + & > VerticalScroll > * { + &:last-of-type { margin-bottom: 2; } + &:even { background: $boost; } + padding-bottom: 1; + } } """ diff --git a/src/textual/scrollbar.py b/src/textual/scrollbar.py index 79ee1c5d9e..78aa968d00 100644 --- a/src/textual/scrollbar.py +++ b/src/textual/scrollbar.py @@ -246,6 +246,8 @@ class MyScrollBarRender(ScrollBarRender): ... ``` """ + DEFAULT_CLASSES = "-textual-system" + def __init__( self, vertical: bool = True, name: str | None = None, *, thickness: int = 1 ) -> None: From 4afdb3f6d02416fcae0c28fcab8dd4ba583b74fa Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 20 Oct 2024 13:44:56 +0100 Subject: [PATCH 21/43] maor widgets --- src/textual/demo2/home.py | 11 ++++--- src/textual/demo2/widgets.py | 49 ++++++++++++++++++++++++++++++- src/textual/renderables/digits.py | 16 ++++++++-- 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/textual/demo2/home.py b/src/textual/demo2/home.py index 989d62cf0a..53611c7aaf 100644 --- a/src/textual/demo2/home.py +++ b/src/textual/demo2/home.py @@ -192,10 +192,13 @@ class Content(VerticalScroll, can_focus=False): class HomeScreen(PageScreen): DEFAULT_CSS = """ HomeScreen { - align-horizontal: center; - Content { - margin: 0 1; - max-width: 100; + + Content { + align-horizontal: center; + & > * { + max-width: 100; + } + margin: 0 1; overflow-y: auto; height: 1fr; scrollbar-gutter: stable; diff --git a/src/textual/demo2/widgets.py b/src/textual/demo2/widgets.py index 7f943be3dc..8f71326f7d 100644 --- a/src/textual/demo2/widgets.py +++ b/src/textual/demo2/widgets.py @@ -7,11 +7,15 @@ Button, Checkbox, DataTable, + Digits, Footer, Input, Label, + ListItem, + ListView, Markdown, MaskedInput, + OptionList, RadioButton, RadioSet, ) @@ -176,7 +180,7 @@ class Inputs(containers.VerticalGroup): } Label { width: 100%; - margin: 1; + padding: 1; text-align: right; } } @@ -205,6 +209,48 @@ def compose(self) -> ComposeResult: ) +class ListViews(containers.VerticalGroup): + DEFAULT_CLASSES = "column" + LISTS_MD = """\ +## List Views and Option Lists + +A List View turns any widget in to a user-navigable and selectable list. +An Option List for a for field to present a list of strings to select from. + + """ + + DEFAULT_CSS = """\ + ListViews { + ListView { + width: 1fr; + height: auto; + margin: 0 2; + background: $panel; + } + OptionList { + max-height: 15; + } + + Digits { + padding: 1 2; + width: 1fr; + + } + } + + """ + + def compose(self) -> ComposeResult: + yield Markdown(self.LISTS_MD) + with containers.HorizontalGroup(): + yield ListView( + ListItem(Digits("$50.00")), + ListItem(Digits("$100.00")), + ListItem(Digits("$500.00")), + ) + yield OptionList(*COUNTRIES) + + class WidgetsScreen(PageScreen): CSS = """ WidgetsScreen { @@ -227,6 +273,7 @@ def compose(self) -> ComposeResult: yield Checkboxes() yield Datatables() yield Inputs() + yield ListViews() yield Footer() def action_unfocus(self) -> None: diff --git a/src/textual/renderables/digits.py b/src/textual/renderables/digits.py index 9fd2044404..8d7fb6fefb 100644 --- a/src/textual/renderables/digits.py +++ b/src/textual/renderables/digits.py @@ -5,7 +5,7 @@ from rich.segment import Segment from rich.style import Style, StyleType -DIGITS = " 0123456789+-^x:ABCDEF" +DIGITS = " 0123456789+-^x:ABCDEF$£" DIGITS3X3_BOLD = """\ @@ -73,7 +73,12 @@ ╭─╴ ├─ ╵ - +╭╫╴ +╰╫╮ +╶╫╯ +╭─╮ +┼─ +╰─╴ """.splitlines() @@ -144,7 +149,12 @@ ╭─╴ ├─ ╵ - +╭╫╴ +╰╫╮ +╶╫╯ +╭─╮ +┼─ +╰─╴ """.splitlines() From d0467589ef6014e844a60c60d9899fc20920e28f Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 20 Oct 2024 14:09:52 +0100 Subject: [PATCH 22/43] change --- CHANGELOG.md | 1 + src/textual/demo2/widgets.py | 11 ++--------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb5dda1e16..fbb23a29eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `background-tint` CSS rule https://github.com/Textualize/textual/pull/5117 - Added `App.DEFAULT_MODE` - Added `Containers.HorizontalGroup` and `Containers.VerticalGroup` +- Added `$` and `£` symbols to Digits ### Fixed diff --git a/src/textual/demo2/widgets.py b/src/textual/demo2/widgets.py index 8f71326f7d..94ff42031f 100644 --- a/src/textual/demo2/widgets.py +++ b/src/textual/demo2/widgets.py @@ -227,15 +227,8 @@ class ListViews(containers.VerticalGroup): margin: 0 2; background: $panel; } - OptionList { - max-height: 15; - } - - Digits { - padding: 1 2; - width: 1fr; - - } + OptionList { max-height: 15; } + Digits { padding: 1 2; width: 1fr; } } """ From 4f9ad305084d5c3b0e6a19001bb939079cc00eff Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 20 Oct 2024 17:03:32 +0100 Subject: [PATCH 23/43] updated digits --- CHANGELOG.md | 2 +- src/textual/demo2/widgets.py | 4 ++-- src/textual/renderables/digits.py | 16 +++++++++++----- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbb23a29eb..818a205e82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `background-tint` CSS rule https://github.com/Textualize/textual/pull/5117 - Added `App.DEFAULT_MODE` - Added `Containers.HorizontalGroup` and `Containers.VerticalGroup` -- Added `$` and `£` symbols to Digits +- Added `$`, `£`, `€` symbols to Digits ### Fixed diff --git a/src/textual/demo2/widgets.py b/src/textual/demo2/widgets.py index 94ff42031f..2d6e29b05e 100644 --- a/src/textual/demo2/widgets.py +++ b/src/textual/demo2/widgets.py @@ -238,8 +238,8 @@ def compose(self) -> ComposeResult: with containers.HorizontalGroup(): yield ListView( ListItem(Digits("$50.00")), - ListItem(Digits("$100.00")), - ListItem(Digits("$500.00")), + ListItem(Digits("£100.00")), + ListItem(Digits("€500.00")), ) yield OptionList(*COUNTRIES) diff --git a/src/textual/renderables/digits.py b/src/textual/renderables/digits.py index 8d7fb6fefb..dcd18ff959 100644 --- a/src/textual/renderables/digits.py +++ b/src/textual/renderables/digits.py @@ -5,7 +5,7 @@ from rich.segment import Segment from rich.style import Style, StyleType -DIGITS = " 0123456789+-^x:ABCDEF$£" +DIGITS = " 0123456789+-^x:ABCDEF$£€" DIGITS3X3_BOLD = """\ @@ -77,8 +77,11 @@ ╰╫╮ ╶╫╯ ╭─╮ -┼─ -╰─╴ +╪═ +└─╴ +╭─╮ +╪═ +╰─╯ """.splitlines() @@ -153,8 +156,11 @@ ╰╫╮ ╶╫╯ ╭─╮ -┼─ -╰─╴ +╪═ +└─╴ +╭─╮ +╪═ +╰─╯ """.splitlines() From 0ffcd6fb82429269965ae88abcf9ed6f1f802feb Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 20 Oct 2024 17:28:29 +0100 Subject: [PATCH 24/43] digit tweaks --- src/textual/demo2/widgets.py | 3 +-- src/textual/renderables/digits.py | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/textual/demo2/widgets.py b/src/textual/demo2/widgets.py index 2d6e29b05e..6a1eded388 100644 --- a/src/textual/demo2/widgets.py +++ b/src/textual/demo2/widgets.py @@ -260,8 +260,7 @@ class WidgetsScreen(PageScreen): def compose(self) -> ComposeResult: with containers.VerticalScroll(): - with containers.Center(classes="column"): - yield Markdown(WIDGETS_MD) + yield Markdown(WIDGETS_MD, classes="column") yield Buttons() yield Checkboxes() yield Datatables() diff --git a/src/textual/renderables/digits.py b/src/textual/renderables/digits.py index dcd18ff959..0285e30f3e 100644 --- a/src/textual/renderables/digits.py +++ b/src/textual/renderables/digits.py @@ -173,6 +173,8 @@ class Digits: """ + REPLACEMENTS = str.maketrans({".": "•"}) + def __init__(self, text: str, style: StyleType = "") -> None: self._text = text self._style = style @@ -202,7 +204,7 @@ def render(self, style: Style) -> RenderResult: else: digits = DIGITS3X3 - for character in self._text: + for character in self._text.translate(self.REPLACEMENTS): try: position = DIGITS.index(character) * 3 except ValueError: From 6c63918dbdd0eed521080f814909294f16aa878f Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 20 Oct 2024 20:12:23 +0100 Subject: [PATCH 25/43] currency tweaks --- src/textual/renderables/digits.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/textual/renderables/digits.py b/src/textual/renderables/digits.py index 0285e30f3e..f751387cf9 100644 --- a/src/textual/renderables/digits.py +++ b/src/textual/renderables/digits.py @@ -73,12 +73,12 @@ ╭─╴ ├─ ╵ -╭╫╴ +╭╫╮ ╰╫╮ -╶╫╯ +╰╫╯ ╭─╮ ╪═ -└─╴ +┴─╴ ╭─╮ ╪═ ╰─╯ @@ -152,12 +152,12 @@ ╭─╴ ├─ ╵ -╭╫╴ +╭╫╮ ╰╫╮ -╶╫╯ +╰╫╯ ╭─╮ ╪═ -└─╴ +┴─╴ ╭─╮ ╪═ ╰─╯ From 0ce8988a67e3bba0ebb2a875780c4d1d2dc418b4 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 22 Oct 2024 15:49:50 +0100 Subject: [PATCH 26/43] hover effects --- src/textual/app.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/textual/app.py b/src/textual/app.py index 843d4affd7..f07c9b9c16 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -775,6 +775,11 @@ def __init__( self._previous_inline_height: int | None = None """Size of previous inline update.""" + self._paused_hover_effects: bool = False + """Have the hover effects been paused?""" + + self._hover_effects_timer: Timer | None = None + if self.ENABLE_COMMAND_PALETTE: for _key, binding in self._bindings: if binding.action in {"command_palette", "app.command_palette"}: @@ -2693,12 +2698,28 @@ def set_focus(self, widget: Widget | None, scroll_visible: bool = True) -> None: """ self.screen.set_focus(widget, scroll_visible) + def _pause_hover_effects(self): + self._paused_hover_effects = True + + def _resume_hover_effects(self): + if self._paused_hover_effects: + self._paused_hover_effects = False + try: + widget, _ = self.screen.get_widget_at(*self.mouse_position) + except NoWidget: + pass + else: + if widget is not self.mouse_over: + self._set_mouse_over(widget) + def _set_mouse_over(self, widget: Widget | None) -> None: """Called when the mouse is over another widget. Args: widget: Widget under mouse, or None for no widgets. """ + if self._paused_hover_effects: + return if widget is None: if self.mouse_over is not None: try: From 444a878bd8a4fb2f68f35075e862f69597fa2642 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 22 Oct 2024 17:03:58 +0100 Subject: [PATCH 27/43] hover effects timer --- src/textual/app.py | 11 +++++++++++ src/textual/widget.py | 3 +++ 2 files changed, 14 insertions(+) diff --git a/src/textual/app.py b/src/textual/app.py index f07c9b9c16..ae77d5ebe8 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -2699,11 +2699,22 @@ def set_focus(self, widget: Widget | None, scroll_visible: bool = True) -> None: self.screen.set_focus(widget, scroll_visible) def _pause_hover_effects(self): + """Pause any hover effects based on Enter and Leave events for 200ms.""" self._paused_hover_effects = True + if self._hover_effects_timer is None: + self._hover_effects_timer = self.set_interval( + 0.2, self._resume_hover_effects + ) + else: + self._hover_effects_timer.reset() + self._hover_effects_timer.resume() def _resume_hover_effects(self): + """Resume sending Enter and Leave for hover effects.""" if self._paused_hover_effects: self._paused_hover_effects = False + if self._hover_effects_timer is not None: + self._hover_effects_timer.pause() try: widget, _ = self.screen.get_widget_at(*self.mouse_position) except NoWidget: diff --git a/src/textual/widget.py b/src/textual/widget.py index a60c6aee9a..ccc9e14f25 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -2353,6 +2353,9 @@ def _scroll_to( if on_complete is not None: self.call_after_refresh(on_complete) + if scrolled_x or scrolled_y: + self.app._pause_hover_effects() + return scrolled_x or scrolled_y def pre_layout(self, layout: Layout) -> None: From 09b636b257effef15bfd123dfa100e545608cc89 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 16 Oct 2024 16:41:34 +0100 Subject: [PATCH 28/43] tint fix --- src/textual/color.py | 25 +++++++++++++++++++++++++ src/textual/dom.py | 12 ++++++------ tests/snapshot_tests/test_snapshots.py | 22 +++++++++++++++++----- tests/test_color.py | 24 ++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 11 deletions(-) diff --git a/src/textual/color.py b/src/textual/color.py index 23c5a4e6dd..10d5d070e3 100644 --- a/src/textual/color.py +++ b/src/textual/color.py @@ -399,6 +399,31 @@ def blend( new_alpha, ) + @lru_cache(maxsize=1024) + def tint(self, color: Color) -> Color: + """Apply a tint to a color. + + Similar to blend, but combines color and alpha. + + Args: + color: A color with alpha component. + + Returns: + New color + """ + r2, g2, b2, a2, ansi2 = color + if ansi2 is not None: + return color + r1, g1, b1, a1, ansi1 = self + if ansi1 is not None: + return color + return Color( + int(r1 + (r2 - r1) * a2), + int(g1 + (g2 - g1) * a2), + int(b1 + (b2 - b1) * a2), + a1, + ) + def __add__(self, other: object) -> Color: if isinstance(other, Color): return self.blend(other, other.a, 1.0) diff --git a/src/textual/dom.py b/src/textual/dom.py index 5cab83d230..aa2fdb3983 100644 --- a/src/textual/dom.py +++ b/src/textual/dom.py @@ -1036,11 +1036,11 @@ def rich_style(self) -> Style: has_rule = styles.has_rule opacity *= styles.opacity if has_rule("background"): - text_background = ( - background + styles.background + styles.background_tint + text_background = background + styles.background.tint( + styles.background_tint ) background += ( - styles.background + styles.background_tint + styles.background.tint(styles.background_tint) ).multiply_alpha(opacity) else: text_background = background @@ -1129,7 +1129,7 @@ def background_colors(self) -> tuple[Color, Color]: for node in reversed(self.ancestors_with_self): styles = node.styles base_background = background - background += styles.background + styles.background_tint + background += styles.background.tint(styles.background_tint) return (base_background, background) @property @@ -1145,7 +1145,7 @@ def _opacity_background_colors(self) -> tuple[Color, Color]: styles = node.styles base_background = background opacity *= styles.opacity - background += (styles.background + styles.background_tint).multiply_alpha( + background += styles.background.tint(styles.background_tint).multiply_alpha( opacity ) return (base_background, background) @@ -1162,7 +1162,7 @@ def colors(self) -> tuple[Color, Color, Color, Color]: for node in reversed(self.ancestors_with_self): styles = node.styles base_background = background - background += styles.background + styles.background_tint + background += styles.background.tint(styles.background_tint) if styles.has_rule("color"): base_color = color if styles.auto_color: diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index a9d3a9ec0b..6793129e50 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -2314,15 +2314,27 @@ def compose(self) -> ComposeResult: def test_background_tint(snap_compare): + """Test background tint with alpha.""" + + # The screen background is dark blue + # The vertical is 20% white + # With no background tint, the verticals will be a light blue + # With a 100% tint, the vertical should be 20% red plus the blue (i.e. purple) + + # tl;dr you should see 4 bars, blue at the top, purple at the bottom, and two shades in betweenm + class BackgroundTintApp(App): CSS = """ + Screen { + background: rgb(0,0,100) + } Vertical { - background: $panel; + background: rgba(255,255,255,0.2); } - #tint1 { background-tint: $foreground 0%; } - #tint2 { background-tint: $foreground 33%; } - #tint3 { background-tint: $foreground 66%; } - #tint4 { background-tint: $foreground 100% } + #tint1 { background-tint: rgb(255,0,0) 0%; } + #tint2 { background-tint: rgb(255,0,0) 33%; } + #tint3 { background-tint: rgb(255,0,0) 66%; } + #tint4 { background-tint: rgb(255,0,0) 100% } """ def compose(self) -> ComposeResult: diff --git a/tests/test_color.py b/tests/test_color.py index e13a7bf726..00e7270116 100644 --- a/tests/test_color.py +++ b/tests/test_color.py @@ -265,3 +265,27 @@ def test_is_transparent(): assert not Color(20, 20, 30, a=0.01).is_transparent assert not Color(20, 20, 30, a=1).is_transparent assert not Color(20, 20, 30, 0, ansi=1).is_transparent + + +@pytest.mark.parametrize( + "base,tint,expected", + [ + ( + Color(0, 0, 0), + Color(10, 20, 30), + Color(10, 20, 30), + ), + ( + Color(0, 0, 0, 0.5), + Color(255, 255, 255, 0.5), + Color(127, 127, 127, 0.5), + ), + ( + Color(100, 0, 0, 0.2), + Color(0, 100, 0, 0.5), + Color(50, 50, 0, 0.2), + ), + ], +) +def test_tint(base: Color, tint: Color, expected: Color) -> None: + assert base.tint(tint) == expected From e3bb452df0ea0bd1d8bdff231afcda37f1299eaa Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 16 Oct 2024 16:49:14 +0100 Subject: [PATCH 29/43] snapshot --- src/textual/color.py | 4 +- .../test_snapshots/test_background_tint.svg | 116 +++++++++--------- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/textual/color.py b/src/textual/color.py index 10d5d070e3..a93eaa4288 100644 --- a/src/textual/color.py +++ b/src/textual/color.py @@ -413,10 +413,10 @@ def tint(self, color: Color) -> Color: """ r2, g2, b2, a2, ansi2 = color if ansi2 is not None: - return color + return self r1, g1, b1, a1, ansi1 = self if ansi1 is not None: - return color + return self return Color( int(r1 + (r2 - r1) * a2), int(g1 + (g2 - g1) * a2), diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_background_tint.svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_background_tint.svg index 22b4fda3db..e37daad3d7 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_background_tint.svg +++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_background_tint.svg @@ -19,134 +19,134 @@ font-weight: 700; } - .terminal-2147534319-matrix { + .terminal-3859065499-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2147534319-title { + .terminal-3859065499-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2147534319-r1 { fill: #e2e3e3 } -.terminal-2147534319-r2 { fill: #c5c8c6 } -.terminal-2147534319-r3 { fill: #ebebec } -.terminal-2147534319-r4 { fill: #f3f3f4 } -.terminal-2147534319-r5 { fill: #fcfcfc } + .terminal-3859065499-r1 { fill: #e4e4ee } +.terminal-3859065499-r2 { fill: #c5c8c6 } +.terminal-3859065499-r3 { fill: #e4e2ec } +.terminal-3859065499-r4 { fill: #e4e0ea } +.terminal-3859065499-r5 { fill: #e4dde8 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - BackgroundTintApp + BackgroundTintApp - - - - 0%                                                                               - - - - - -33%                                                                              - - - - - -66%                                                                              - - - - - -100%                                                                             - - - - + + + + 0%                                                                               + + + + + +33%                                                                              + + + + + +66%                                                                              + + + + + +100%                                                                             + + + + From e6c97c7f9040c6698fbf3da2bcc551e4a763dc6a Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 16 Oct 2024 16:50:10 +0100 Subject: [PATCH 30/43] reorder --- src/textual/color.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/textual/color.py b/src/textual/color.py index a93eaa4288..2de8aa1bf5 100644 --- a/src/textual/color.py +++ b/src/textual/color.py @@ -411,12 +411,13 @@ def tint(self, color: Color) -> Color: Returns: New color """ - r2, g2, b2, a2, ansi2 = color - if ansi2 is not None: - return self + r1, g1, b1, a1, ansi1 = self if ansi1 is not None: return self + r2, g2, b2, a2, ansi2 = color + if ansi2 is not None: + return self return Color( int(r1 + (r2 - r1) * a2), int(g1 + (g2 - g1) * a2), From 89b112e2b307199cd4f81249fca18fcd967fa7fa Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 16 Oct 2024 16:51:57 +0100 Subject: [PATCH 31/43] typo --- tests/snapshot_tests/test_snapshots.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index 6793129e50..0516429c6b 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -2321,7 +2321,7 @@ def test_background_tint(snap_compare): # With no background tint, the verticals will be a light blue # With a 100% tint, the vertical should be 20% red plus the blue (i.e. purple) - # tl;dr you should see 4 bars, blue at the top, purple at the bottom, and two shades in betweenm + # tl;dr you should see 4 bars, blue at the top, purple at the bottom, and two shades in between class BackgroundTintApp(App): CSS = """ From bc69bdfca7e8bf5b20237e93197dc880e72e4925 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 22 Oct 2024 12:14:33 +0100 Subject: [PATCH 32/43] fix infinite loop in cropping --- src/textual/strip.py | 3 +++ src/textual/widgets/_text_area.py | 4 +--- tests/test_strip.py | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/textual/strip.py b/src/textual/strip.py index 71bfd78089..c7644898f8 100644 --- a/src/textual/strip.py +++ b/src/textual/strip.py @@ -372,10 +372,13 @@ def crop(self, start: int, end: int | None = None) -> Strip: Returns: A new Strip. """ + start = max(0, start) end = self.cell_length if end is None else min(self.cell_length, end) if start == 0 and end == self.cell_length: return self + if end <= start: + return Strip([], 0) cache_key = (start, end) cached = self._crop_cache.get(cache_key) if cached is not None: diff --git a/src/textual/widgets/_text_area.py b/src/textual/widgets/_text_area.py index b147c27ee5..0e7da87543 100644 --- a/src/textual/widgets/_text_area.py +++ b/src/textual/widgets/_text_area.py @@ -1236,9 +1236,7 @@ def render_line(self, y: int) -> Strip: # Crop the line to show only the visible part (some may be scrolled out of view) if not self.soft_wrap: - text_strip = text_strip.crop( - scroll_x, scroll_x + virtual_width - gutter_width - ) + text_strip = text_strip.crop(scroll_x, scroll_x + virtual_width) # Stylize the line the cursor is currently on. if cursor_row == line_index: diff --git a/tests/test_strip.py b/tests/test_strip.py index 7f6d9bae63..b88c68ecc5 100644 --- a/tests/test_strip.py +++ b/tests/test_strip.py @@ -131,7 +131,7 @@ def test_crop(): assert Strip([Segment("foo")]).crop(1, 3) == Strip([Segment("oo")]) assert Strip([Segment("foo")]).crop(1, 2) == Strip([Segment("o")]) - assert Strip([Segment("foo")]).crop(1, 1) == Strip([Segment("")]) + assert Strip([Segment("foo")]).crop(1, 1) == Strip([]) assert Strip([Segment("foo💩"), Segment("b💩ar"), Segment("ba💩z")]).crop( 1, 6 From 6c395331feda69af89a75fb77c3566e76314bd40 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 22 Oct 2024 13:01:10 +0100 Subject: [PATCH 33/43] version bump --- CHANGELOG.md | 4 +++- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 818a205e82..fb17ee2645 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## Unreleased +## [0.84.0] ### Changed @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Fixed `RadioSet` not being scrollable https://github.com/Textualize/textual/issues/5100 +- Fixed infinite loop in TextArea https://github.com/Textualize/textual/pull/5154 ### Added @@ -2469,6 +2470,7 @@ https://textual.textualize.io/blog/2022/11/08/version-040/#version-040 - New handler system for messages that doesn't require inheritance - Improved traceback handling +[0.84.0]: https://github.com/Textualize/textual/compare/v0.83.0...v0.84.0 [0.83.0]: https://github.com/Textualize/textual/compare/v0.82.0...v0.83.0 [0.82.0]: https://github.com/Textualize/textual/compare/v0.81.0...v0.82.0 [0.81.0]: https://github.com/Textualize/textual/compare/v0.80.1...v0.81.0 diff --git a/pyproject.toml b/pyproject.toml index 3b88d9a1a6..ea2cf45af2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "textual" -version = "0.83.0" +version = "0.84.0" homepage = "https://github.com/Textualize/textual" repository = "https://github.com/Textualize/textual" documentation = "https://textual.textualize.io/" From b4fa813a46bbdeaad2f02030b3f5533ca96a2874 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 22 Oct 2024 13:02:53 +0100 Subject: [PATCH 34/43] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb17ee2645..0e8d38f745 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [0.84.0] +## [0.84.0] - 2024-10-22 ### Changed From 536d2dd67b04b46ce92fd35398a4a6311a380fb1 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 22 Oct 2024 13:09:15 +0100 Subject: [PATCH 35/43] depenencies --- poetry.lock | 1401 +++++++++++++++++++++++++++++---------------------- 1 file changed, 785 insertions(+), 616 deletions(-) diff --git a/poetry.lock b/poetry.lock index a8e6709daf..d971d5cc4b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,114 +1,114 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" -version = "2.4.0" +version = "2.4.3" description = "Happy Eyeballs for asyncio" optional = false python-versions = ">=3.8" files = [ - {file = "aiohappyeyeballs-2.4.0-py3-none-any.whl", hash = "sha256:7ce92076e249169a13c2f49320d1967425eaf1f407522d707d59cac7628d62bd"}, - {file = "aiohappyeyeballs-2.4.0.tar.gz", hash = "sha256:55a1714f084e63d49639800f95716da97a1f173d46a16dfcfda0016abb93b6b2"}, + {file = "aiohappyeyeballs-2.4.3-py3-none-any.whl", hash = "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572"}, + {file = "aiohappyeyeballs-2.4.3.tar.gz", hash = "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586"}, ] [[package]] name = "aiohttp" -version = "3.10.5" +version = "3.10.10" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3"}, - {file = "aiohttp-3.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6"}, - {file = "aiohttp-3.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f1f1c75c395991ce9c94d3e4aa96e5c59c8356a15b1c9231e783865e2772699"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f7acae3cf1a2a2361ec4c8e787eaaa86a94171d2417aae53c0cca6ca3118ff6"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94c4381ffba9cc508b37d2e536b418d5ea9cfdc2848b9a7fea6aebad4ec6aac1"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c31ad0c0c507894e3eaa843415841995bf8de4d6b2d24c6e33099f4bc9fc0d4f"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0912b8a8fadeb32ff67a3ed44249448c20148397c1ed905d5dac185b4ca547bb"}, - {file = "aiohttp-3.10.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d93400c18596b7dc4794d48a63fb361b01a0d8eb39f28800dc900c8fbdaca91"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d00f3c5e0d764a5c9aa5a62d99728c56d455310bcc288a79cab10157b3af426f"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d742c36ed44f2798c8d3f4bc511f479b9ceef2b93f348671184139e7d708042c"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:814375093edae5f1cb31e3407997cf3eacefb9010f96df10d64829362ae2df69"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8224f98be68a84b19f48e0bdc14224b5a71339aff3a27df69989fa47d01296f3"}, - {file = "aiohttp-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9a487ef090aea982d748b1b0d74fe7c3950b109df967630a20584f9a99c0683"}, - {file = "aiohttp-3.10.5-cp310-cp310-win32.whl", hash = "sha256:d9ef084e3dc690ad50137cc05831c52b6ca428096e6deb3c43e95827f531d5ef"}, - {file = "aiohttp-3.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:66bf9234e08fe561dccd62083bf67400bdbf1c67ba9efdc3dac03650e97c6088"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8c6a4e5e40156d72a40241a25cc226051c0a8d816610097a8e8f517aeacd59a2"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c634a3207a5445be65536d38c13791904fda0748b9eabf908d3fe86a52941cf"}, - {file = "aiohttp-3.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4aff049b5e629ef9b3e9e617fa6e2dfeda1bf87e01bcfecaf3949af9e210105e"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1942244f00baaacaa8155eca94dbd9e8cc7017deb69b75ef67c78e89fdad3c77"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e04a1f2a65ad2f93aa20f9ff9f1b672bf912413e5547f60749fa2ef8a644e061"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f2bfc0032a00405d4af2ba27f3c429e851d04fad1e5ceee4080a1c570476697"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:424ae21498790e12eb759040bbb504e5e280cab64693d14775c54269fd1d2bb7"}, - {file = "aiohttp-3.10.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:975218eee0e6d24eb336d0328c768ebc5d617609affaca5dbbd6dd1984f16ed0"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4120d7fefa1e2d8fb6f650b11489710091788de554e2b6f8347c7a20ceb003f5"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b90078989ef3fc45cf9221d3859acd1108af7560c52397ff4ace8ad7052a132e"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ba5a8b74c2a8af7d862399cdedce1533642fa727def0b8c3e3e02fcb52dca1b1"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:02594361128f780eecc2a29939d9dfc870e17b45178a867bf61a11b2a4367277"}, - {file = "aiohttp-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4fc029e135859f533025bc82047334e24b0d489e75513144f25408ecaf058"}, - {file = "aiohttp-3.10.5-cp311-cp311-win32.whl", hash = "sha256:e1ca1ef5ba129718a8fc827b0867f6aa4e893c56eb00003b7367f8a733a9b072"}, - {file = "aiohttp-3.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:349ef8a73a7c5665cca65c88ab24abe75447e28aa3bc4c93ea5093474dfdf0ff"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:305be5ff2081fa1d283a76113b8df7a14c10d75602a38d9f012935df20731487"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3a1c32a19ee6bbde02f1cb189e13a71b321256cc1d431196a9f824050b160d5a"}, - {file = "aiohttp-3.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:61645818edd40cc6f455b851277a21bf420ce347baa0b86eaa41d51ef58ba23d"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c225286f2b13bab5987425558baa5cbdb2bc925b2998038fa028245ef421e75"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ba01ebc6175e1e6b7275c907a3a36be48a2d487549b656aa90c8a910d9f3178"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8eaf44ccbc4e35762683078b72bf293f476561d8b68ec8a64f98cf32811c323e"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c43eb1ab7cbf411b8e387dc169acb31f0ca0d8c09ba63f9eac67829585b44f"}, - {file = "aiohttp-3.10.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de7a5299827253023c55ea549444e058c0eb496931fa05d693b95140a947cb73"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4790f0e15f00058f7599dab2b206d3049d7ac464dc2e5eae0e93fa18aee9e7bf"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44b324a6b8376a23e6ba25d368726ee3bc281e6ab306db80b5819999c737d820"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0d277cfb304118079e7044aad0b76685d30ecb86f83a0711fc5fb257ffe832ca"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:54d9ddea424cd19d3ff6128601a4a4d23d54a421f9b4c0fff740505813739a91"}, - {file = "aiohttp-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6"}, - {file = "aiohttp-3.10.5-cp312-cp312-win32.whl", hash = "sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12"}, - {file = "aiohttp-3.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77"}, - {file = "aiohttp-3.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa"}, - {file = "aiohttp-3.10.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5"}, - {file = "aiohttp-3.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987"}, - {file = "aiohttp-3.10.5-cp313-cp313-win32.whl", hash = "sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04"}, - {file = "aiohttp-3.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f6f18898ace4bcd2d41a122916475344a87f1dfdec626ecde9ee802a711bc569"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5ede29d91a40ba22ac1b922ef510aab871652f6c88ef60b9dcdf773c6d32ad7a"}, - {file = "aiohttp-3.10.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:673f988370f5954df96cc31fd99c7312a3af0a97f09e407399f61583f30da9bc"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58718e181c56a3c02d25b09d4115eb02aafe1a732ce5714ab70326d9776457c3"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b38b1570242fbab8d86a84128fb5b5234a2f70c2e32f3070143a6d94bc854cf"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:074d1bff0163e107e97bd48cad9f928fa5a3eb4b9d33366137ffce08a63e37fe"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd31f176429cecbc1ba499d4aba31aaccfea488f418d60376b911269d3b883c5"}, - {file = "aiohttp-3.10.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7384d0b87d4635ec38db9263e6a3f1eb609e2e06087f0aa7f63b76833737b471"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8989f46f3d7ef79585e98fa991e6ded55d2f48ae56d2c9fa5e491a6e4effb589"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:c83f7a107abb89a227d6c454c613e7606c12a42b9a4ca9c5d7dad25d47c776ae"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:cde98f323d6bf161041e7627a5fd763f9fd829bcfcd089804a5fdce7bb6e1b7d"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:676f94c5480d8eefd97c0c7e3953315e4d8c2b71f3b49539beb2aa676c58272f"}, - {file = "aiohttp-3.10.5-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2d21ac12dc943c68135ff858c3a989f2194a709e6e10b4c8977d7fcd67dfd511"}, - {file = "aiohttp-3.10.5-cp38-cp38-win32.whl", hash = "sha256:17e997105bd1a260850272bfb50e2a328e029c941c2708170d9d978d5a30ad9a"}, - {file = "aiohttp-3.10.5-cp38-cp38-win_amd64.whl", hash = "sha256:1c19de68896747a2aa6257ae4cf6ef59d73917a36a35ee9d0a6f48cff0f94db8"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7e2fe37ac654032db1f3499fe56e77190282534810e2a8e833141a021faaab0e"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5bf3ead3cb66ab990ee2561373b009db5bc0e857549b6c9ba84b20bc462e172"}, - {file = "aiohttp-3.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b2c16a919d936ca87a3c5f0e43af12a89a3ce7ccbce59a2d6784caba945b68b"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad146dae5977c4dd435eb31373b3fe9b0b1bf26858c6fc452bf6af394067e10b"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c5c6fa16412b35999320f5c9690c0f554392dc222c04e559217e0f9ae244b92"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:95c4dc6f61d610bc0ee1edc6f29d993f10febfe5b76bb470b486d90bbece6b22"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da452c2c322e9ce0cfef392e469a26d63d42860f829026a63374fde6b5c5876f"}, - {file = "aiohttp-3.10.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:898715cf566ec2869d5cb4d5fb4be408964704c46c96b4be267442d265390f32"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:391cc3a9c1527e424c6865e087897e766a917f15dddb360174a70467572ac6ce"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:380f926b51b92d02a34119d072f178d80bbda334d1a7e10fa22d467a66e494db"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce91db90dbf37bb6fa0997f26574107e1b9d5ff939315247b7e615baa8ec313b"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9093a81e18c45227eebe4c16124ebf3e0d893830c6aca7cc310bfca8fe59d857"}, - {file = "aiohttp-3.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ee40b40aa753d844162dcc80d0fe256b87cba48ca0054f64e68000453caead11"}, - {file = "aiohttp-3.10.5-cp39-cp39-win32.whl", hash = "sha256:03f2645adbe17f274444953bdea69f8327e9d278d961d85657cb0d06864814c1"}, - {file = "aiohttp-3.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:d17920f18e6ee090bdd3d0bfffd769d9f2cb4c8ffde3eb203777a3895c128862"}, - {file = "aiohttp-3.10.5.tar.gz", hash = "sha256:f071854b47d39591ce9a17981c46790acb30518e2f83dfca8db2dfa091178691"}, + {file = "aiohttp-3.10.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:be7443669ae9c016b71f402e43208e13ddf00912f47f623ee5994e12fc7d4b3f"}, + {file = "aiohttp-3.10.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b06b7843929e41a94ea09eb1ce3927865387e3e23ebe108e0d0d09b08d25be9"}, + {file = "aiohttp-3.10.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:333cf6cf8e65f6a1e06e9eb3e643a0c515bb850d470902274239fea02033e9a8"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:274cfa632350225ce3fdeb318c23b4a10ec25c0e2c880eff951a3842cf358ac1"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9e5e4a85bdb56d224f412d9c98ae4cbd032cc4f3161818f692cd81766eee65a"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b606353da03edcc71130b52388d25f9a30a126e04caef1fd637e31683033abd"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab5a5a0c7a7991d90446a198689c0535be89bbd6b410a1f9a66688f0880ec026"}, + {file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:578a4b875af3e0daaf1ac6fa983d93e0bbfec3ead753b6d6f33d467100cdc67b"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8105fd8a890df77b76dd3054cddf01a879fc13e8af576805d667e0fa0224c35d"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3bcd391d083f636c06a68715e69467963d1f9600f85ef556ea82e9ef25f043f7"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fbc6264158392bad9df19537e872d476f7c57adf718944cc1e4495cbabf38e2a"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e48d5021a84d341bcaf95c8460b152cfbad770d28e5fe14a768988c461b821bc"}, + {file = "aiohttp-3.10.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2609e9ab08474702cc67b7702dbb8a80e392c54613ebe80db7e8dbdb79837c68"}, + {file = "aiohttp-3.10.10-cp310-cp310-win32.whl", hash = "sha256:84afcdea18eda514c25bc68b9af2a2b1adea7c08899175a51fe7c4fb6d551257"}, + {file = "aiohttp-3.10.10-cp310-cp310-win_amd64.whl", hash = "sha256:9c72109213eb9d3874f7ac8c0c5fa90e072d678e117d9061c06e30c85b4cf0e6"}, + {file = "aiohttp-3.10.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f"}, + {file = "aiohttp-3.10.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb"}, + {file = "aiohttp-3.10.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7"}, + {file = "aiohttp-3.10.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1"}, + {file = "aiohttp-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a"}, + {file = "aiohttp-3.10.10-cp311-cp311-win32.whl", hash = "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94"}, + {file = "aiohttp-3.10.10-cp311-cp311-win_amd64.whl", hash = "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959"}, + {file = "aiohttp-3.10.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c"}, + {file = "aiohttp-3.10.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28"}, + {file = "aiohttp-3.10.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16"}, + {file = "aiohttp-3.10.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a"}, + {file = "aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205"}, + {file = "aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628"}, + {file = "aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf"}, + {file = "aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28"}, + {file = "aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d"}, + {file = "aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e"}, + {file = "aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67"}, + {file = "aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b"}, + {file = "aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8"}, + {file = "aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151"}, + {file = "aiohttp-3.10.10-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1b66ccafef7336a1e1f0e389901f60c1d920102315a56df85e49552308fc0486"}, + {file = "aiohttp-3.10.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:acd48d5b80ee80f9432a165c0ac8cbf9253eaddb6113269a5e18699b33958dbb"}, + {file = "aiohttp-3.10.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3455522392fb15ff549d92fbf4b73b559d5e43dc522588f7eb3e54c3f38beee7"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45c3b868724137f713a38376fef8120c166d1eadd50da1855c112fe97954aed8"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:da1dee8948d2137bb51fbb8a53cce6b1bcc86003c6b42565f008438b806cccd8"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5ce2ce7c997e1971b7184ee37deb6ea9922ef5163c6ee5aa3c274b05f9e12fa"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28529e08fde6f12eba8677f5a8608500ed33c086f974de68cc65ab218713a59d"}, + {file = "aiohttp-3.10.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7db54c7914cc99d901d93a34704833568d86c20925b2762f9fa779f9cd2e70f"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:03a42ac7895406220124c88911ebee31ba8b2d24c98507f4a8bf826b2937c7f2"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:7e338c0523d024fad378b376a79faff37fafb3c001872a618cde1d322400a572"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:038f514fe39e235e9fef6717fbf944057bfa24f9b3db9ee551a7ecf584b5b480"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:64f6c17757251e2b8d885d728b6433d9d970573586a78b78ba8929b0f41d045a"}, + {file = "aiohttp-3.10.10-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:93429602396f3383a797a2a70e5f1de5df8e35535d7806c9f91df06f297e109b"}, + {file = "aiohttp-3.10.10-cp38-cp38-win32.whl", hash = "sha256:c823bc3971c44ab93e611ab1a46b1eafeae474c0c844aff4b7474287b75fe49c"}, + {file = "aiohttp-3.10.10-cp38-cp38-win_amd64.whl", hash = "sha256:54ca74df1be3c7ca1cf7f4c971c79c2daf48d9aa65dea1a662ae18926f5bc8ce"}, + {file = "aiohttp-3.10.10-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:01948b1d570f83ee7bbf5a60ea2375a89dfb09fd419170e7f5af029510033d24"}, + {file = "aiohttp-3.10.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9fc1500fd2a952c5c8e3b29aaf7e3cc6e27e9cfc0a8819b3bce48cc1b849e4cc"}, + {file = "aiohttp-3.10.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f614ab0c76397661b90b6851a030004dac502e48260ea10f2441abd2207fbcc7"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00819de9e45d42584bed046314c40ea7e9aea95411b38971082cad449392b08c"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05646ebe6b94cc93407b3bf34b9eb26c20722384d068eb7339de802154d61bc5"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:998f3bd3cfc95e9424a6acd7840cbdd39e45bc09ef87533c006f94ac47296090"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9010c31cd6fa59438da4e58a7f19e4753f7f264300cd152e7f90d4602449762"}, + {file = "aiohttp-3.10.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ea7ffc6d6d6f8a11e6f40091a1040995cdff02cfc9ba4c2f30a516cb2633554"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ef9c33cc5cbca35808f6c74be11eb7f5f6b14d2311be84a15b594bd3e58b5527"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ce0cdc074d540265bfeb31336e678b4e37316849d13b308607efa527e981f5c2"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:597a079284b7ee65ee102bc3a6ea226a37d2b96d0418cc9047490f231dc09fe8"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:7789050d9e5d0c309c706953e5e8876e38662d57d45f936902e176d19f1c58ab"}, + {file = "aiohttp-3.10.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e7f8b04d83483577fd9200461b057c9f14ced334dcb053090cea1da9c8321a91"}, + {file = "aiohttp-3.10.10-cp39-cp39-win32.whl", hash = "sha256:c02a30b904282777d872266b87b20ed8cc0d1501855e27f831320f471d54d983"}, + {file = "aiohttp-3.10.10-cp39-cp39-win_amd64.whl", hash = "sha256:edfe3341033a6b53a5c522c802deb2079eee5cbfbb0af032a55064bd65c73a23"}, + {file = "aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a"}, ] [package.dependencies] @@ -118,7 +118,7 @@ async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" -yarl = ">=1.0,<2.0" +yarl = ">=1.12.0,<2.0" [package.extras] speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] @@ -154,13 +154,13 @@ frozenlist = ">=1.1.0" [[package]] name = "anyio" -version = "4.4.0" +version = "4.5.2" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" files = [ - {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, - {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, + {file = "anyio-4.5.2-py3-none-any.whl", hash = "sha256:c011ee36bc1e8ba40e5a81cb9df91925c218fe9b778554e0b56a21e1b5d4716f"}, + {file = "anyio-4.5.2.tar.gz", hash = "sha256:23009af4ed04ce05991845451e11ef02fc7c5ed29179ac9a420e5ad0ac7ddc5b"}, ] [package.dependencies] @@ -170,9 +170,9 @@ sniffio = ">=1.1" typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.23)"] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] +trio = ["trio (>=0.26.1)"] [[package]] name = "async-timeout" @@ -312,101 +312,116 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] [[package]] @@ -523,13 +538,13 @@ toml = ["tomli"] [[package]] name = "distlib" -version = "0.3.8" +version = "0.3.9" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, - {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, ] [[package]] @@ -562,18 +577,18 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] [[package]] name = "filelock" -version = "3.16.0" +version = "3.16.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.16.0-py3-none-any.whl", hash = "sha256:f6ed4c963184f4c84dd5557ce8fece759a3724b37b80c6c4f20a2f63a4dc6609"}, - {file = "filelock-3.16.0.tar.gz", hash = "sha256:81de9eb8453c769b63369f87f11131a7ab04e367f8d97ad39dc230daa07e3bec"}, + {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, + {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, ] [package.extras] -docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.1.1)", "pytest (>=8.3.2)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.3)"] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] typing = ["typing-extensions (>=4.12.2)"] [[package]] @@ -782,13 +797,13 @@ socks = ["socksio (==1.*)"] [[package]] name = "identify" -version = "2.6.0" +version = "2.6.1" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0"}, - {file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"}, + {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, + {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, ] [package.extras] @@ -796,33 +811,40 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.8" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" files = [ - {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, - {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "importlib-metadata" -version = "8.4.0" +version = "8.5.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-8.4.0-py3-none-any.whl", hash = "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1"}, - {file = "importlib_metadata-8.4.0.tar.gz", hash = "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5"}, + {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, + {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, ] [package.dependencies] -zipp = ">=0.5" +zipp = ">=3.20" [package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] [[package]] name = "iniconfig" @@ -1001,13 +1023,13 @@ files = [ [[package]] name = "mdit-py-plugins" -version = "0.4.1" +version = "0.4.2" description = "Collection of plugins for markdown-it-py" optional = false python-versions = ">=3.8" files = [ - {file = "mdit_py_plugins-0.4.1-py3-none-any.whl", hash = "sha256:1020dfe4e6bfc2c79fb49ae4e3f5b297f5ccd20f010187acc52af2921e27dc6a"}, - {file = "mdit_py_plugins-0.4.1.tar.gz", hash = "sha256:834b8ac23d1cd60cec703646ffd22ae97b7955a6d596eb1d304be1e251ae499c"}, + {file = "mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636"}, + {file = "mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5"}, ] [package.dependencies] @@ -1119,13 +1141,13 @@ pyyaml = ">=5.1" [[package]] name = "mkdocs-git-revision-date-localized-plugin" -version = "1.2.8" +version = "1.2.9" description = "Mkdocs plugin that enables displaying the localized date of the last git modification of a markdown file." optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_git_revision_date_localized_plugin-1.2.8-py3-none-any.whl", hash = "sha256:c7ec3b1481ca23134269e84927bd8a5dc1aa359c0e515b832dbd5d25019b5748"}, - {file = "mkdocs_git_revision_date_localized_plugin-1.2.8.tar.gz", hash = "sha256:6e09c308bb27bcf36b211d17b74152ecc2837cdfc351237f70cffc723ef0fd99"}, + {file = "mkdocs_git_revision_date_localized_plugin-1.2.9-py3-none-any.whl", hash = "sha256:dea5c8067c23df30275702a1708885500fadf0abfb595b60e698bffc79c7a423"}, + {file = "mkdocs_git_revision_date_localized_plugin-1.2.9.tar.gz", hash = "sha256:df9a50873fba3a42ce9123885f8c53d589e90ef6c2443fe3280ef1e8d33c8f65"}, ] [package.dependencies] @@ -1141,13 +1163,13 @@ dev = ["click", "codecov", "mkdocs-gen-files", "mkdocs-git-authors-plugin", "mkd [[package]] name = "mkdocs-material" -version = "9.5.34" +version = "9.5.42" description = "Documentation that simply works" optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_material-9.5.34-py3-none-any.whl", hash = "sha256:54caa8be708de2b75167fd4d3b9f3d949579294f49cb242515d4653dbee9227e"}, - {file = "mkdocs_material-9.5.34.tar.gz", hash = "sha256:1e60ddf716cfb5679dfd65900b8a25d277064ed82d9a53cd5190e3f894df7840"}, + {file = "mkdocs_material-9.5.42-py3-none-any.whl", hash = "sha256:452a7c5d21284b373f36b981a2cbebfff59263feebeede1bc28652e9c5bbe316"}, + {file = "mkdocs_material-9.5.42.tar.gz", hash = "sha256:92779b5e9b5934540c574c11647131d217dc540dce72b05feeda088c8eb1b8f2"}, ] [package.dependencies] @@ -1245,202 +1267,220 @@ mkdocstrings = ">=0.20" [[package]] name = "msgpack" -version = "1.0.8" +version = "1.1.0" description = "MessagePack serializer" optional = false python-versions = ">=3.8" files = [ - {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868"}, - {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c"}, - {file = "msgpack-1.0.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659"}, - {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2"}, - {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982"}, - {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa"}, - {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128"}, - {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d"}, - {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653"}, - {file = "msgpack-1.0.8-cp310-cp310-win32.whl", hash = "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693"}, - {file = "msgpack-1.0.8-cp310-cp310-win_amd64.whl", hash = "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a"}, - {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836"}, - {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad"}, - {file = "msgpack-1.0.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b"}, - {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba"}, - {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85"}, - {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950"}, - {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a"}, - {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b"}, - {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce"}, - {file = "msgpack-1.0.8-cp311-cp311-win32.whl", hash = "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305"}, - {file = "msgpack-1.0.8-cp311-cp311-win_amd64.whl", hash = "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e"}, - {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee"}, - {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b"}, - {file = "msgpack-1.0.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8"}, - {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3"}, - {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc"}, - {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58"}, - {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f"}, - {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04"}, - {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543"}, - {file = "msgpack-1.0.8-cp312-cp312-win32.whl", hash = "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c"}, - {file = "msgpack-1.0.8-cp312-cp312-win_amd64.whl", hash = "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd"}, - {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40"}, - {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151"}, - {file = "msgpack-1.0.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24"}, - {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d"}, - {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db"}, - {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77"}, - {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13"}, - {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2"}, - {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a"}, - {file = "msgpack-1.0.8-cp38-cp38-win32.whl", hash = "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c"}, - {file = "msgpack-1.0.8-cp38-cp38-win_amd64.whl", hash = "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480"}, - {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a"}, - {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596"}, - {file = "msgpack-1.0.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d"}, - {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f"}, - {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228"}, - {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18"}, - {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8"}, - {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746"}, - {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"}, - {file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"}, - {file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"}, - {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"}, + {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd"}, + {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74bed8f63f8f14d75eec75cf3d04ad581da6b914001b474a5d3cd3372c8cc27d"}, + {file = "msgpack-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:914571a2a5b4e7606997e169f64ce53a8b1e06f2cf2c3a7273aa106236d43dd5"}, + {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c921af52214dcbb75e6bdf6a661b23c3e6417f00c603dd2070bccb5c3ef499f5"}, + {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8ce0b22b890be5d252de90d0e0d119f363012027cf256185fc3d474c44b1b9e"}, + {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73322a6cc57fcee3c0c57c4463d828e9428275fb85a27aa2aa1a92fdc42afd7b"}, + {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e1f3c3d21f7cf67bcf2da8e494d30a75e4cf60041d98b3f79875afb5b96f3a3f"}, + {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64fc9068d701233effd61b19efb1485587560b66fe57b3e50d29c5d78e7fef68"}, + {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:42f754515e0f683f9c79210a5d1cad631ec3d06cea5172214d2176a42e67e19b"}, + {file = "msgpack-1.1.0-cp310-cp310-win32.whl", hash = "sha256:3df7e6b05571b3814361e8464f9304c42d2196808e0119f55d0d3e62cd5ea044"}, + {file = "msgpack-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:685ec345eefc757a7c8af44a3032734a739f8c45d1b0ac45efc5d8977aa4720f"}, + {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d364a55082fb2a7416f6c63ae383fbd903adb5a6cf78c5b96cc6316dc1cedc7"}, + {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79ec007767b9b56860e0372085f8504db5d06bd6a327a335449508bbee9648fa"}, + {file = "msgpack-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ad622bf7756d5a497d5b6836e7fc3752e2dd6f4c648e24b1803f6048596f701"}, + {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e59bca908d9ca0de3dc8684f21ebf9a690fe47b6be93236eb40b99af28b6ea6"}, + {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1da8f11a3dd397f0a32c76165cf0c4eb95b31013a94f6ecc0b280c05c91b59"}, + {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452aff037287acb1d70a804ffd022b21fa2bb7c46bee884dbc864cc9024128a0"}, + {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8da4bf6d54ceed70e8861f833f83ce0814a2b72102e890cbdfe4b34764cdd66e"}, + {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:41c991beebf175faf352fb940bf2af9ad1fb77fd25f38d9142053914947cdbf6"}, + {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a52a1f3a5af7ba1c9ace055b659189f6c669cf3657095b50f9602af3a3ba0fe5"}, + {file = "msgpack-1.1.0-cp311-cp311-win32.whl", hash = "sha256:58638690ebd0a06427c5fe1a227bb6b8b9fdc2bd07701bec13c2335c82131a88"}, + {file = "msgpack-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd2906780f25c8ed5d7b323379f6138524ba793428db5d0e9d226d3fa6aa1788"}, + {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d"}, + {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2"}, + {file = "msgpack-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420"}, + {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2"}, + {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39"}, + {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f"}, + {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247"}, + {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c"}, + {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b"}, + {file = "msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b"}, + {file = "msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f"}, + {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:071603e2f0771c45ad9bc65719291c568d4edf120b44eb36324dcb02a13bfddf"}, + {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0f92a83b84e7c0749e3f12821949d79485971f087604178026085f60ce109330"}, + {file = "msgpack-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1964df7b81285d00a84da4e70cb1383f2e665e0f1f2a7027e683956d04b734"}, + {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59caf6a4ed0d164055ccff8fe31eddc0ebc07cf7326a2aaa0dbf7a4001cd823e"}, + {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0907e1a7119b337971a689153665764adc34e89175f9a34793307d9def08e6ca"}, + {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65553c9b6da8166e819a6aa90ad15288599b340f91d18f60b2061f402b9a4915"}, + {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a946a8992941fea80ed4beae6bff74ffd7ee129a90b4dd5cf9c476a30e9708d"}, + {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4b51405e36e075193bc051315dbf29168d6141ae2500ba8cd80a522964e31434"}, + {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4c01941fd2ff87c2a934ee6055bda4ed353a7846b8d4f341c428109e9fcde8c"}, + {file = "msgpack-1.1.0-cp313-cp313-win32.whl", hash = "sha256:7c9a35ce2c2573bada929e0b7b3576de647b0defbd25f5139dcdaba0ae35a4cc"}, + {file = "msgpack-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f"}, + {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c40ffa9a15d74e05ba1fe2681ea33b9caffd886675412612d93ab17b58ea2fec"}, + {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1ba6136e650898082d9d5a5217d5906d1e138024f836ff48691784bbe1adf96"}, + {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0856a2b7e8dcb874be44fea031d22e5b3a19121be92a1e098f46068a11b0870"}, + {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:471e27a5787a2e3f974ba023f9e265a8c7cfd373632247deb225617e3100a3c7"}, + {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:646afc8102935a388ffc3914b336d22d1c2d6209c773f3eb5dd4d6d3b6f8c1cb"}, + {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:13599f8829cfbe0158f6456374e9eea9f44eee08076291771d8ae93eda56607f"}, + {file = "msgpack-1.1.0-cp38-cp38-win32.whl", hash = "sha256:8a84efb768fb968381e525eeeb3d92857e4985aacc39f3c47ffd00eb4509315b"}, + {file = "msgpack-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:879a7b7b0ad82481c52d3c7eb99bf6f0645dbdec5134a4bddbd16f3506947feb"}, + {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:53258eeb7a80fc46f62fd59c876957a2d0e15e6449a9e71842b6d24419d88ca1"}, + {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e7b853bbc44fb03fbdba34feb4bd414322180135e2cb5164f20ce1c9795ee48"}, + {file = "msgpack-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3e9b4936df53b970513eac1758f3882c88658a220b58dcc1e39606dccaaf01c"}, + {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46c34e99110762a76e3911fc923222472c9d681f1094096ac4102c18319e6468"}, + {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a706d1e74dd3dea05cb54580d9bd8b2880e9264856ce5068027eed09680aa74"}, + {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:534480ee5690ab3cbed89d4c8971a5c631b69a8c0883ecfea96c19118510c846"}, + {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8cf9e8c3a2153934a23ac160cc4cba0ec035f6867c8013cc6077a79823370346"}, + {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3180065ec2abbe13a4ad37688b61b99d7f9e012a535b930e0e683ad6bc30155b"}, + {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c5a91481a3cc573ac8c0d9aace09345d989dc4a0202b7fcb312c88c26d4e71a8"}, + {file = "msgpack-1.1.0-cp39-cp39-win32.whl", hash = "sha256:f80bc7d47f76089633763f952e67f8214cb7b3ee6bfa489b3cb6a84cfac114cd"}, + {file = "msgpack-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:4d1b7ff2d6146e16e8bd665ac726a89c74163ef8cd39fa8c1087d4e52d3a2325"}, + {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"}, ] [[package]] name = "multidict" -version = "6.0.5" +version = "6.1.0" description = "multidict implementation" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, - {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, - {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, - {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, - {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, - {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, - {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, - {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, - {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, - {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, - {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, - {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, - {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, - {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, - {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, - {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, + {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, + {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, + {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, + {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, + {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, + {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, + {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, + {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, + {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, + {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, + {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, + {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, + {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, + {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + [[package]] name = "mypy" -version = "1.11.2" +version = "1.12.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a"}, - {file = "mypy-1.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef"}, - {file = "mypy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383"}, - {file = "mypy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8"}, - {file = "mypy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7"}, - {file = "mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385"}, - {file = "mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca"}, - {file = "mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104"}, - {file = "mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4"}, - {file = "mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6"}, - {file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"}, - {file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"}, - {file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"}, - {file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"}, - {file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"}, - {file = "mypy-1.11.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:37c7fa6121c1cdfcaac97ce3d3b5588e847aa79b580c1e922bb5d5d2902df19b"}, - {file = "mypy-1.11.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8a53bc3ffbd161b5b2a4fff2f0f1e23a33b0168f1c0778ec70e1a3d66deb86"}, - {file = "mypy-1.11.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ff93107f01968ed834f4256bc1fc4475e2fecf6c661260066a985b52741ddce"}, - {file = "mypy-1.11.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:edb91dded4df17eae4537668b23f0ff6baf3707683734b6a818d5b9d0c0c31a1"}, - {file = "mypy-1.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:ee23de8530d99b6db0573c4ef4bd8f39a2a6f9b60655bf7a1357e585a3486f2b"}, - {file = "mypy-1.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6"}, - {file = "mypy-1.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70"}, - {file = "mypy-1.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d"}, - {file = "mypy-1.11.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d"}, - {file = "mypy-1.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24"}, - {file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"}, - {file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"}, + {file = "mypy-1.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3d7d4371829184e22fda4015278fbfdef0327a4b955a483012bd2d423a788801"}, + {file = "mypy-1.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f59f1dfbf497d473201356966e353ef09d4daec48caeacc0254db8ef633a28a5"}, + {file = "mypy-1.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b947097fae68004b8328c55161ac9db7d3566abfef72d9d41b47a021c2fba6b1"}, + {file = "mypy-1.12.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:96af62050971c5241afb4701c15189ea9507db89ad07794a4ee7b4e092dc0627"}, + {file = "mypy-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:d90da248f4c2dba6c44ddcfea94bb361e491962f05f41990ff24dbd09969ce20"}, + {file = "mypy-1.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1230048fec1380faf240be6385e709c8570604d2d27ec6ca7e573e3bc09c3735"}, + {file = "mypy-1.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:02dcfe270c6ea13338210908f8cadc8d31af0f04cee8ca996438fe6a97b4ec66"}, + {file = "mypy-1.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5a437c9102a6a252d9e3a63edc191a3aed5f2fcb786d614722ee3f4472e33f6"}, + {file = "mypy-1.12.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:186e0c8346efc027ee1f9acf5ca734425fc4f7dc2b60144f0fbe27cc19dc7931"}, + {file = "mypy-1.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:673ba1140a478b50e6d265c03391702fa11a5c5aff3f54d69a62a48da32cb811"}, + {file = "mypy-1.12.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9fb83a7be97c498176fb7486cafbb81decccaef1ac339d837c377b0ce3743a7f"}, + {file = "mypy-1.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:389e307e333879c571029d5b93932cf838b811d3f5395ed1ad05086b52148fb0"}, + {file = "mypy-1.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:94b2048a95a21f7a9ebc9fbd075a4fcd310410d078aa0228dbbad7f71335e042"}, + {file = "mypy-1.12.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ee5932370ccf7ebf83f79d1c157a5929d7ea36313027b0d70a488493dc1b179"}, + {file = "mypy-1.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:19bf51f87a295e7ab2894f1d8167622b063492d754e69c3c2fed6563268cb42a"}, + {file = "mypy-1.12.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d34167d43613ffb1d6c6cdc0cc043bb106cac0aa5d6a4171f77ab92a3c758bcc"}, + {file = "mypy-1.12.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:427878aa54f2e2c5d8db31fa9010c599ed9f994b3b49e64ae9cd9990c40bd635"}, + {file = "mypy-1.12.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fcde63ea2c9f69d6be859a1e6dd35955e87fa81de95bc240143cf00de1f7f81"}, + {file = "mypy-1.12.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d54d840f6c052929f4a3d2aab2066af0f45a020b085fe0e40d4583db52aab4e4"}, + {file = "mypy-1.12.1-cp313-cp313-win_amd64.whl", hash = "sha256:20db6eb1ca3d1de8ece00033b12f793f1ea9da767334b7e8c626a4872090cf02"}, + {file = "mypy-1.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b16fe09f9c741d85a2e3b14a5257a27a4f4886c171d562bc5a5e90d8591906b8"}, + {file = "mypy-1.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0dcc1e843d58f444fce19da4cce5bd35c282d4bde232acdeca8279523087088a"}, + {file = "mypy-1.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e10ba7de5c616e44ad21005fa13450cd0de7caaa303a626147d45307492e4f2d"}, + {file = "mypy-1.12.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0e6fe449223fa59fbee351db32283838a8fee8059e0028e9e6494a03802b4004"}, + {file = "mypy-1.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:dc6e2a2195a290a7fd5bac3e60b586d77fc88e986eba7feced8b778c373f9afe"}, + {file = "mypy-1.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:de5b2a8988b4e1269a98beaf0e7cc71b510d050dce80c343b53b4955fff45f19"}, + {file = "mypy-1.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:843826966f1d65925e8b50d2b483065c51fc16dc5d72647e0236aae51dc8d77e"}, + {file = "mypy-1.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9fe20f89da41a95e14c34b1ddb09c80262edcc295ad891f22cc4b60013e8f78d"}, + {file = "mypy-1.12.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8135ffec02121a75f75dc97c81af7c14aa4ae0dda277132cfcd6abcd21551bfd"}, + {file = "mypy-1.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:a7b76fa83260824300cc4834a3ab93180db19876bce59af921467fd03e692810"}, + {file = "mypy-1.12.1-py3-none-any.whl", hash = "sha256:ce561a09e3bb9863ab77edf29ae3a50e65685ad74bba1431278185b7e5d5486e"}, + {file = "mypy-1.12.1.tar.gz", hash = "sha256:f5b3936f7a6d0e8280c9bdef94c7ce4847f5cdfc258fbb2c29a8c1711e8bb96d"}, ] [package.dependencies] @@ -1515,13 +1555,13 @@ files = [ [[package]] name = "platformdirs" -version = "4.3.2" +version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.3.2-py3-none-any.whl", hash = "sha256:eb1c8582560b34ed4ba105009a4badf7f6f85768b30126f351328507b2beb617"}, - {file = "platformdirs-4.3.2.tar.gz", hash = "sha256:9e5e27a08aa095dd127b9f2e764d74254f482fef22b0970773bfba79d091ab8c"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] @@ -1562,6 +1602,113 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" +[[package]] +name = "propcache" +version = "0.2.0" +description = "Accelerated property cache" +optional = false +python-versions = ">=3.8" +files = [ + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336"}, + {file = "propcache-0.2.0-cp310-cp310-win32.whl", hash = "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad"}, + {file = "propcache-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b"}, + {file = "propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1"}, + {file = "propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348"}, + {file = "propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5"}, + {file = "propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544"}, + {file = "propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032"}, + {file = "propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed"}, + {file = "propcache-0.2.0-cp38-cp38-win32.whl", hash = "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d"}, + {file = "propcache-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798"}, + {file = "propcache-0.2.0-cp39-cp39-win32.whl", hash = "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9"}, + {file = "propcache-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df"}, + {file = "propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036"}, + {file = "propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70"}, +] + [[package]] name = "pygments" version = "2.18.0" @@ -1578,13 +1725,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pymdown-extensions" -version = "10.9" +version = "10.11.2" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.9-py3-none-any.whl", hash = "sha256:d323f7e90d83c86113ee78f3fe62fc9dee5f56b54d912660703ea1816fed5626"}, - {file = "pymdown_extensions-10.9.tar.gz", hash = "sha256:6ff740bcd99ec4172a938970d42b96128bdc9d4b9bcad72494f29921dc69b753"}, + {file = "pymdown_extensions-10.11.2-py3-none-any.whl", hash = "sha256:41cdde0a77290e480cf53892f5c5e50921a7ee3e5cd60ba91bf19837b33badcf"}, + {file = "pymdown_extensions-10.11.2.tar.gz", hash = "sha256:bc8847ecc9e784a098efd35e20cba772bc5a1b529dfcef9dc1972db9021a1049"}, ] [package.dependencies] @@ -1596,13 +1743,13 @@ extra = ["pygments (>=2.12)"] [[package]] name = "pytest" -version = "8.3.2" +version = "8.3.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, - {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, ] [package.dependencies] @@ -1706,13 +1853,13 @@ six = ">=1.5" [[package]] name = "pytz" -version = "2024.1" +version = "2024.2" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, - {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, + {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, + {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, ] [[package]] @@ -1793,90 +1940,105 @@ pyyaml = "*" [[package]] name = "regex" -version = "2024.7.24" +version = "2024.9.11" description = "Alternative regular expression module, to replace re." optional = false python-versions = ">=3.8" files = [ - {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b0d3f567fafa0633aee87f08b9276c7062da9616931382993c03808bb68ce"}, - {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3426de3b91d1bc73249042742f45c2148803c111d1175b283270177fdf669024"}, - {file = "regex-2024.7.24-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f273674b445bcb6e4409bf8d1be67bc4b58e8b46fd0d560055d515b8830063cd"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23acc72f0f4e1a9e6e9843d6328177ae3074b4182167e34119ec7233dfeccf53"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65fd3d2e228cae024c411c5ccdffae4c315271eee4a8b839291f84f796b34eca"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c414cbda77dbf13c3bc88b073a1a9f375c7b0cb5e115e15d4b73ec3a2fbc6f59"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf7a89eef64b5455835f5ed30254ec19bf41f7541cd94f266ab7cbd463f00c41"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19c65b00d42804e3fbea9708f0937d157e53429a39b7c61253ff15670ff62cb5"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7a5486ca56c8869070a966321d5ab416ff0f83f30e0e2da1ab48815c8d165d46"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6f51f9556785e5a203713f5efd9c085b4a45aecd2a42573e2b5041881b588d1f"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a4997716674d36a82eab3e86f8fa77080a5d8d96a389a61ea1d0e3a94a582cf7"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c0abb5e4e8ce71a61d9446040c1e86d4e6d23f9097275c5bd49ed978755ff0fe"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:18300a1d78cf1290fa583cd8b7cde26ecb73e9f5916690cf9d42de569c89b1ce"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:416c0e4f56308f34cdb18c3f59849479dde5b19febdcd6e6fa4d04b6c31c9faa"}, - {file = "regex-2024.7.24-cp310-cp310-win32.whl", hash = "sha256:fb168b5924bef397b5ba13aabd8cf5df7d3d93f10218d7b925e360d436863f66"}, - {file = "regex-2024.7.24-cp310-cp310-win_amd64.whl", hash = "sha256:6b9fc7e9cc983e75e2518496ba1afc524227c163e43d706688a6bb9eca41617e"}, - {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:382281306e3adaaa7b8b9ebbb3ffb43358a7bbf585fa93821300a418bb975281"}, - {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4fdd1384619f406ad9037fe6b6eaa3de2749e2e12084abc80169e8e075377d3b"}, - {file = "regex-2024.7.24-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3d974d24edb231446f708c455fd08f94c41c1ff4f04bcf06e5f36df5ef50b95a"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec4419a3fe6cf8a4795752596dfe0adb4aea40d3683a132bae9c30b81e8d73"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb563dd3aea54c797adf513eeec819c4213d7dbfc311874eb4fd28d10f2ff0f2"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45104baae8b9f67569f0f1dca5e1f1ed77a54ae1cd8b0b07aba89272710db61e"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:994448ee01864501912abf2bad9203bffc34158e80fe8bfb5b031f4f8e16da51"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fac296f99283ac232d8125be932c5cd7644084a30748fda013028c815ba3364"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e37e809b9303ec3a179085415cb5f418ecf65ec98cdfe34f6a078b46ef823ee"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:01b689e887f612610c869421241e075c02f2e3d1ae93a037cb14f88ab6a8934c"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f6442f0f0ff81775eaa5b05af8a0ffa1dda36e9cf6ec1e0d3d245e8564b684ce"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:871e3ab2838fbcb4e0865a6e01233975df3a15e6fce93b6f99d75cacbd9862d1"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c918b7a1e26b4ab40409820ddccc5d49871a82329640f5005f73572d5eaa9b5e"}, - {file = "regex-2024.7.24-cp311-cp311-win32.whl", hash = "sha256:2dfbb8baf8ba2c2b9aa2807f44ed272f0913eeeba002478c4577b8d29cde215c"}, - {file = "regex-2024.7.24-cp311-cp311-win_amd64.whl", hash = "sha256:538d30cd96ed7d1416d3956f94d54e426a8daf7c14527f6e0d6d425fcb4cca52"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fe4ebef608553aff8deb845c7f4f1d0740ff76fa672c011cc0bacb2a00fbde86"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:74007a5b25b7a678459f06559504f1eec2f0f17bca218c9d56f6a0a12bfffdad"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7df9ea48641da022c2a3c9c641650cd09f0cd15e8908bf931ad538f5ca7919c9"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a1141a1dcc32904c47f6846b040275c6e5de0bf73f17d7a409035d55b76f289"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80c811cfcb5c331237d9bad3bea2c391114588cf4131707e84d9493064d267f9"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7214477bf9bd195894cf24005b1e7b496f46833337b5dedb7b2a6e33f66d962c"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d55588cba7553f0b6ec33130bc3e114b355570b45785cebdc9daed8c637dd440"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:558a57cfc32adcf19d3f791f62b5ff564922942e389e3cfdb538a23d65a6b610"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a512eed9dfd4117110b1881ba9a59b31433caed0c4101b361f768e7bcbaf93c5"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:86b17ba823ea76256b1885652e3a141a99a5c4422f4a869189db328321b73799"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5eefee9bfe23f6df09ffb6dfb23809f4d74a78acef004aa904dc7c88b9944b05"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:731fcd76bbdbf225e2eb85b7c38da9633ad3073822f5ab32379381e8c3c12e94"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eaef80eac3b4cfbdd6de53c6e108b4c534c21ae055d1dbea2de6b3b8ff3def38"}, - {file = "regex-2024.7.24-cp312-cp312-win32.whl", hash = "sha256:185e029368d6f89f36e526764cf12bf8d6f0e3a2a7737da625a76f594bdfcbfc"}, - {file = "regex-2024.7.24-cp312-cp312-win_amd64.whl", hash = "sha256:2f1baff13cc2521bea83ab2528e7a80cbe0ebb2c6f0bfad15be7da3aed443908"}, - {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:66b4c0731a5c81921e938dcf1a88e978264e26e6ac4ec96a4d21ae0354581ae0"}, - {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:88ecc3afd7e776967fa16c80f974cb79399ee8dc6c96423321d6f7d4b881c92b"}, - {file = "regex-2024.7.24-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64bd50cf16bcc54b274e20235bf8edbb64184a30e1e53873ff8d444e7ac656b2"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb462f0e346fcf41a901a126b50f8781e9a474d3927930f3490f38a6e73b6950"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a82465ebbc9b1c5c50738536fdfa7cab639a261a99b469c9d4c7dcbb2b3f1e57"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:68a8f8c046c6466ac61a36b65bb2395c74451df2ffb8458492ef49900efed293"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac8e84fff5d27420f3c1e879ce9929108e873667ec87e0c8eeb413a5311adfe"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba2537ef2163db9e6ccdbeb6f6424282ae4dea43177402152c67ef869cf3978b"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:43affe33137fcd679bdae93fb25924979517e011f9dea99163f80b82eadc7e53"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c9bb87fdf2ab2370f21e4d5636e5317775e5d51ff32ebff2cf389f71b9b13750"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:945352286a541406f99b2655c973852da7911b3f4264e010218bbc1cc73168f2"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:8bc593dcce679206b60a538c302d03c29b18e3d862609317cb560e18b66d10cf"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3f3b6ca8eae6d6c75a6cff525c8530c60e909a71a15e1b731723233331de4169"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c51edc3541e11fbe83f0c4d9412ef6c79f664a3745fab261457e84465ec9d5a8"}, - {file = "regex-2024.7.24-cp38-cp38-win32.whl", hash = "sha256:d0a07763776188b4db4c9c7fb1b8c494049f84659bb387b71c73bbc07f189e96"}, - {file = "regex-2024.7.24-cp38-cp38-win_amd64.whl", hash = "sha256:8fd5afd101dcf86a270d254364e0e8dddedebe6bd1ab9d5f732f274fa00499a5"}, - {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0ffe3f9d430cd37d8fa5632ff6fb36d5b24818c5c986893063b4e5bdb84cdf24"}, - {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25419b70ba00a16abc90ee5fce061228206173231f004437730b67ac77323f0d"}, - {file = "regex-2024.7.24-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:33e2614a7ce627f0cdf2ad104797d1f68342d967de3695678c0cb84f530709f8"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33a0021893ede5969876052796165bab6006559ab845fd7b515a30abdd990dc"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04ce29e2c5fedf296b1a1b0acc1724ba93a36fb14031f3abfb7abda2806c1535"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b16582783f44fbca6fcf46f61347340c787d7530d88b4d590a397a47583f31dd"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:836d3cc225b3e8a943d0b02633fb2f28a66e281290302a79df0e1eaa984ff7c1"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438d9f0f4bc64e8dea78274caa5af971ceff0f8771e1a2333620969936ba10be"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:973335b1624859cb0e52f96062a28aa18f3a5fc77a96e4a3d6d76e29811a0e6e"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c5e69fd3eb0b409432b537fe3c6f44ac089c458ab6b78dcec14478422879ec5f"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fbf8c2f00904eaf63ff37718eb13acf8e178cb940520e47b2f05027f5bb34ce3"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2757ace61bc4061b69af19e4689fa4416e1a04840f33b441034202b5cd02d4"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:44fc61b99035fd9b3b9453f1713234e5a7c92a04f3577252b45feefe1b327759"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:84c312cdf839e8b579f504afcd7b65f35d60b6285d892b19adea16355e8343c9"}, - {file = "regex-2024.7.24-cp39-cp39-win32.whl", hash = "sha256:ca5b2028c2f7af4e13fb9fc29b28d0ce767c38c7facdf64f6c2cd040413055f1"}, - {file = "regex-2024.7.24-cp39-cp39-win_amd64.whl", hash = "sha256:7c479f5ae937ec9985ecaf42e2e10631551d909f203e31308c12d703922742f9"}, - {file = "regex-2024.7.24.tar.gz", hash = "sha256:9cfd009eed1a46b27c14039ad5bbc5e71b6367c5b2e6d5f5da0ea91600817506"}, + {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408"}, + {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d"}, + {file = "regex-2024.9.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16e13a7929791ac1216afde26f712802e3df7bf0360b32e4914dca3ab8baeea5"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46989629904bad940bbec2106528140a218b4a36bb3042d8406980be1941429c"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a906ed5e47a0ce5f04b2c981af1c9acf9e8696066900bf03b9d7879a6f679fc8"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a091b0550b3b0207784a7d6d0f1a00d1d1c8a11699c1a4d93db3fbefc3ad35"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ddcd9a179c0a6fa8add279a4444015acddcd7f232a49071ae57fa6e278f1f71"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b41e1adc61fa347662b09398e31ad446afadff932a24807d3ceb955ed865cc8"}, + {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ced479f601cd2f8ca1fd7b23925a7e0ad512a56d6e9476f79b8f381d9d37090a"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:635a1d96665f84b292e401c3d62775851aedc31d4f8784117b3c68c4fcd4118d"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c0256beda696edcf7d97ef16b2a33a8e5a875affd6fa6567b54f7c577b30a137"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3ce4f1185db3fbde8ed8aa223fc9620f276c58de8b0d4f8cc86fd1360829edb6"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:09d77559e80dcc9d24570da3745ab859a9cf91953062e4ab126ba9d5993688ca"}, + {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a22ccefd4db3f12b526eccb129390942fe874a3a9fdbdd24cf55773a1faab1a"}, + {file = "regex-2024.9.11-cp310-cp310-win32.whl", hash = "sha256:f745ec09bc1b0bd15cfc73df6fa4f726dcc26bb16c23a03f9e3367d357eeedd0"}, + {file = "regex-2024.9.11-cp310-cp310-win_amd64.whl", hash = "sha256:01c2acb51f8a7d6494c8c5eafe3d8e06d76563d8a8a4643b37e9b2dd8a2ff623"}, + {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df"}, + {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268"}, + {file = "regex-2024.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50"}, + {file = "regex-2024.9.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96"}, + {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1"}, + {file = "regex-2024.9.11-cp311-cp311-win32.whl", hash = "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9"}, + {file = "regex-2024.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf"}, + {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7"}, + {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231"}, + {file = "regex-2024.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a"}, + {file = "regex-2024.9.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a"}, + {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a"}, + {file = "regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776"}, + {file = "regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009"}, + {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784"}, + {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36"}, + {file = "regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6"}, + {file = "regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554"}, + {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8"}, + {file = "regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8"}, + {file = "regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f"}, + {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:35f4a6f96aa6cb3f2f7247027b07b15a374f0d5b912c0001418d1d55024d5cb4"}, + {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:55b96e7ce3a69a8449a66984c268062fbaa0d8ae437b285428e12797baefce7e"}, + {file = "regex-2024.9.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb130fccd1a37ed894824b8c046321540263013da72745d755f2d35114b81a60"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:323c1f04be6b2968944d730e5c2091c8c89767903ecaa135203eec4565ed2b2b"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be1c8ed48c4c4065ecb19d882a0ce1afe0745dfad8ce48c49586b90a55f02366"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5b029322e6e7b94fff16cd120ab35a253236a5f99a79fb04fda7ae71ca20ae8"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6fff13ef6b5f29221d6904aa816c34701462956aa72a77f1f151a8ec4f56aeb"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d4af3979376652010e400accc30404e6c16b7df574048ab1f581af82065e4"}, + {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:079400a8269544b955ffa9e31f186f01d96829110a3bf79dc338e9910f794fca"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f9268774428ec173654985ce55fc6caf4c6d11ade0f6f914d48ef4719eb05ebb"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:23f9985c8784e544d53fc2930fc1ac1a7319f5d5332d228437acc9f418f2f168"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2941333154baff9838e88aa71c1d84f4438189ecc6021a12c7573728b5838e"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e93f1c331ca8e86fe877a48ad64e77882c0c4da0097f2212873a69bbfea95d0c"}, + {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:846bc79ee753acf93aef4184c040d709940c9d001029ceb7b7a52747b80ed2dd"}, + {file = "regex-2024.9.11-cp38-cp38-win32.whl", hash = "sha256:c94bb0a9f1db10a1d16c00880bdebd5f9faf267273b8f5bd1878126e0fbde771"}, + {file = "regex-2024.9.11-cp38-cp38-win_amd64.whl", hash = "sha256:2b08fce89fbd45664d3df6ad93e554b6c16933ffa9d55cb7e01182baaf971508"}, + {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:07f45f287469039ffc2c53caf6803cd506eb5f5f637f1d4acb37a738f71dd066"}, + {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4838e24ee015101d9f901988001038f7f0d90dc0c3b115541a1365fb439add62"}, + {file = "regex-2024.9.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6edd623bae6a737f10ce853ea076f56f507fd7726bee96a41ee3d68d347e4d16"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c69ada171c2d0e97a4b5aa78fbb835e0ffbb6b13fc5da968c09811346564f0d3"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02087ea0a03b4af1ed6ebab2c54d7118127fee8d71b26398e8e4b05b78963199"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69dee6a020693d12a3cf892aba4808fe168d2a4cef368eb9bf74f5398bfd4ee8"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297f54910247508e6e5cae669f2bc308985c60540a4edd1c77203ef19bfa63ca"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecea58b43a67b1b79805f1a0255730edaf5191ecef84dbc4cc85eb30bc8b63b9"}, + {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eab4bb380f15e189d1313195b062a6aa908f5bd687a0ceccd47c8211e9cf0d4a"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0cbff728659ce4bbf4c30b2a1be040faafaa9eca6ecde40aaff86f7889f4ab39"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:54c4a097b8bc5bb0dfc83ae498061d53ad7b5762e00f4adaa23bee22b012e6ba"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:73d6d2f64f4d894c96626a75578b0bf7d9e56dcda8c3d037a2118fdfe9b1c664"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:e53b5fbab5d675aec9f0c501274c467c0f9a5d23696cfc94247e1fb56501ed89"}, + {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0ffbcf9221e04502fc35e54d1ce9567541979c3fdfb93d2c554f0ca583a19b35"}, + {file = "regex-2024.9.11-cp39-cp39-win32.whl", hash = "sha256:e4c22e1ac1f1ec1e09f72e6c44d8f2244173db7eb9629cc3a346a8d7ccc31142"}, + {file = "regex-2024.9.11-cp39-cp39-win_amd64.whl", hash = "sha256:faa3c142464efec496967359ca99696c896c591c56c53506bac1ad465f66e919"}, + {file = "regex-2024.9.11.tar.gz", hash = "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd"}, ] [[package]] @@ -1919,37 +2081,37 @@ idna2008 = ["idna"] [[package]] name = "rich" -version = "13.8.0" +version = "13.9.2" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.8.0" files = [ - {file = "rich-13.8.0-py3-none-any.whl", hash = "sha256:2e85306a063b9492dffc86278197a60cbece75bcb766022f3436f567cae11bdc"}, - {file = "rich-13.8.0.tar.gz", hash = "sha256:a5ac1f1cd448ade0d59cc3356f7db7a7ccda2c8cbae9c7a90c28ff463d3e91f4"}, + {file = "rich-13.9.2-py3-none-any.whl", hash = "sha256:8c82a3d3f8dcfe9e734771313e606b39d8247bb6b826e196f4914b333b743cf1"}, + {file = "rich-13.9.2.tar.gz", hash = "sha256:51a2c62057461aaf7152b4d611168f93a9fc73068f8ded2790f29fe2b5366d0c"}, ] [package.dependencies] markdown-it-py = ">=2.2.0" pygments = ">=2.13.0,<3.0.0" -typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} +typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.11\""} [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "setuptools" -version = "74.1.2" +version = "75.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-74.1.2-py3-none-any.whl", hash = "sha256:5f4c08aa4d3ebcb57a50c33b1b07e94315d7fc7230f7115e47fc99776c8ce308"}, - {file = "setuptools-74.1.2.tar.gz", hash = "sha256:95b40ed940a1c67eb70fc099094bd6e99c6ee7c23aa2306f4d2697ba7916f9c6"}, + {file = "setuptools-75.2.0-py3-none-any.whl", hash = "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8"}, + {file = "setuptools-75.2.0.tar.gz", hash = "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec"}, ] [package.extras] check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] @@ -1991,13 +2153,13 @@ files = [ [[package]] name = "syrupy" -version = "4.7.1" +version = "4.7.2" description = "Pytest Snapshot Test Utility" optional = false python-versions = ">=3.8.1" files = [ - {file = "syrupy-4.7.1-py3-none-any.whl", hash = "sha256:be002267a512a4bedddfae2e026c93df1ea928ae10baadc09640516923376d41"}, - {file = "syrupy-4.7.1.tar.gz", hash = "sha256:f9d4485f3f27d0e5df6ed299cac6fa32eb40a441915d988e82be5a4bdda335c8"}, + {file = "syrupy-4.7.2-py3-none-any.whl", hash = "sha256:eae7ba6be5aed190237caa93be288e97ca1eec5ca58760e4818972a10c4acc64"}, + {file = "syrupy-4.7.2.tar.gz", hash = "sha256:ea45e099f242de1bb53018c238f408a5bb6c82007bc687aefcbeaa0e1c2e935a"}, ] [package.dependencies] @@ -2024,13 +2186,13 @@ typing-extensions = ">=4.4.0,<5.0.0" [[package]] name = "textual-serve" -version = "1.1.0" +version = "1.1.1" description = "Turn your Textual TUIs in to web applications" optional = false python-versions = ">=3.8" files = [ - {file = "textual_serve-1.1.0-py3-none-any.whl", hash = "sha256:aaa40bc4b75f6a1e73a2d7f6e667f5555a552d8040129a95e52789a3de5d9154"}, - {file = "textual_serve-1.1.0.tar.gz", hash = "sha256:9332716464a1fca38bb5421ef29e38bdc5d304e5a15faa3ae1f8dcb185a7885c"}, + {file = "textual_serve-1.1.1-py3-none-any.whl", hash = "sha256:568782f1c0e60e3f7039d9121e1cb5c2f4ca1aaf6d6bd7aeb833d5763a534cb2"}, + {file = "textual_serve-1.1.1.tar.gz", hash = "sha256:71c662472c462e5e368defc660ee6e8eae3bfda88ca40c050c55474686eb0c54"}, ] [package.dependencies] @@ -2042,13 +2204,13 @@ textual = ">=0.66.0" [[package]] name = "tomli" -version = "2.0.1" +version = "2.0.2" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, + {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, ] [[package]] @@ -2259,13 +2421,13 @@ files = [ [[package]] name = "tzdata" -version = "2024.1" +version = "2024.2" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, - {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, + {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, + {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, ] [[package]] @@ -2284,13 +2446,13 @@ test = ["coverage", "pytest", "pytest-cov"] [[package]] name = "urllib3" -version = "2.2.2" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] @@ -2301,13 +2463,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.26.4" +version = "20.27.0" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "virtualenv-20.26.4-py3-none-any.whl", hash = "sha256:48f2695d9809277003f30776d155615ffc11328e6a0a8c1f0ec80188d7874a55"}, - {file = "virtualenv-20.26.4.tar.gz", hash = "sha256:c17f4e0f3e6036e9f26700446f85c76ab11df65ff6d8a9cbfad9f71aabfcf23c"}, + {file = "virtualenv-20.27.0-py3-none-any.whl", hash = "sha256:44a72c29cceb0ee08f300b314848c86e57bf8d1f13107a5e671fb9274138d655"}, + {file = "virtualenv-20.27.0.tar.gz", hash = "sha256:2ca56a68ed615b8fe4326d11a0dca5dfbe8fd68510fb6c6349163bed3c15f2b2"}, ] [package.dependencies] @@ -2368,118 +2530,125 @@ watchmedo = ["PyYAML (>=3.10)"] [[package]] name = "yarl" -version = "1.11.0" +version = "1.15.2" description = "Yet another URL library" optional = false python-versions = ">=3.8" files = [ - {file = "yarl-1.11.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0a657db1b9982f3dac0e360614d0e8945d2873da6e681fb7fca23ef1c3eb37f8"}, - {file = "yarl-1.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:65a1a05efca52b102691e64db5fcf973030a1c88fee393804ff91f99c95a6e74"}, - {file = "yarl-1.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f4cb417d380e2d77961eecec75aaaf6f7ab14e6de26eb3a498f498029a6556a1"}, - {file = "yarl-1.11.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8aee7c8378c6aa3103b99d1eb9995268ef730fa9f88ea68b9eee4341e204eec9"}, - {file = "yarl-1.11.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84624db40e2358cfd5cf2558b1aaffd93366d27ee32228a97785f2ec87d44a17"}, - {file = "yarl-1.11.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a596bb15e036952549871a4ccd2205679902dc7f241e3ced6b2ab2e44c55795"}, - {file = "yarl-1.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9d4d2cc4b076c8ad0175a15ee9482a387b3303c97d4b71062db7356b2ac04c7"}, - {file = "yarl-1.11.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25f8bc849004122591104793a576e9c747b0e5d9486d6a30225521b817255748"}, - {file = "yarl-1.11.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e38176a559edde0cfff4b663791a007a5f9f90c73aee1d6f7ddbcf6bfb7287b3"}, - {file = "yarl-1.11.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:706ac0f77b45e9e0278ec6c98929764e119d3ce3136792b6475e7ae961da53ec"}, - {file = "yarl-1.11.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:48bac099586cf75ae5837b0ac17a674450d01f451f38afcb02acfc940110b60b"}, - {file = "yarl-1.11.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:540fd5f62fe21f3d1d9efe8af5c4d9dbbb184ce03ce95acb0289500e46215dd2"}, - {file = "yarl-1.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:05ab59db0bb64e847972373c5cda8924e6605480f6b13cc04573fa0d87bfc637"}, - {file = "yarl-1.11.0-cp310-cp310-win32.whl", hash = "sha256:ddab47748933ac9cf5f29d6e9e2e2060cff40b2751d02c55129661ea4e577152"}, - {file = "yarl-1.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:976d02274e6d88b24c7131e7b26a083412b2592f2bbcef53d3b00b2508cad26c"}, - {file = "yarl-1.11.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:39e3087e1ef70862de81e22af9eb299faee580f41673ef92829949022791b521"}, - {file = "yarl-1.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7fd535cc41b81a566ad347081b671ab5c7e5f5b6a15526d85b4e748baf065cf0"}, - {file = "yarl-1.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f7cc02d8e9a612174869f4b983f159e87659096f7e2dc1fe9effd9902e408739"}, - {file = "yarl-1.11.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30f391ccf4b1b1e0ba4880075ba337d41a619a5350f67053927f67ebe764bf44"}, - {file = "yarl-1.11.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c19a0d95943bb2c914b4e71043803be34bc75c08c4a6ca232bdc649a1e9ef1b"}, - {file = "yarl-1.11.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ead4d89eade0e09b8ef97877664abb0e2e8704787db5564f83658fdee5c36497"}, - {file = "yarl-1.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:195f7791bc23d5f2480efe53f935daf8a61661000dfbfbdd70dbd06397594fff"}, - {file = "yarl-1.11.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01a7905e662665ca8e058635377522bc3c98bdb873be761ff42c86eb72b03914"}, - {file = "yarl-1.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:53c80b1927b75aed208d7fd965a3a705dc8c1db4d50b9112418fa0f7784363e6"}, - {file = "yarl-1.11.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:11af21bbf807688d49b7d4915bb28cbc2e3aa028a2ee194738477eabcc413c65"}, - {file = "yarl-1.11.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:732d56da00ea7a5da4f0d15adbbd22dcb37da7825510aafde40112e53f6baa52"}, - {file = "yarl-1.11.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7bd54d79025b59d1dc5fb26a09734d6a9cc651a04bc381966ed264b28331a168"}, - {file = "yarl-1.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:aacd62ff67efd54cb18cea2aa7ae4fb83cfbca19a07055d4777266b70561defe"}, - {file = "yarl-1.11.0-cp311-cp311-win32.whl", hash = "sha256:68e14ae71e5b51c8282ae5db53ccb3baffc40e1551370a8a2361f1c1d8a0bf8c"}, - {file = "yarl-1.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:3ade2265716667b6bd4123d6f684b5f7cf4a8d83dcf1d5581ac44643466bb00a"}, - {file = "yarl-1.11.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:6e73dab98e3c3b5441720153e72a5f28e717aac2d22f1ec4b08ef33417d9987e"}, - {file = "yarl-1.11.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4a0d090d296ced05edfe29c6ff34869412fa6a97d0928c12b00939c4842884cd"}, - {file = "yarl-1.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d29e446cfb0a82d3df7745968b9fa286665a9be8b4d68de46bcc32d917cb218e"}, - {file = "yarl-1.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c8dc0efcf8266ecfe057b95e01f43eb62516196a4bbf3918fd1dcb8d0dc0dff"}, - {file = "yarl-1.11.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:202f5ec49ff163dcc767426deb55020a28078e61d6bbe1f80331d92bca53b236"}, - {file = "yarl-1.11.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8055b0d78ce1cafa657c4b455e22661e8d3b2834de66a0753c3567da47fcc4aa"}, - {file = "yarl-1.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60ed3c7f64e820959d7f682ec2f559b4f4df723dc09df619d269853a4214a4b4"}, - {file = "yarl-1.11.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2371510367d39d74997acfdcd1dead17938c79c99365482821627f7838a8eba0"}, - {file = "yarl-1.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e24bb6a8be89ccc3ce8c47e8940fdfcb7429e9efbf65ce6fa3e7d122fcf0bcf0"}, - {file = "yarl-1.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:18ec42da256cfcb9b4cd5d253e04c291f69911a5228d1438a7d431c15ba0ae40"}, - {file = "yarl-1.11.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:418eeb8f228ea36c368bf6782ebd6016ecebfb1a8b90145ef6726ffcbba65ef8"}, - {file = "yarl-1.11.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:07e8cfb1dd7669a129f8fd5df1da65efa73aea77582bde2a3a837412e2863543"}, - {file = "yarl-1.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3c458483711d393dad51340505c3fab3194748fd06bab311d2f8b5b7a7349e9a"}, - {file = "yarl-1.11.0-cp312-cp312-win32.whl", hash = "sha256:5b008c3127382503e7a1e12b4c3a3236e3dd833a4c62a066f4a0fbd650c655d2"}, - {file = "yarl-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc94be7472b9f88d7441340534a3ecae05c86ccfec7ba75ce5b6e4778b2bfc6e"}, - {file = "yarl-1.11.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a45e51ba3777031e0b20c1e7ab59114ed4e1884b3c1db48962c1d8d08aefb418"}, - {file = "yarl-1.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:765128029218eade3a01187cdd7f375977cc827505ed31828196c8ae9b622928"}, - {file = "yarl-1.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2516e238daf0339c8ac4dfab9d7cda9afad652ff073517f200d653d5d8371f7e"}, - {file = "yarl-1.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d10be62bee117f05b1ad75a6c2538ca9e5367342dc8a4f3c206c87dadbc1189c"}, - {file = "yarl-1.11.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50ceaeda771ee3e382291168c90c7ede62b63ecf3e181024bcfeb35c0ea6c84f"}, - {file = "yarl-1.11.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a601c99fc20fd0eea84e7bc0dc9e7f196f55a0ded67242d724988c754295538"}, - {file = "yarl-1.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42ff79371614764fc0a4ab8eaba9adb493bf9ad856e2a4664f6c754fc907a903"}, - {file = "yarl-1.11.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93fca4c9f88c17ead902b3f3285b2d039fc8f26d117e1441973ba64315109b54"}, - {file = "yarl-1.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e7dddf5f41395c84fc59e0ed5493b24bfeb39fb04823e880b52c8c55085d4695"}, - {file = "yarl-1.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ea501ea07e14ba6364ff2621bfc8b2381e5b1e10353927fa9a607057fd2b98e5"}, - {file = "yarl-1.11.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a4f7e470f2c9c8b8774a5bda72adfb8e9dc4ec32311fe9bdaa4921e36cf6659b"}, - {file = "yarl-1.11.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:361fdb3993431157302b7104d525092b5df4d7d346df5a5ffeee2d1ca8e0d15b"}, - {file = "yarl-1.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e300eaf5e0329ad31b3d53e2f3d26b4b6dff1217207c6ab1d4212967b54b2185"}, - {file = "yarl-1.11.0-cp313-cp313-win32.whl", hash = "sha256:f1e2d4ce72e06e38a16da3e9c24a0520dbc19018a69ef6ed57b6b38527cb275c"}, - {file = "yarl-1.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:fa9de2f87be58f714a230bd1f3ef3aad1ed65c9931146e3fc55f85fcbe6bacc3"}, - {file = "yarl-1.11.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:24da0b38274727fe9266d09229987e7f0efdb97beb94c0bb2d327d65f112e78d"}, - {file = "yarl-1.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0310eb2e63872de66047e05ad9982f2e53ad6405dc42fa60d7cc670bf6ca8aa8"}, - {file = "yarl-1.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:52433604340a4ab3d1f32281c6eb9ad9b47c99435b4212f763121bf7348c8c00"}, - {file = "yarl-1.11.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98e2eb182d59f0845a79434003f94b4f61cd69465248f9388c2e5bf2191c9f7f"}, - {file = "yarl-1.11.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b3dd10f0fe0e0f659926c1da791de5bef05fd48974ad74618c9168e302e2b7cc"}, - {file = "yarl-1.11.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:121d3798e4bb35a4321b2422cb887f80ea39f94bf52f0eb5cb2c168bb0043c9b"}, - {file = "yarl-1.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8bbac56c80610dd659ace534765d7bcd2488f6600023f6984f35108b2b3f4f0"}, - {file = "yarl-1.11.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79d420399f0e82e302236a762d8b8ceec89761ce3b30c83ac1d4d6e29f811444"}, - {file = "yarl-1.11.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:03a726fb50588307dfe1d233b67535d493fb0bb157bdbfda6bb34e04189f2f57"}, - {file = "yarl-1.11.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9057f5de2fade7440e6db358913bc7ae8de43ba72c83cf95420a1fc1a6c6b59e"}, - {file = "yarl-1.11.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:6471d747d0ac8059895e66d32ca8630c8db5b572ca7763150d0927eaa257df67"}, - {file = "yarl-1.11.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:d97cb22ad380850754fa16ef8d490d9340d8573d81f73429f3975e8e87db0586"}, - {file = "yarl-1.11.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:fe78dec8caeda1e7b353cbd8aa0cc5a5bc182b22998d64ec8fa9ee59c898ab3b"}, - {file = "yarl-1.11.0-cp38-cp38-win32.whl", hash = "sha256:7ff371002fbbb79613269d76a2932c99979dac15fac30107064ef70d25f35474"}, - {file = "yarl-1.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:4fa9d762eee63eed767895d68b994c58e29f809292a4d0fca483e9cc6fdc22c8"}, - {file = "yarl-1.11.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4ae63bc65e5bf8843bd1eca46e75eaa9eb157e0312fb362123181512892daad8"}, - {file = "yarl-1.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3d1bd3262e00043907e0a6d7d4f7b7a4815281acc25699a2384552870c79f1f0"}, - {file = "yarl-1.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c58656c2e0b41b5d325130b8da4f8e216aad10029e7de5c523a6be25faa9fe8"}, - {file = "yarl-1.11.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9425c333575fce5e0fb414b766492c6ba4aa335ef910a7540dbdefe58a78232e"}, - {file = "yarl-1.11.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9dc66e2420e1e282105071934883bbb9c37c16901b5b8aa0a8aee370b477eac6"}, - {file = "yarl-1.11.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2949067359d1ef5bf3228c7f1deb102c209832a13df5419239f99449bc1d3fa9"}, - {file = "yarl-1.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c006fe73f851cf20b9986b3b4cc15239795bd5da9c3fda76bb3e043da5bec4ff"}, - {file = "yarl-1.11.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:969ad4ee3892e893471b6572bbf2bbb091f93e7c81de25d6b3a5c0a5126e5ccb"}, - {file = "yarl-1.11.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c9fbe9dc6ee8bfe1af34137e3add6f0e49799dd5467dd6af189d27616879161e"}, - {file = "yarl-1.11.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69a45c711fea9b783b592a75f26f6dc59b2e4a923b97bf6eec357566fcb1d922"}, - {file = "yarl-1.11.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:1a29b82c42a7791ffe53ee6dfbf29acc61ea7ec05643dcacc50510ed6187b897"}, - {file = "yarl-1.11.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ed0c090f00c3fc024f7b0799cab9dd7c419fcd8f1a00634d1f9952bab7e7bfb2"}, - {file = "yarl-1.11.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:31df9d9b3fe6e15decee629fc7976a5fb21eaa39e290f60e57e1d422827194c6"}, - {file = "yarl-1.11.0-cp39-cp39-win32.whl", hash = "sha256:fcb7c36ba8b663a5900e6d40533f0e698ba0f38f744aad5410d4e38129e41a70"}, - {file = "yarl-1.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:c6c0d640bad721834a737e25267fb71d296684ada21ca7d5ad2e63da7b73f1b7"}, - {file = "yarl-1.11.0-py3-none-any.whl", hash = "sha256:03717a6627e55934b2a1d9caf24f299b461a2e8d048a90920f42ad5c20ae1b82"}, - {file = "yarl-1.11.0.tar.gz", hash = "sha256:f86f4f4a57a29ef08fa70c4667d04c5e3ba513500da95586208b285437cb9592"}, + {file = "yarl-1.15.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e4ee8b8639070ff246ad3649294336b06db37a94bdea0d09ea491603e0be73b8"}, + {file = "yarl-1.15.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a7cf963a357c5f00cb55b1955df8bbe68d2f2f65de065160a1c26b85a1e44172"}, + {file = "yarl-1.15.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:43ebdcc120e2ca679dba01a779333a8ea76b50547b55e812b8b92818d604662c"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3433da95b51a75692dcf6cc8117a31410447c75a9a8187888f02ad45c0a86c50"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38d0124fa992dbacd0c48b1b755d3ee0a9f924f427f95b0ef376556a24debf01"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ded1b1803151dd0f20a8945508786d57c2f97a50289b16f2629f85433e546d47"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace4cad790f3bf872c082366c9edd7f8f8f77afe3992b134cfc810332206884f"}, + {file = "yarl-1.15.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c77494a2f2282d9bbbbcab7c227a4d1b4bb829875c96251f66fb5f3bae4fb053"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b7f227ca6db5a9fda0a2b935a2ea34a7267589ffc63c8045f0e4edb8d8dcf956"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:31561a5b4d8dbef1559b3600b045607cf804bae040f64b5f5bca77da38084a8a"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3e52474256a7db9dcf3c5f4ca0b300fdea6c21cca0148c8891d03a025649d935"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0e1af74a9529a1137c67c887ed9cde62cff53aa4d84a3adbec329f9ec47a3936"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:15c87339490100c63472a76d87fe7097a0835c705eb5ae79fd96e343473629ed"}, + {file = "yarl-1.15.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:74abb8709ea54cc483c4fb57fb17bb66f8e0f04438cff6ded322074dbd17c7ec"}, + {file = "yarl-1.15.2-cp310-cp310-win32.whl", hash = "sha256:ffd591e22b22f9cb48e472529db6a47203c41c2c5911ff0a52e85723196c0d75"}, + {file = "yarl-1.15.2-cp310-cp310-win_amd64.whl", hash = "sha256:1695497bb2a02a6de60064c9f077a4ae9c25c73624e0d43e3aa9d16d983073c2"}, + {file = "yarl-1.15.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9fcda20b2de7042cc35cf911702fa3d8311bd40055a14446c1e62403684afdc5"}, + {file = "yarl-1.15.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0545de8c688fbbf3088f9e8b801157923be4bf8e7b03e97c2ecd4dfa39e48e0e"}, + {file = "yarl-1.15.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fbda058a9a68bec347962595f50546a8a4a34fd7b0654a7b9697917dc2bf810d"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1ac2bc069f4a458634c26b101c2341b18da85cb96afe0015990507efec2e417"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd126498171f752dd85737ab1544329a4520c53eed3997f9b08aefbafb1cc53b"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3db817b4e95eb05c362e3b45dafe7144b18603e1211f4a5b36eb9522ecc62bcf"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:076b1ed2ac819933895b1a000904f62d615fe4533a5cf3e052ff9a1da560575c"}, + {file = "yarl-1.15.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f8cfd847e6b9ecf9f2f2531c8427035f291ec286c0a4944b0a9fce58c6446046"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:32b66be100ac5739065496c74c4b7f3015cef792c3174982809274d7e51b3e04"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:34a2d76a1984cac04ff8b1bfc939ec9dc0914821264d4a9c8fd0ed6aa8d4cfd2"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0afad2cd484908f472c8fe2e8ef499facee54a0a6978be0e0cff67b1254fd747"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c68e820879ff39992c7f148113b46efcd6ec765a4865581f2902b3c43a5f4bbb"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:98f68df80ec6ca3015186b2677c208c096d646ef37bbf8b49764ab4a38183931"}, + {file = "yarl-1.15.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c56ec1eacd0a5d35b8a29f468659c47f4fe61b2cab948ca756c39b7617f0aa5"}, + {file = "yarl-1.15.2-cp311-cp311-win32.whl", hash = "sha256:eedc3f247ee7b3808ea07205f3e7d7879bc19ad3e6222195cd5fbf9988853e4d"}, + {file = "yarl-1.15.2-cp311-cp311-win_amd64.whl", hash = "sha256:0ccaa1bc98751fbfcf53dc8dfdb90d96e98838010fc254180dd6707a6e8bb179"}, + {file = "yarl-1.15.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:82d5161e8cb8f36ec778fd7ac4d740415d84030f5b9ef8fe4da54784a1f46c94"}, + {file = "yarl-1.15.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fa2bea05ff0a8fb4d8124498e00e02398f06d23cdadd0fe027d84a3f7afde31e"}, + {file = "yarl-1.15.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:99e12d2bf587b44deb74e0d6170fec37adb489964dbca656ec41a7cd8f2ff178"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:243fbbbf003754fe41b5bdf10ce1e7f80bcc70732b5b54222c124d6b4c2ab31c"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:856b7f1a7b98a8c31823285786bd566cf06226ac4f38b3ef462f593c608a9bd6"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:553dad9af802a9ad1a6525e7528152a015b85fb8dbf764ebfc755c695f488367"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30c3ff305f6e06650a761c4393666f77384f1cc6c5c0251965d6bfa5fbc88f7f"}, + {file = "yarl-1.15.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:353665775be69bbfc6d54c8d134bfc533e332149faeddd631b0bc79df0897f46"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f4fe99ce44128c71233d0d72152db31ca119711dfc5f2c82385ad611d8d7f897"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9c1e3ff4b89cdd2e1a24c214f141e848b9e0451f08d7d4963cb4108d4d798f1f"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:711bdfae4e699a6d4f371137cbe9e740dc958530cb920eb6f43ff9551e17cfbc"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4388c72174868884f76affcdd3656544c426407e0043c89b684d22fb265e04a5"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f0e1844ad47c7bd5d6fa784f1d4accc5f4168b48999303a868fe0f8597bde715"}, + {file = "yarl-1.15.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a5cafb02cf097a82d74403f7e0b6b9df3ffbfe8edf9415ea816314711764a27b"}, + {file = "yarl-1.15.2-cp312-cp312-win32.whl", hash = "sha256:156ececdf636143f508770bf8a3a0498de64da5abd890c7dbb42ca9e3b6c05b8"}, + {file = "yarl-1.15.2-cp312-cp312-win_amd64.whl", hash = "sha256:435aca062444a7f0c884861d2e3ea79883bd1cd19d0a381928b69ae1b85bc51d"}, + {file = "yarl-1.15.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:416f2e3beaeae81e2f7a45dc711258be5bdc79c940a9a270b266c0bec038fb84"}, + {file = "yarl-1.15.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:173563f3696124372831007e3d4b9821746964a95968628f7075d9231ac6bb33"}, + {file = "yarl-1.15.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9ce2e0f6123a60bd1a7f5ae3b2c49b240c12c132847f17aa990b841a417598a2"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eaea112aed589131f73d50d570a6864728bd7c0c66ef6c9154ed7b59f24da611"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4ca3b9f370f218cc2a0309542cab8d0acdfd66667e7c37d04d617012485f904"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23ec1d3c31882b2a8a69c801ef58ebf7bae2553211ebbddf04235be275a38548"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75119badf45f7183e10e348edff5a76a94dc19ba9287d94001ff05e81475967b"}, + {file = "yarl-1.15.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e6fdc976ec966b99e4daa3812fac0274cc28cd2b24b0d92462e2e5ef90d368"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8657d3f37f781d987037f9cc20bbc8b40425fa14380c87da0cb8dfce7c92d0fb"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:93bed8a8084544c6efe8856c362af08a23e959340c87a95687fdbe9c9f280c8b"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:69d5856d526802cbda768d3e6246cd0d77450fa2a4bc2ea0ea14f0d972c2894b"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:ccad2800dfdff34392448c4bf834be124f10a5bc102f254521d931c1c53c455a"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:a880372e2e5dbb9258a4e8ff43f13888039abb9dd6d515f28611c54361bc5644"}, + {file = "yarl-1.15.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c998d0558805860503bc3a595994895ca0f7835e00668dadc673bbf7f5fbfcbe"}, + {file = "yarl-1.15.2-cp313-cp313-win32.whl", hash = "sha256:533a28754e7f7439f217550a497bb026c54072dbe16402b183fdbca2431935a9"}, + {file = "yarl-1.15.2-cp313-cp313-win_amd64.whl", hash = "sha256:5838f2b79dc8f96fdc44077c9e4e2e33d7089b10788464609df788eb97d03aad"}, + {file = "yarl-1.15.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fbbb63bed5fcd70cd3dd23a087cd78e4675fb5a2963b8af53f945cbbca79ae16"}, + {file = "yarl-1.15.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e2e93b88ecc8f74074012e18d679fb2e9c746f2a56f79cd5e2b1afcf2a8a786b"}, + {file = "yarl-1.15.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:af8ff8d7dc07ce873f643de6dfbcd45dc3db2c87462e5c387267197f59e6d776"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66f629632220a4e7858b58e4857927dd01a850a4cef2fb4044c8662787165cf7"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:833547179c31f9bec39b49601d282d6f0ea1633620701288934c5f66d88c3e50"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2aa738e0282be54eede1e3f36b81f1e46aee7ec7602aa563e81e0e8d7b67963f"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a13a07532e8e1c4a5a3afff0ca4553da23409fad65def1b71186fb867eeae8d"}, + {file = "yarl-1.15.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c45817e3e6972109d1a2c65091504a537e257bc3c885b4e78a95baa96df6a3f8"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:670eb11325ed3a6209339974b276811867defe52f4188fe18dc49855774fa9cf"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:d417a4f6943112fae3924bae2af7112562285848d9bcee737fc4ff7cbd450e6c"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:bc8936d06cd53fddd4892677d65e98af514c8d78c79864f418bbf78a4a2edde4"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:954dde77c404084c2544e572f342aef384240b3e434e06cecc71597e95fd1ce7"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:5bc0df728e4def5e15a754521e8882ba5a5121bd6b5a3a0ff7efda5d6558ab3d"}, + {file = "yarl-1.15.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b71862a652f50babab4a43a487f157d26b464b1dedbcc0afda02fd64f3809d04"}, + {file = "yarl-1.15.2-cp38-cp38-win32.whl", hash = "sha256:63eab904f8630aed5a68f2d0aeab565dcfc595dc1bf0b91b71d9ddd43dea3aea"}, + {file = "yarl-1.15.2-cp38-cp38-win_amd64.whl", hash = "sha256:2cf441c4b6e538ba0d2591574f95d3fdd33f1efafa864faa077d9636ecc0c4e9"}, + {file = "yarl-1.15.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a32d58f4b521bb98b2c0aa9da407f8bd57ca81f34362bcb090e4a79e9924fefc"}, + {file = "yarl-1.15.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:766dcc00b943c089349d4060b935c76281f6be225e39994c2ccec3a2a36ad627"}, + {file = "yarl-1.15.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bed1b5dbf90bad3bfc19439258c97873eab453c71d8b6869c136346acfe497e7"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed20a4bdc635f36cb19e630bfc644181dd075839b6fc84cac51c0f381ac472e2"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d538df442c0d9665664ab6dd5fccd0110fa3b364914f9c85b3ef9b7b2e157980"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c6cf1d92edf936ceedc7afa61b07e9d78a27b15244aa46bbcd534c7458ee1b"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce44217ad99ffad8027d2fde0269ae368c86db66ea0571c62a000798d69401fb"}, + {file = "yarl-1.15.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47a6000a7e833ebfe5886b56a31cb2ff12120b1efd4578a6fcc38df16cc77bd"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e52f77a0cd246086afde8815039f3e16f8d2be51786c0a39b57104c563c5cbb0"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:f9ca0e6ce7774dc7830dc0cc4bb6b3eec769db667f230e7c770a628c1aa5681b"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:136f9db0f53c0206db38b8cd0c985c78ded5fd596c9a86ce5c0b92afb91c3a19"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:173866d9f7409c0fb514cf6e78952e65816600cb888c68b37b41147349fe0057"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:6e840553c9c494a35e449a987ca2c4f8372668ee954a03a9a9685075228e5036"}, + {file = "yarl-1.15.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:458c0c65802d816a6b955cf3603186de79e8fdb46d4f19abaec4ef0a906f50a7"}, + {file = "yarl-1.15.2-cp39-cp39-win32.whl", hash = "sha256:5b48388ded01f6f2429a8c55012bdbd1c2a0c3735b3e73e221649e524c34a58d"}, + {file = "yarl-1.15.2-cp39-cp39-win_amd64.whl", hash = "sha256:81dadafb3aa124f86dc267a2168f71bbd2bfb163663661ab0038f6e4b8edb810"}, + {file = "yarl-1.15.2-py3-none-any.whl", hash = "sha256:0d3105efab7c5c091609abacad33afff33bdff0035bece164c98bcf5a85ef90a"}, + {file = "yarl-1.15.2.tar.gz", hash = "sha256:a39c36f4218a5bb668b4f06874d676d35a035ee668e6e7e3538835c703634b84"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" +propcache = ">=0.2.0" [[package]] name = "zipp" -version = "3.20.1" +version = "3.20.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.20.1-py3-none-any.whl", hash = "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064"}, - {file = "zipp-3.20.1.tar.gz", hash = "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b"}, + {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, + {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, ] [package.extras] From 4f41dfe77866d0fcf25e1d274d631a6772968b0e Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 22 Oct 2024 13:39:57 +0100 Subject: [PATCH 36/43] snapshot --- tests/snapshot_tests/test_snapshots.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index 0516429c6b..b184b9a247 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -2417,3 +2417,8 @@ def on_mount(self) -> None: self.mount(Label("HELLO")) assert snap_compare(PSApp()) + + +def test_split_segments_infinite_loop(snap_compare): + """Regression test for https://github.com/Textualize/textual/issues/5151""" + assert snap_compare(SNAPSHOT_APPS_DIR / "split_segments.py") From 9b8cbf6173c62e1f3a261a0cf261c0500783dfca Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 22 Oct 2024 13:40:14 +0100 Subject: [PATCH 37/43] snapshot --- .../snapshot_tests/snapshot_apps/split_segments.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/snapshot_tests/snapshot_apps/split_segments.py diff --git a/tests/snapshot_tests/snapshot_apps/split_segments.py b/tests/snapshot_tests/snapshot_apps/split_segments.py new file mode 100644 index 0000000000..cb80b63e84 --- /dev/null +++ b/tests/snapshot_tests/snapshot_apps/split_segments.py @@ -0,0 +1,14 @@ +from textual.app import App, ComposeResult +from textual.widgets import TextArea + +FAIL_TEXT = "x " + + +class CodeApp(App): + def compose(self) -> ComposeResult: + yield TextArea(FAIL_TEXT, soft_wrap=False, show_line_numbers=True) + + +if __name__ == "__main__": + app = CodeApp() + app.run() From 4923061d070b787693736ae3cf161ea637c5bf7e Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 22 Oct 2024 13:50:37 +0100 Subject: [PATCH 38/43] snapshot tests --- .../test_split_segments_infinite_loop.svg | 154 ++++++++++++++++++ .../snapshot_apps/split_segments.py | 2 +- tests/snapshot_tests/test_snapshots.py | 6 +- 3 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 tests/snapshot_tests/__snapshots__/test_snapshots/test_split_segments_infinite_loop.svg diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_split_segments_infinite_loop.svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_split_segments_infinite_loop.svg new file mode 100644 index 0000000000..fb874be20f --- /dev/null +++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_split_segments_infinite_loop.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CodeApp + + + + + + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎ +1  x + + + + + + + + + + + + + + + + + + + + + +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎ + + + diff --git a/tests/snapshot_tests/snapshot_apps/split_segments.py b/tests/snapshot_tests/snapshot_apps/split_segments.py index cb80b63e84..9acb6fe28b 100644 --- a/tests/snapshot_tests/snapshot_apps/split_segments.py +++ b/tests/snapshot_tests/snapshot_apps/split_segments.py @@ -1,7 +1,7 @@ from textual.app import App, ComposeResult from textual.widgets import TextArea -FAIL_TEXT = "x " +FAIL_TEXT = "x" class CodeApp(App): diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index b184b9a247..019f49f505 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -2420,5 +2420,9 @@ def on_mount(self) -> None: def test_split_segments_infinite_loop(snap_compare): - """Regression test for https://github.com/Textualize/textual/issues/5151""" + """Regression test for https://github.com/Textualize/textual/issues/5151 + + Should be a bare-bones text editor containing "x" + + """ assert snap_compare(SNAPSHOT_APPS_DIR / "split_segments.py") From 8e755109cfba8dc615bc2d9839932ec2fe0eb596 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 23 Oct 2024 11:56:34 +0100 Subject: [PATCH 39/43] remove -screen-suspended class --- src/textual/screen.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/textual/screen.py b/src/textual/screen.py index ac452ba03f..8fbf68d5db 100644 --- a/src/textual/screen.py +++ b/src/textual/screen.py @@ -1210,7 +1210,6 @@ def _screen_resized(self, size: Size): def _on_screen_resume(self) -> None: """Screen has resumed.""" - self.remove_class("-screen-suspended") self.stack_updates += 1 self.app._refresh_notifications() size = self.app.size @@ -1230,7 +1229,6 @@ def _on_screen_resume(self) -> None: def _on_screen_suspend(self) -> None: """Screen has suspended.""" - self.add_class("-screen-suspended") self.app._set_mouse_over(None) self._clear_tooltip() self.stack_updates += 1 From faae1c6a857ad8969b754ec7d7b7bed559237b29 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 23 Oct 2024 15:57:48 +0100 Subject: [PATCH 40/43] snapshots --- CHANGELOG.md | 21 +-- src/textual/app.py | 9 +- src/textual/renderables/digits.py | 14 +- .../test_collapsible_expanded.svg | 131 +++++++++--------- .../test_snapshots/test_digits.svg | 112 +++++++-------- tests/snapshot_tests/snapshot_apps/digits.py | 6 +- .../snapshot_apps/dock_scroll_off_by_one.py | 2 + .../snapshot_tests/snapshot_apps/scroll_to.py | 2 + 8 files changed, 162 insertions(+), 135 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e8d38f745..049de85098 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,23 +5,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [0.84.0] - 2024-10-22 +## Unreleased ### Changed -- Grid will now size children to the maximum height of a row -- Markdown links will be opened with `App.open_url` automatically -- The universal selector (`*`) will now not match widgets with the class `-textual-system` (scrollbars, notifications etc) +- Grid will now size children to the maximum height of a row https://github.com/Textualize/textual/pull/5113 +- Markdown links will be opened with `App.open_url` automatically https://github.com/Textualize/textual/pull/5113 +- The universal selector (`*`) will now not match widgets with the class `-textual-system` (scrollbars, notifications etc) https://github.com/Textualize/textual/pull/5113 ### Added -- Added Link widget -- Added `open_links` to `Markdown` and `MarkdownViewer` widgets -- Added `background-tint` CSS rule https://github.com/Textualize/textual/pull/5117 -- Added `App.DEFAULT_MODE` -- Added `Containers.HorizontalGroup` and `Containers.VerticalGroup` -- Added `$`, `£`, `€` symbols to Digits +- Added Link widget https://github.com/Textualize/textual/pull/5113 +- Added `open_links` to `Markdown` and `MarkdownViewer` widgets https://github.com/Textualize/textual/pull/5113 +- Added `App.DEFAULT_MODE` https://github.com/Textualize/textual/pull/5113 +- Added `Containers.HorizontalGroup` and `Containers.VerticalGroup` https://github.com/Textualize/textual/pull/5113 +- Added `$`, `£`, `€`, `(`, `)` symbols to Digits https://github.com/Textualize/textual/pull/5113 + +## [0.84.0] - 2024-10-22 ### Fixed diff --git a/src/textual/app.py b/src/textual/app.py index 382d476d3d..438abb1b15 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -493,6 +493,9 @@ class MyApp(App[None]): SUSPENDED_SCREEN_CLASS: ClassVar[str] = "" """Class to apply to suspended screens, or empty string for no class.""" + HOVER_EFFECTS_SCROLL_PAUSE: ClassVar[float] = 0.2 + """Seconds to pause hover effects for when scrolling.""" + _PSEUDO_CLASSES: ClassVar[dict[str, Callable[[App], bool]]] = { "focus": lambda app: app.app_focus, "blur": lambda app: not app.app_focus, @@ -2703,10 +2706,12 @@ def set_focus(self, widget: Widget | None, scroll_visible: bool = True) -> None: def _pause_hover_effects(self): """Pause any hover effects based on Enter and Leave events for 200ms.""" + if not self.HOVER_EFFECTS_SCROLL_PAUSE: + return self._paused_hover_effects = True if self._hover_effects_timer is None: self._hover_effects_timer = self.set_interval( - 0.2, self._resume_hover_effects + self.HOVER_EFFECTS_SCROLL_PAUSE, self._resume_hover_effects ) else: self._hover_effects_timer.reset() @@ -2714,6 +2719,8 @@ def _pause_hover_effects(self): def _resume_hover_effects(self): """Resume sending Enter and Leave for hover effects.""" + if not self.HOVER_EFFECTS_SCROLL_PAUSE: + return if self._paused_hover_effects: self._paused_hover_effects = False if self._hover_effects_timer is not None: diff --git a/src/textual/renderables/digits.py b/src/textual/renderables/digits.py index f751387cf9..c6d982f5dc 100644 --- a/src/textual/renderables/digits.py +++ b/src/textual/renderables/digits.py @@ -5,7 +5,7 @@ from rich.segment import Segment from rich.style import Style, StyleType -DIGITS = " 0123456789+-^x:ABCDEF$£€" +DIGITS = " 0123456789+-^x:ABCDEF$£€()" DIGITS3X3_BOLD = """\ @@ -82,6 +82,12 @@ ╭─╮ ╪═ ╰─╯ +╭╴ +│ +╰╴ + ╶╮ + │ + ╶╯ """.splitlines() @@ -161,6 +167,12 @@ ╭─╮ ╪═ ╰─╯ +╭╴ +│ +╰╴ + ╶╮ + │ + ╶╯ """.splitlines() diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_collapsible_expanded.svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_collapsible_expanded.svg index f734738d0b..7051555a72 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_collapsible_expanded.svg +++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_collapsible_expanded.svg @@ -19,142 +19,141 @@ font-weight: 700; } - .terminal-938527833-matrix { + .terminal-3191182536-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-938527833-title { + .terminal-3191182536-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-938527833-r1 { fill: #121212 } -.terminal-938527833-r2 { fill: #1e1e1e } -.terminal-938527833-r3 { fill: #c5c8c6 } -.terminal-938527833-r4 { fill: #ddedf9 } -.terminal-938527833-r5 { fill: #e2e2e2 } -.terminal-938527833-r6 { fill: #4ebf71;font-weight: bold } -.terminal-938527833-r7 { fill: #14191f } -.terminal-938527833-r8 { fill: #e1e1e1 } -.terminal-938527833-r9 { fill: #fea62b;font-weight: bold } -.terminal-938527833-r10 { fill: #a7a9ab } -.terminal-938527833-r11 { fill: #e2e3e3 } -.terminal-938527833-r12 { fill: #4c5055 } + .terminal-3191182536-r1 { fill: #c5c8c6 } +.terminal-3191182536-r2 { fill: #e1e1e1 } +.terminal-3191182536-r3 { fill: #121212 } +.terminal-3191182536-r4 { fill: #e2e2e2 } +.terminal-3191182536-r5 { fill: #23568b } +.terminal-3191182536-r6 { fill: #1e1e1e } +.terminal-3191182536-r7 { fill: #4ebf71;font-weight: bold } +.terminal-3191182536-r8 { fill: #fea62b;font-weight: bold } +.terminal-3191182536-r9 { fill: #a7a9ab } +.terminal-3191182536-r10 { fill: #e2e3e3 } +.terminal-3191182536-r11 { fill: #4c5055 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - CollapsibleApp + CollapsibleApp - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ -▼ Leto - -# Duke Leto I Atreides - -Head of House Atreides.                                                    - -▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ -▼ Jessica - - - -Lady Jessica - -  Bene Gesserit and concubine of Leto, and mother of Paul and Alia. - - - -▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ -▼ Paul▆▆ - - - - c Collapse All  e Expand All ^p palette + + + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +▼ Jessica + +▂▂ + +Lady Jessica + +  Bene Gesserit and concubine of Leto, and mother of Paul and Alia. + + + +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +▼ Paul + + + +Paul Atreides + +  Son of Leto and Jessica. + + + + c Collapse All  e Expand All ^p palette diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_digits.svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_digits.svg index 238accbed3..25cf2879e4 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_digits.svg +++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_digits.svg @@ -19,133 +19,133 @@ font-weight: 700; } - .terminal-2016553667-matrix { + .terminal-876286072-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2016553667-title { + .terminal-876286072-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2016553667-r1 { fill: #e1e1e1 } -.terminal-2016553667-r2 { fill: #c5c8c6 } -.terminal-2016553667-r3 { fill: #e1e1e1;font-weight: bold } + .terminal-876286072-r1 { fill: #e1e1e1 } +.terminal-876286072-r2 { fill: #c5c8c6 } +.terminal-876286072-r3 { fill: #e1e1e1;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - DigitApp + DigitApp - + - - ╶─╮ ╶╮ ╷ ╷╶─╮╶─┐                                                                 - ─┤  │ ╰─┤┌─┘  │                                                                 -╶─╯.╶┴╴  ╵╰─╴  ╵                                                                 -             ╭─╮╶╮ ╶─╮╶─╮╷ ╷╭─╴╭─╴╶─┐╭─╮╭─╮        ╭─╮┌─╮╭─╮┌─╮╭─╴╭─╴            -             │ │ │ ┌─┘ ─┤╰─┤╰─╮├─╮  │├─┤╰─┤╶┼╴╶─╴  ├─┤├─┤│  │ │├─ ├─             -             ╰─╯╶┴╴╰─╴╶─╯  ╵╶─╯╰─╯  ╵╰─╯╶─╯      .,╵ ╵└─╯╰─╯└─╯╰─╴╵              -             ┏━┓ ┓ ╺━┓╺━┓╻ ╻┏━╸┏━╸╺━┓┏━┓┏━┓        ╭─╮┌─╮╭─╮┌─╮╭─╴╭─╴            -             ┃ ┃ ┃ ┏━┛ ━┫┗━┫┗━┓┣━┓  ┃┣━┫┗━┫╺╋╸╺━╸  ├─┤├─┤│  │ │├─ ├─             -             ┗━┛╺┻╸┗━╸╺━┛  ╹╺━┛┗━┛  ╹┗━┛╺━┛      .,╵ ╵└─╯╰─╯└─╯╰─╴╵              -                                                              ╶─╮   ╶╮ ╭─╮ ^ ╷ ╷ -                                                               ─┤ ×  │ │ │   ╰─┤ -                                                              ╶─╯   ╶┴╴╰─╯     ╵ - - - - - - - - - - - - + + ╶─╮ ╶╮ ╷ ╷╶╮ ╭─╴╭─╮╶─╮╭─╴╭─╴╶─╮╭─╴╭─╮                                            + ─┤  │ ╰─┤ │ ╰─╮╰─┤┌─┘├─╮╰─╮ ─┤╰─╮╰─┤                                            +╶─╯•╶┴╴  ╵╶┴╴╶─╯╶─╯╰─╴╰─╯╶─╯╶─╯╶─╯╶─╯                                            +             ╭─╮╶╮ ╶─╮╶─╮╷ ╷╭─╴╭─╴╶─┐╭─╮╭─╮        ╭─╮┌─╮╭─╮┌─╮╭─╴╭─╴            +             │ │ │ ┌─┘ ─┤╰─┤╰─╮├─╮  │├─┤╰─┤╶┼╴╶─╴  ├─┤├─┤│  │ │├─ ├─             +             ╰─╯╶┴╴╰─╴╶─╯  ╵╶─╯╰─╯  ╵╰─╯╶─╯      •,╵ ╵└─╯╰─╯└─╯╰─╴╵              +             ┏━┓ ┓ ╺━┓╺━┓╻ ╻┏━╸┏━╸╺━┓┏━┓┏━┓        ╭─╮┌─╮╭─╮┌─╮╭─╴╭─╴            +             ┃ ┃ ┃ ┏━┛ ━┫┗━┫┗━┓┣━┓  ┃┣━┫┗━┫╺╋╸╺━╸  ├─┤├─┤│  │ │├─ ├─             +             ┗━┛╺┻╸┗━╸╺━┛  ╹╺━┛┗━┛  ╹┗━┛╺━┛      •,╵ ╵└─╯╰─╯└─╯╰─╴╵              +                                                              ╶─╮   ╶╮ ╭─╮ ^ ╷ ╷ +                                                               ─┤ ×  │ │ │   ╰─┤ +                                                              ╶─╯   ╶┴╴╰─╯     ╵ +                                                              ╶─╮   ╶╮ ╭─╮ ^ ╷ ╷ +                                                               ─┤ ×  │ │ │   ╰─┤ +                                                              ╶─╯   ╶┴╴╰─╯     ╵ +╭╴ ╭╫╮╶╮ ╶─╮╶─╮ ╷ ╷╭─╴ ╶╮                                                        +│  ╰╫╮ │ ┌─┘ ─┤ ╰─┤╰─╮  │                                                        +╰╴ ╰╫╯╶┴╴╰─╴╶─╯•  ╵╶─╯ ╶╯                                                        +╭─╮╶╮ ╶─╮╶─╮ ╷ ╷╭─╴                                                              +╪═  │ ┌─┘ ─┤ ╰─┤╰─╮                                                              +┴─╴╶┴╴╰─╴╶─╯•  ╵╶─╯                                                              +╭─╮╶╮ ╶─╮╶─╮ ╷ ╷╭─╴                                                              +╪═  │ ┌─┘ ─┤ ╰─┤╰─╮                                                              +╰─╯╶┴╴╰─╴╶─╯•  ╵╶─╯                                                              diff --git a/tests/snapshot_tests/snapshot_apps/digits.py b/tests/snapshot_tests/snapshot_apps/digits.py index 93d7c5df32..0eb16e9da2 100644 --- a/tests/snapshot_tests/snapshot_apps/digits.py +++ b/tests/snapshot_tests/snapshot_apps/digits.py @@ -19,10 +19,14 @@ class DigitApp(App): """ def compose(self) -> ComposeResult: - yield Digits("3.1427", classes="left") + yield Digits("3.14159265359", classes="left") yield Digits(" 0123456789+-.,ABCDEF", classes="center") yield Digits(" 0123456789+-.,ABCDEF", classes="center bold") yield Digits("3x10^4", classes="right") + yield Digits("3x10^4", classes="right") + yield Digits("($123.45)") + yield Digits("£123.45") + yield Digits("€123.45") if __name__ == "__main__": diff --git a/tests/snapshot_tests/snapshot_apps/dock_scroll_off_by_one.py b/tests/snapshot_tests/snapshot_apps/dock_scroll_off_by_one.py index f9a5a00fd0..3a3f531768 100644 --- a/tests/snapshot_tests/snapshot_apps/dock_scroll_off_by_one.py +++ b/tests/snapshot_tests/snapshot_apps/dock_scroll_off_by_one.py @@ -3,6 +3,8 @@ class ScrollOffByOne(App): + HOVER_EFFECTS_SCROLL_PAUSE = 0.0 + def compose(self) -> ComposeResult: for number in range(1, 100): yield Checkbox(str(number)) diff --git a/tests/snapshot_tests/snapshot_apps/scroll_to.py b/tests/snapshot_tests/snapshot_apps/scroll_to.py index 9dd21a3fc4..b3673eb269 100644 --- a/tests/snapshot_tests/snapshot_apps/scroll_to.py +++ b/tests/snapshot_tests/snapshot_apps/scroll_to.py @@ -5,6 +5,8 @@ class ScrollOffByOne(App): """Scroll to item 50.""" + HOVER_EFFECTS_SCROLL_PAUSE = 0 + def compose(self) -> ComposeResult: for number in range(1, 100): yield Checkbox(str(number), id=f"number-{number}") From b1bf8a88a5e7ea6953fff2b88c3d422f04a31da4 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 23 Oct 2024 15:59:38 +0100 Subject: [PATCH 41/43] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 049de85098..ef410b0749 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `App.DEFAULT_MODE` https://github.com/Textualize/textual/pull/5113 - Added `Containers.HorizontalGroup` and `Containers.VerticalGroup` https://github.com/Textualize/textual/pull/5113 - Added `$`, `£`, `€`, `(`, `)` symbols to Digits https://github.com/Textualize/textual/pull/5113 +- Added `Button.action` parameter to invoke action when clicked https://github.com/Textualize/textual/pull/5113 ## [0.84.0] - 2024-10-22 From 2b43743cac46838645033981bd7df9624c1c89f1 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 24 Oct 2024 11:45:57 +0100 Subject: [PATCH 42/43] no hover pause in tests --- src/textual/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/textual/app.py b/src/textual/app.py index 438abb1b15..36fbe50f15 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -2706,7 +2706,7 @@ def set_focus(self, widget: Widget | None, scroll_visible: bool = True) -> None: def _pause_hover_effects(self): """Pause any hover effects based on Enter and Leave events for 200ms.""" - if not self.HOVER_EFFECTS_SCROLL_PAUSE: + if not self.HOVER_EFFECTS_SCROLL_PAUSE or self.is_headless: return self._paused_hover_effects = True if self._hover_effects_timer is None: @@ -2719,7 +2719,7 @@ def _pause_hover_effects(self): def _resume_hover_effects(self): """Resume sending Enter and Leave for hover effects.""" - if not self.HOVER_EFFECTS_SCROLL_PAUSE: + if not self.HOVER_EFFECTS_SCROLL_PAUSE or self.is_headless: return if self._paused_hover_effects: self._paused_hover_effects = False From 92d391eebd7f1cd68eb29126456155d8b392ec06 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 24 Oct 2024 12:11:13 +0100 Subject: [PATCH 43/43] fix for stars --- src/textual/demo2/projects.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/textual/demo2/projects.py b/src/textual/demo2/projects.py index 045eb24016..e5fa217491 100644 --- a/src/textual/demo2/projects.py +++ b/src/textual/demo2/projects.py @@ -141,13 +141,13 @@ class Project(Vertical, can_focus=True, can_focus_children=False): background: $primary 40%; opacity: 1.0; } - #title { text-style: bold; } + #title { text-style: bold; width: 1fr; } #author { text-style: italic; } .stars { color: $secondary; text-align: right; text-style: bold; - width: 1fr; + width: auto; } .header { height: 1; } .link {