diff --git a/docs/design/interface/cli.qmd b/docs/design/interface/cli.qmd
index 2500a819..9e3b026e 100644
--- a/docs/design/interface/cli.qmd
+++ b/docs/design/interface/cli.qmd
@@ -182,13 +182,13 @@ human-friendly way in the terminal. It has the following signature that
is positional as well as keyword-based:
``` {.bash filename="Terminal"}
-seedcase-flower view [SOURCE] [STYLE]
+seedcase-flower view [SOURCE] [MODE]
```
For example:
``` {.bash filename="Terminal"}
-seedcase-flower view SOURCE --style STYLE
+seedcase-flower view SOURCE --mode stdout
```
The diagram below shows the flow of inputs and outputs for `view`.
@@ -199,27 +199,20 @@ The diagram below shows the flow of inputs and outputs for `view`.
flowchart LR
source("datapackage.json
[SOURCE: file, https,
gh/github]")
view("view")
- style_opt("--style
[option]")
- output("Output
[Terminal]")
+ mode_opt("--mode
[option]")
+ output("Output
[TUI or stdout]")
source --> view
- style_opt --> view
+ mode_opt --> view
view --> output
```
-`view` takes a `SOURCE` and `--style` argument like `build`, with two
-differences:
+`view` takes a `SOURCE` and an optional `--mode` argument, with two modes:
-- No output files are generated---`view` only displays the metadata in
- the terminal.
-- No configuration file is used. The only way to change the output is
- via `--style` with one of the built-in styles.
+- `tui` opens an interactive terminal interface.
+- `stdout` prints a plain terminal representation that can be piped to
+ other tools.
`view` intentionally has no configuration file support; it's meant for
quick, lightweight inspection of a Data Package's metadata and terminal
display also limits customisation options.
-
-::: callout-tip
-Want a different style for viewing the metadata? Check out our
-[contribute a style](/docs/guide/contribute-style.qmd) guide.
-:::
diff --git a/docs/design/interface/python.qmd b/docs/design/interface/python.qmd
index 5c6ddcbf..a29bbaf1 100644
--- a/docs/design/interface/python.qmd
+++ b/docs/design/interface/python.qmd
@@ -82,11 +82,11 @@ flowchart TD
### {{< var done >}} `view()`
-`view()` takes the same parameters as `build()`: `source` and `style`.
-Unlike `build()`, `view()`'s `style` parameter only accepts built-in
-one-page styles (the terminal displays a single page) and ignores custom
-styles and the configuration file. For details about the parameters, see
-[`view()`](/docs/reference/view.qmd).
+`view()` takes a `source` and a display `mode`. Unlike `build()`,
+`view()` does not use styles, custom templates, output files, or the
+configuration file. The metadata is shown in an interactive TUI by
+default, or printed to stdout when `mode="stdout"`. For details about
+the parameters, see [`view()`](/docs/reference/view.qmd).
The internal flow of `view()` is shown in the diagram below.
@@ -95,10 +95,9 @@ The internal flow of `view()` is shown in the diagram below.
%%| fig-cap: "Diagram of the internal flow of functions and objects in the `view()` CLI function."
flowchart TD
source:::input --> parse_source{{"parse_source()"}} --> address
- style_cfg[style]:::input --> Config
+ mode[mode]:::input
address --> read_properties{{"read_properties()"}} --> properties
- properties & Config --> build_sections{{"build_sections()"}} --> output["list[BuiltSection]"]
- output --> pretty_print{{"pretty_print()"}}
+ properties & mode --> output{{"TUI or stdout"}}
classDef input fill:#FFF
```
diff --git a/docs/guide/cli.qmd b/docs/guide/cli.qmd
index d647843c..c2363683 100644
--- a/docs/guide/cli.qmd
+++ b/docs/guide/cli.qmd
@@ -96,24 +96,20 @@ terminal, so some aspects of it might not display as expected here.
```{python}
#| echo: false
-!uv run seedcase-flower view gh:seedcase-project/example-seed-beetle
+!uv run seedcase-flower view --mode stdout gh:seedcase-project/example-seed-beetle
```
:::
-### Styling terminal output
+### Plain terminal output
-Use the `--style` flag to format the terminal output with any of the
-[built-in view styles](/docs/reference/ViewStyle.qmd). For example:
+By default, `view` opens an interactive TUI. Use `--mode stdout` to
+print a plain terminal representation that can be piped to tools like
+`less`:
```{.bash filename="Terminal"}
-seedcase-flower view --style quarto-one-page gh:seedcase-project/example-seed-beetle
+seedcase-flower view --mode stdout gh:seedcase-project/example-seed-beetle | less -R
```
-
-
-This output will look identical to the output above, since
-`quarto-one-page` is the default style for `view`.
-
::: {.callout-tip collapse="true" icon="false"}
### Output
@@ -122,13 +118,30 @@ terminal, so some aspects of it might not display as expected here.
```{python}
#| echo: false
-!uv run seedcase-flower view --style quarto-one-page gh:seedcase-project/example-seed-beetle
+!uv run seedcase-flower view --mode stdout gh:seedcase-project/example-seed-beetle
```
:::
-`view` only works with single-page
-[built-in styles](/docs/reference/Style.qmd); multi-page styles are not
-supported.
+### Interactive TUI
+
+The default `view` mode shows the package and resources in a left-hand
+table of contents and the selected section in a scrollable content pane:
+
+```{.bash filename="Terminal"}
+seedcase-flower view gh:seedcase-project/example-seed-beetle
+```
+
+In the TUI, use `j` and `k` or the arrow keys to move through the table
+of contents. Press `l` or the right arrow to focus the current page's
+table. Press `l` or the right arrow again to select columns, and `h` or
+the left arrow to move back through selected columns, row selection, and
+the table of contents. Use `ctrl+d` and `ctrl+u` to move six items down
+or up. For tables, use `s` to cycle sorting through the columns and
+directions, `ctrl+f` or `/` to search all tables, `c` or `y` to copy the
+selected row or column, and `q` or `ctrl+q` to quit. Press `?` to show
+all keyboard shortcuts, and press `?` again to close them. The sorted
+column shows an arrow for ascending or descending order, and the table
+of contents hides resources whose tables have no search matches.
::: callout-important
`view` is only configurable via command line flags. This means that any
diff --git a/docs/guide/contribute-style.qmd b/docs/guide/contribute-style.qmd
index 30d28423..cdf4e937 100644
--- a/docs/guide/contribute-style.qmd
+++ b/docs/guide/contribute-style.qmd
@@ -34,10 +34,9 @@ should be short, descriptive, and distinct from existing built-in
styles. It should be given in snake case (e.g., `my_new_style`).
::: callout-note
-A terminal style for the `view` command must be a single-page output
-style, meaning it can only use a single `[[one]]` section. `view`
-ignores `output-path` since it doesn't output files and single-page
-styles can be used by `build` as well.
+The `view` command can display built-in styles with one or more
+sections. Multi-section styles are rendered as one paged terminal
+document, with each section labelled by its `output-path`.
:::
## Adding the style as built-in
@@ -63,11 +62,10 @@ license, or schema fields. Remember to give your templates descriptive
names. The `.qmd` extension serves as an example; Jinja2 can produce any
plain text format (e.g., `.html`, `.md`, `.yml`).
-Finally, add your style to the appropriate style enum(s) in
-`src/seedcase_flower/styles.py`. All styles are defined in the `Style`
-enum, while styles for terminal output with `view` are also added to
-`ViewStyle`. For example, if `your_new_style` is your new style, you
-would include it in `Style` like so:
+Finally, add your style to the style enum in
+`src/seedcase_flower/styles.py`. Build styles are defined in the `Style`
+enum. For example, if `your_new_style` is your new style, you would
+include it in `Style` like so:
``` {.python filename="src/seedcase_flower/styles.py"}
class Style(Enum):
@@ -75,15 +73,6 @@ class Style(Enum):
your_new_style = "your_new_style"
```
-If your style is also a terminal style for the `view` command, add it
-below the existing styles in the `ViewStyle` enum as well:
-
-``` {.python filename="src/seedcase_flower/styles.py"}
-class ViewStyle(Enum):
- # ...
- your_new_style = "your_new_style"
-```
-
::: callout-important
For the new style to work properly, the string value of the enum member
(e.g., `"your_new_style"`) must exactly match the folder name.
diff --git a/pyproject.toml b/pyproject.toml
index f76bb274..b81a864c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -34,6 +34,7 @@ dependencies = [
"python-jsonpath>=2.0.2",
"rich>=14.3.3",
"seedcase-soil>=0.11.0",
+ "textual>=8.2.5",
]
[project.urls]
diff --git a/src/seedcase_flower/__init__.py b/src/seedcase_flower/__init__.py
index 955f9e8c..83fcf259 100644
--- a/src/seedcase_flower/__init__.py
+++ b/src/seedcase_flower/__init__.py
@@ -3,14 +3,13 @@
from .cli import build, view
from .config import Config
from .sections import Content, Many, ManyContent, One
-from .styles import Style, ViewStyle
+from .styles import Style
__all__ = [
"build",
"view",
"Config",
"Style",
- "ViewStyle",
"Content",
"One",
"Many",
diff --git a/src/seedcase_flower/cli.py b/src/seedcase_flower/cli.py
index 61793a66..8680fa1f 100644
--- a/src/seedcase_flower/cli.py
+++ b/src/seedcase_flower/cli.py
@@ -1,5 +1,6 @@
"""Functions for the exposed CLI."""
+from enum import Enum
from pathlib import Path
from typing import Any, Optional
@@ -20,7 +21,7 @@
from seedcase_flower.build_sections import build_sections
from seedcase_flower.config import Config
from seedcase_flower.internals import _number
-from seedcase_flower.styles import Style, ViewStyle
+from seedcase_flower.styles import Style
from seedcase_flower.write_sections import write_sections
app = setup_cli(
@@ -30,6 +31,13 @@
)
+class ViewMode(Enum):
+ """Ways to display `view` output in the terminal."""
+
+ tui = "tui"
+ stdout = "stdout"
+
+
@app.command()
def build(
source: str = "datapackage.json",
@@ -92,7 +100,7 @@ def view(
source: str = "datapackage.json",
/, # End of positional-only args
*, # Start of keyword-only params
- style: ViewStyle = ViewStyle.quarto_one_page,
+ mode: ViewMode = ViewMode.tui,
) -> None:
"""Display the contents of a `datapackage.json` in a human-friendly way.
@@ -103,17 +111,21 @@ def view(
in the repo root (in the format `gh:org/repo`, which can also include
reference to a tag or branch, such as `gh:org/repo@main` or
`gh:org/repo@1.0.1`).
- style: The style used to display the output in the terminal. Must be a
- single-page style.
+ mode: The terminal display mode. Use `tui` for an interactive interface
+ or `stdout` for plain output that can be piped to other tools.
"""
address: Address = parse_source(source)
properties: dict[str, Any] = read_properties(address)
check(properties, error=True)
- built_sections = build_sections(properties, Config(style=Style[style.name]))
+ if mode == ViewMode.tui:
+ from seedcase_flower.tui import run_textual_viewer
+
+ run_textual_viewer(properties)
+ return
+
console = Console(theme=CONSOLE_THEME)
- # TODO move back console theme? will it be used in CDP?
- print() # One line separation between the command and the datapackage title
- console.print(Markdown(built_sections[0].content))
+ for section in build_sections(properties, Config(style=Style.quarto_one_page)):
+ console.print(Markdown(section.content))
def main() -> None:
diff --git a/src/seedcase_flower/styles.py b/src/seedcase_flower/styles.py
index 48912b5b..420cfe4b 100644
--- a/src/seedcase_flower/styles.py
+++ b/src/seedcase_flower/styles.py
@@ -7,9 +7,3 @@ class Style(Enum):
quarto_one_page = "quarto_one_page"
quarto_resource_listing = "quarto_resource_listing"
quarto_resource_tables = "quarto_resource_tables"
-
-
-class ViewStyle(Enum):
- """Subset of styles suitable for terminal output (single-page only)."""
-
- quarto_one_page = "quarto_one_page"
diff --git a/src/seedcase_flower/tui.py b/src/seedcase_flower/tui.py
new file mode 100644
index 00000000..98ba616b
--- /dev/null
+++ b/src/seedcase_flower/tui.py
@@ -0,0 +1,831 @@
+"""Textual terminal app for browsing Data Package metadata."""
+
+from dataclasses import dataclass
+from typing import Any
+
+from rich.text import Text
+from textual.app import App, ComposeResult
+from textual.binding import Binding
+from textual.containers import Horizontal, VerticalScroll
+from textual.timer import Timer
+from textual.widgets import (
+ ContentSwitcher,
+ DataTable,
+ Footer,
+ Header,
+ Input,
+ Label,
+ ListItem,
+ ListView,
+ Static,
+)
+from textual.widgets._data_table import ColumnKey
+
+RICH_BLUE = "color(4) bold"
+RICH_YELLOW = "color(3) bold"
+HIGHLIGHT_DEBOUNCE_SECONDS = 0.1
+
+
+@dataclass(frozen=True)
+class ViewPage:
+ """A Data Package page prepared for navigation in the Textual viewer."""
+
+ label: str
+ id: str
+ blocks: list["ViewBlock"]
+
+
+@dataclass(frozen=True)
+class TextBlock:
+ """A text fragment in a Textual viewer page."""
+
+ content: str
+ style: str = ""
+ classes: str = "body-text"
+ spans: tuple[tuple[int, int, str], ...] = ()
+
+
+@dataclass(frozen=True)
+class TableBlock:
+ """Structured table data prepared for Textual's DataTable."""
+
+ headers: list[str]
+ rows: list[list[str]]
+
+
+type ViewBlock = TextBlock | TableBlock
+
+
+def prepare_view_pages(properties: dict[str, Any]) -> list[ViewPage]:
+ """Prepare Data Package properties for display in the Textual viewer."""
+ pages = [
+ ViewPage(
+ label="Package",
+ id="page-1",
+ blocks=_package_blocks(properties),
+ )
+ ]
+ pages.extend(
+ ViewPage(
+ label=resource.get("name", f"Resource {index}"),
+ id=f"page-{index + 1}",
+ blocks=_resource_blocks(resource),
+ )
+ for index, resource in enumerate(properties.get("resources", []), start=1)
+ )
+ return pages
+
+
+def _package_blocks(properties: dict[str, Any]) -> list[ViewBlock]:
+ blocks: list[ViewBlock] = []
+ title = _package_title(properties)
+ if title:
+ blocks.append(TextBlock(title, style=RICH_BLUE, classes="title"))
+
+ if description := properties.get("description"):
+ blocks.append(TextBlock(description))
+ if version := properties.get("version"):
+ blocks.append(_labeled_list("Version", [version]))
+ if licenses := properties.get("licenses"):
+ blocks.append(
+ TextBlock("Licenses", style=RICH_YELLOW, classes="compact-heading")
+ )
+ blocks.append(
+ TextBlock("\n".join(_license_text(licenses)), classes="metadata-list")
+ )
+ if contributors := properties.get("contributors"):
+ blocks.append(
+ TextBlock("Contributors", style=RICH_YELLOW, classes="compact-heading")
+ )
+ blocks.append(
+ TextBlock(
+ "\n".join(_contributor_text(contributors)), classes="metadata-list"
+ )
+ )
+ if resources := properties.get("resources"):
+ blocks.append(TextBlock("Resources", style=RICH_YELLOW, classes="heading"))
+ blocks.append(
+ TableBlock(
+ headers=["Name", "Title", "Description"],
+ rows=[
+ [
+ resource.get("name", ""),
+ resource.get("title", ""),
+ resource.get("description", ""),
+ ]
+ for resource in resources
+ ],
+ )
+ )
+ return blocks
+
+
+def _package_title(properties: dict[str, Any]) -> str:
+ name = properties.get("name")
+ title = properties.get("title")
+ if name and title:
+ return f"{name}: {title}"
+ return name or title or ""
+
+
+def _license_text(licenses: list[dict[str, Any]]) -> list[str]:
+ return [
+ f"• {label}"
+ for license in licenses
+ if (label := license.get("title") or license.get("name"))
+ ]
+
+
+def _contributor_text(contributors: list[dict[str, Any]]) -> list[str]:
+ return [
+ text
+ for contributor in contributors
+ if (text := _single_contributor_text(contributor))
+ ]
+
+
+def _single_contributor_text(contributor: dict[str, Any]) -> str:
+ full_name = (
+ f"{contributor.get('firstName', '')} {contributor.get('lastName', '')}"
+ ).strip()
+ label = (
+ contributor.get("title")
+ or full_name
+ or contributor.get("organization")
+ or contributor.get("email")
+ or ""
+ )
+ roles = ", ".join(contributor.get("roles", []))
+ return f"• {label}{': ' + roles if roles else ''}" if label else ""
+
+
+def _resource_blocks(resource: dict[str, Any]) -> list[ViewBlock]:
+ blocks: list[ViewBlock] = []
+ resource_name = resource.get("name", "")
+ title = resource.get("title") or resource_name
+ if title:
+ blocks.append(TextBlock(title, style=RICH_BLUE, classes="title"))
+
+ if description := _resource_description(resource):
+ blocks.append(TextBlock(description))
+
+ schema = resource.get("schema") or {}
+ blocks.extend(_resource_metadata_blocks(resource, schema))
+
+ if fields := schema.get("fields"):
+ blocks.append(TextBlock("Fields", style=RICH_YELLOW, classes="heading"))
+ blocks.append(
+ TableBlock(
+ headers=["Name", "Title", "Type", "Description"],
+ rows=[
+ [
+ field.get("name", ""),
+ field.get("title", ""),
+ field.get("type", "any"),
+ field.get("description", ""),
+ ]
+ for field in fields
+ ],
+ )
+ )
+ return blocks
+
+
+def _resource_description(resource: dict[str, Any]) -> str:
+ description = resource.get("description", "")
+ resource_name = resource.get("name", "")
+ title = resource.get("title", "")
+ labels = {_metadata_label(resource_name), _metadata_label(title)}
+ return "" if _metadata_label(description) in labels else description
+
+
+def _metadata_label(value: str) -> str:
+ return value.strip().strip("`")
+
+
+def _resource_metadata_blocks(
+ resource: dict[str, Any], schema: dict[str, Any]
+) -> list[TextBlock]:
+ blocks = []
+ if path := resource.get("path"):
+ blocks.append(_labeled_list("Path", [path]))
+ if primary_key := schema.get("primaryKey"):
+ blocks.append(_labeled_list("Primary key", [_as_list_text(primary_key)]))
+ if foreign_keys := schema.get("foreignKeys"):
+ blocks.append(
+ _labeled_list("Foreign keys", _foreign_key_text(foreign_keys, resource))
+ )
+ return blocks
+
+
+def _labeled_list(label: str, values: list[str]) -> TextBlock:
+ lines = [label] + [f"• {value}" for value in values]
+ return TextBlock(
+ "\n".join(lines),
+ classes="metadata-list",
+ spans=((0, len(label), RICH_YELLOW),),
+ )
+
+
+def _as_list_text(value: str | list[str]) -> str:
+ return value if isinstance(value, str) else ", ".join(value)
+
+
+def _foreign_key_text(
+ foreign_keys: list[dict[str, Any]], resource: dict[str, Any]
+) -> list[str]:
+ lines = []
+ for foreign_key in foreign_keys:
+ reference = foreign_key.get("reference", {})
+ reference_resource = reference.get("resource") or resource.get("name", "")
+ lines.append(
+ f"{_as_list_text(foreign_key.get('fields', []))} → "
+ f"{reference_resource}.{_as_list_text(reference.get('fields', []))}"
+ )
+ return lines
+
+
+class FlowerViewApp(App[None]):
+ """Interactive terminal viewer for Data Package documentation sections."""
+
+ CSS = """
+ Screen {
+ layout: vertical;
+ background: ansi_default;
+ color: ansi_default;
+ }
+
+ Header, Footer {
+ background: #292E42;
+ background-tint: ansi_default 0%;
+ color: ansi_default;
+ }
+
+ FooterLabel, FooterKey {
+ background: #292E42;
+ background-tint: ansi_default 0%;
+ color: ansi_default;
+ }
+
+ #body {
+ height: 1fr;
+ background: ansi_default;
+ }
+
+ #toc {
+ width: 32;
+ min-width: 24;
+ height: 100%;
+ background: #292E42;
+ background-tint: ansi_default 0%;
+ color: ansi_default;
+ border-right: solid ansi_white;
+ }
+
+ #toc:focus {
+ background-tint: ansi_default 0%;
+ }
+
+ #content-switcher {
+ width: 1fr;
+ height: 100%;
+ padding: 0 1;
+ background: ansi_default;
+ }
+
+ .content-page {
+ width: 1fr;
+ height: 100%;
+ }
+
+ ListItem {
+ width: 100%;
+ }
+
+ ListItem > Label {
+ width: 100%;
+ padding: 0 1;
+ color: ansi_default;
+ }
+
+ #toc > ListItem.-highlight {
+ background: #292E42;
+ color: ansi_default;
+ }
+
+ #toc > ListItem.-highlight > Label {
+ background: #292E42;
+ color: ansi_default;
+ }
+
+ #toc:focus > ListItem.-highlight {
+ background: ansi_yellow;
+ color: #1A1B26;
+ }
+
+ #toc:focus > ListItem.-highlight > Label {
+ background: ansi_yellow;
+ color: #1A1B26;
+ }
+
+ PageView {
+ width: 1fr;
+ height: 100%;
+ background: ansi_default;
+ }
+
+ .body-text {
+ margin: 0 0 1 0;
+ color: ansi_default;
+ }
+
+ .metadata-list {
+ margin: 0;
+ color: ansi_default;
+ }
+
+ .title {
+ margin: 0 0 1 0;
+ color: ansi_blue;
+ text-style: bold;
+ }
+
+ .subtitle {
+ margin: 0 0 1 0;
+ }
+
+ .heading {
+ margin: 1 0 0 0;
+ color: ansi_yellow;
+ text-style: bold;
+ }
+
+ .compact-heading {
+ margin: 0;
+ color: ansi_yellow;
+ text-style: bold;
+ }
+
+ .field-table {
+ width: 1fr;
+ height: 1fr;
+ min-height: 8;
+ background: ansi_default;
+ color: ansi_default;
+ }
+
+ .field-table > .datatable--header {
+ background: ansi_default;
+ color: ansi_blue;
+ text-style: bold;
+ }
+
+ .field-table > .datatable--cursor {
+ background: ansi_yellow;
+ color: #1A1B26;
+ }
+
+ #table-search {
+ display: none;
+ height: 3;
+ background: #292E42;
+ color: ansi_yellow;
+ text-style: bold;
+ border: solid ansi_yellow;
+ }
+
+ Toast {
+ background: #292E42;
+ color: ansi_default;
+ border-left: outer ansi_yellow;
+ }
+
+ Toast:ansi {
+ background: #292E42;
+ }
+
+ ToastRack {
+ margin-bottom: 2;
+ }
+ """
+ COMMAND_PALETTE_DISPLAY = "ctrl+p"
+ BINDINGS = [
+ Binding("ctrl+q", "quit", "Quit", key_display="ctrl+q |", show=False),
+ Binding("q", "quit", "Quit"),
+ Binding("?", "toggle_help_panel", "Keyboard shortcuts"),
+ Binding(
+ "ctrl+p",
+ "command_palette",
+ "Command Palette",
+ key_display="ctrl+p",
+ show=False,
+ ),
+ Binding("j,down", "toc_down", "Down", key_display="down | j", show=False),
+ Binding("k,up", "toc_up", "Up", key_display="up | k", show=False),
+ Binding(
+ "l,right", "focus_table", "Select", key_display="right | l", show=False
+ ),
+ Binding("h,left", "focus_toc", "Back", key_display="left | h", show=False),
+ Binding("y,c", "copy_selection", "Copy", key_display="c | y", show=False),
+ Binding("s", "sort_table", "Sort table", show=False),
+ Binding(
+ "/,ctrl+f",
+ "search_table",
+ "Search",
+ key_display="ctrl+f | /",
+ show=False,
+ ),
+ Binding("ctrl+d", "jump_down", "Jump down", key_display="ctrl+d", show=False),
+ Binding("ctrl+u", "jump_up", "Jump up", key_display="ctrl+u", show=False),
+ ]
+ TITLE = "Flower"
+
+ def __init__(self, pages: list[ViewPage]) -> None:
+ """Initialize the app with pages to display."""
+ super().__init__(ansi_color=True)
+ self.pages = pages
+ self._pending_page_index: int | None = None
+ self._highlight_timer: Timer | None = None
+
+ def get_key_display(self, binding: Binding) -> str:
+ """Format key labels with explicit ctrl names instead of caret syntax."""
+ key_display = super().get_key_display(binding)
+ return key_display.replace("^", "ctrl+")
+
+ def action_toggle_help_panel(self) -> None:
+ """Toggle the keyboard shortcuts help panel."""
+ if self.screen.query("HelpPanel"):
+ self.action_hide_help_panel()
+ else:
+ self.action_show_help_panel()
+
+ def compose(self) -> ComposeResult:
+ """Compose the page navigation and content widgets."""
+ initial_page = self.pages[0]
+ self.sub_title = initial_page.label
+ yield Header()
+ with Horizontal(id="body"):
+ yield ListView(
+ *[ListItem(Label(page.label)) for page in self.pages], id="toc"
+ )
+ with ContentSwitcher(id="content-switcher", initial=initial_page.id):
+ for page in self.pages:
+ yield PageView(page.blocks, id=page.id, classes="content-page")
+ yield SearchInput(placeholder="Search all tables", id="table-search")
+ yield Footer()
+
+ def on_mount(self) -> None:
+ """Focus page navigation when the app starts."""
+ self.query_one("#toc", ListView).focus()
+
+ async def on_list_view_highlighted(self, event: ListView.Highlighted) -> None:
+ """Show the highlighted page in the content pane."""
+ index = event.list_view.index
+ if index is not None:
+ self._pending_page_index = index
+ if self._highlight_timer is not None:
+ self._highlight_timer.stop()
+ self._highlight_timer = self.set_timer(
+ HIGHLIGHT_DEBOUNCE_SECONDS,
+ self._show_pending_page,
+ )
+
+ async def on_list_view_selected(self, event: ListView.Selected) -> None:
+ """Show the selected page in the content pane."""
+ if self._highlight_timer is not None:
+ self._highlight_timer.stop()
+ self._pending_page_index = None
+ await self._show_page(event.index)
+
+ def action_toc_down(self) -> None:
+ """Move down in the focused table or page navigation."""
+ self._move_focused(1)
+
+ def action_toc_up(self) -> None:
+ """Move up in the focused table or page navigation."""
+ self._move_focused(-1)
+
+ def action_jump_down(self) -> None:
+ """Move down six rows or table-of-contents items."""
+ self._move_focused(6)
+
+ def action_jump_up(self) -> None:
+ """Move up six rows or table-of-contents items."""
+ self._move_focused(-6)
+
+ def _move_focused(self, step: int) -> None:
+ """Move the focused table or sidebar by one or more rows."""
+ if isinstance(self.focused, SearchableDataTable):
+ action = (
+ self.focused.action_cursor_down
+ if step > 0
+ else self.focused.action_cursor_up
+ )
+ for _ in range(abs(step)):
+ action()
+ return
+ self._move_toc(step)
+
+ def _move_toc(self, step: int) -> None:
+ """Move to the next visible table-of-contents item."""
+ toc = self.query_one("#toc", ListView)
+ visible_indices = self._visible_toc_indices()
+ if not visible_indices:
+ return
+
+ current = toc.index if toc.index is not None else self._current_page_index()
+ if current is None or current not in visible_indices:
+ toc.index = visible_indices[0 if step > 0 else -1]
+ return
+
+ current_position = visible_indices.index(current)
+ next_position = max(
+ 0,
+ min(len(visible_indices) - 1, current_position + step),
+ )
+ toc.index = visible_indices[next_position]
+
+ def action_search_table(self) -> None:
+ """Focus the table search input."""
+ search = self.query_one("#table-search", Input)
+ search.display = True
+ search.focus()
+
+ def action_copy_selection(self) -> None:
+ """Copy the selected row or column and show a toast notification."""
+ if isinstance(self.focused, SearchableDataTable):
+ text = self.focused.selected_text()
+ if text:
+ self.copy_to_clipboard(text)
+ self.notify("Selection copied", markup=False)
+
+ def action_sort_table(self) -> None:
+ """Sort the current page table by the next column."""
+ if table := self._current_table():
+ table.sort_next_column()
+
+ def action_focus_table(self) -> None:
+ """Focus the current page table or advance its column selection."""
+ if isinstance(self.focused, SearchableDataTable):
+ self.focused.select_next_column()
+ return
+ if table := self._current_table():
+ table.focus_row_selection()
+ table.focus()
+
+ def action_focus_toc(self) -> None:
+ """Move table selection back or focus the table of contents."""
+ if isinstance(self.focused, SearchableDataTable):
+ if self.focused.select_previous_column_or_row():
+ return
+ self.query_one("#toc", ListView).focus()
+
+ def action_clear_search(self) -> None:
+ """Clear table filtering and hide the search input."""
+ search = self.query_one("#table-search", Input)
+ search.value = ""
+ search.display = False
+ self._filter_all_tables("")
+ self.query_one("#toc", ListView).focus()
+
+ async def on_input_changed(self, event: Input.Changed) -> None:
+ """Filter the current page table while typing in the search input."""
+ if event.input.id == "table-search":
+ visible_pages = self._filter_all_tables(event.value)
+ if visible_pages and self._current_page_index() not in visible_pages:
+ self.query_one("#toc", ListView).index = visible_pages[0]
+ await self._show_page(visible_pages[0])
+
+ def on_input_submitted(self, event: Input.Submitted) -> None:
+ """Return focus to navigation after submitting table search."""
+ if event.input.id == "table-search":
+ self.query_one("#toc", ListView).focus()
+
+ async def _show_pending_page(self) -> None:
+ """Show the latest highlighted page after a short navigation debounce."""
+ if self._pending_page_index is not None:
+ await self._show_page(self._pending_page_index)
+ self._pending_page_index = None
+ self._highlight_timer = None
+
+ async def _show_page(self, index: int) -> None:
+ page = self.pages[index]
+ self.sub_title = page.label
+ self.query_one("#content-switcher", ContentSwitcher).current = page.id
+ search = self.query_one("#table-search", Input)
+ if table := self._current_table():
+ table.filter_rows(search.value)
+
+ def _filter_all_tables(self, query: str) -> list[int]:
+ """Filter all mounted tables and return visible page indices."""
+ for table in self.query(SearchableDataTable):
+ table.filter_rows(query)
+
+ visible_pages = []
+ toc = self.query_one("#toc", ListView)
+ for index, item in enumerate(toc.children):
+ page = self.query_one(f"#{self.pages[index].id}", PageView)
+ tables = page.query(SearchableDataTable)
+ is_visible = (
+ not query or index == 0 or any(table.row_count > 0 for table in tables)
+ )
+ item.display = is_visible
+ if is_visible:
+ visible_pages.append(index)
+ return visible_pages
+
+ def _visible_toc_indices(self) -> list[int]:
+ """Return indices for visible table-of-contents items."""
+ toc = self.query_one("#toc", ListView)
+ return [
+ index
+ for index, item in enumerate(toc.children)
+ if item.display is not False
+ ]
+
+ def _current_page_index(self) -> int | None:
+ """Return the index of the currently visible page."""
+ current = self.query_one("#content-switcher", ContentSwitcher).current
+ for index, page in enumerate(self.pages):
+ if page.id == current:
+ return index
+ return None
+
+ def _current_table(self) -> "SearchableDataTable | None":
+ """Return the first table on the currently visible page."""
+ switcher = self.query_one("#content-switcher", ContentSwitcher)
+ if not switcher.current:
+ return None
+ page = self.query_one(f"#{switcher.current}", PageView)
+ tables = page.query(SearchableDataTable)
+ return tables.first() if tables else None
+
+
+def run_textual_viewer(properties: dict[str, Any]) -> None:
+ """Run the interactive Textual viewer for Data Package properties."""
+ FlowerViewApp(prepare_view_pages(properties)).run()
+
+
+class SearchInput(Input):
+ """Search input with common terminal word-delete bindings."""
+
+ BINDINGS = [
+ *Input.BINDINGS,
+ Binding("ctrl+backspace", "delete_left_word", show=False),
+ ]
+
+
+class PageView(VerticalScroll):
+ """A cached Textual page composed from text and native tables."""
+
+ def __init__(
+ self,
+ blocks: list[ViewBlock],
+ *,
+ id: str | None = None,
+ classes: str | None = None,
+ ) -> None:
+ """Initialize the page with prepared content blocks."""
+ super().__init__(id=id, classes=classes)
+ self.blocks = blocks
+
+ def compose(self) -> ComposeResult:
+ """Compose text fragments and DataTables for the page."""
+ for block in self.blocks:
+ if isinstance(block, TextBlock):
+ text = Text(block.content, style=block.style)
+ for start, end, style in block.spans:
+ text.stylize(style, start, end)
+ yield Static(text, classes=block.classes)
+ else:
+ table = SearchableDataTable(block)
+ yield table
+
+
+class SearchableDataTable(DataTable[str]):
+ """DataTable with simple current-page sorting and row filtering."""
+
+ BINDINGS = [
+ *DataTable.BINDINGS,
+ ]
+
+ def __init__(self, block: TableBlock) -> None:
+ """Initialize a table from prepared table data."""
+ super().__init__(
+ show_row_labels=False,
+ show_cursor=False,
+ zebra_stripes=True,
+ cursor_type="row",
+ classes="field-table",
+ )
+ self.headers = block.headers
+ self.all_rows = block.rows
+ self.column_keys: list[ColumnKey] = []
+ self._sort_column_index: int | None = None
+ self._sort_reverse = False
+
+ def on_mount(self) -> None:
+ """Populate the table once it has app context for measuring columns."""
+ for header in self.headers:
+ self.column_keys.append(self.add_column(header, key=header))
+ self.filter_rows("")
+
+ def on_focus(self) -> None:
+ """Show row selection only while the table is active."""
+ self.show_cursor = True
+
+ def on_blur(self) -> None:
+ """Hide row selection when focus returns to navigation or search."""
+ self.show_cursor = False
+ self.focus_row_selection()
+
+ def action_copy_selection(self) -> None:
+ """Copy the selected row or column to the clipboard with a toast."""
+ if not self.row_count:
+ return
+ self.app.copy_to_clipboard(self.selected_text())
+ self.app.notify("Selection copied", markup=False)
+
+ def selected_text(self) -> str:
+ """Return selected row or column as tabular plain text."""
+ if self.cursor_type == "column" and self.headers:
+ column = self.column_keys[self.cursor_column]
+ return "\n".join(str(value) for value in self.get_column(column))
+ return "\t".join(str(value) for value in self.get_row_at(self.cursor_row))
+
+ def filter_rows(self, query: str) -> None:
+ """Show only rows that contain the query text."""
+ normalized_query = query.casefold()
+ rows = [
+ row
+ for row in self.all_rows
+ if not normalized_query
+ or normalized_query in " ".join(str(cell) for cell in row).casefold()
+ ]
+ self.clear()
+ self.add_rows(rows)
+ if self._sort_column_index is not None:
+ self._sort_by_column(self._sort_column_index)
+
+ def sort_next_column(self) -> None:
+ """Sort rows by columns, toggling direction before moving on."""
+ if not self.headers:
+ return
+ if self._sort_column_index is None:
+ self._sort_column_index = 0
+ self._sort_reverse = False
+ elif not self._sort_reverse:
+ self._sort_reverse = True
+ else:
+ self._sort_column_index = (self._sort_column_index + 1) % len(self.headers)
+ self._sort_reverse = False
+ self._sort_by_column(self._sort_column_index)
+
+ def focus_row_selection(self) -> None:
+ """Select rows rather than columns."""
+ self.cursor_type = "row"
+
+ def select_next_column(self) -> None:
+ """Select the next table column."""
+ if not self.headers:
+ return
+ if self.cursor_type != "column":
+ next_column = 0
+ else:
+ next_column = min(self.cursor_column + 1, len(self.headers) - 1)
+ self.cursor_type = "column"
+ self.move_cursor(column=next_column)
+
+ def select_previous_column_or_row(self) -> bool:
+ """Move column selection left, returning True if table focus remains."""
+ if self.cursor_type != "column":
+ return False
+ if self.cursor_column <= 0:
+ self.focus_row_selection()
+ return True
+ self.move_cursor(column=self.cursor_column - 1)
+ return True
+
+ def _sort_by_column(self, column_index: int) -> None:
+ """Sort rows case-insensitively by one column."""
+ self._refresh_sort_indicators()
+ self.sort(
+ self.column_keys[column_index],
+ key=lambda value: str(value).casefold(),
+ reverse=self._sort_reverse,
+ )
+
+ def _refresh_sort_indicators(self) -> None:
+ """Show the active sort column and direction in table headers."""
+ for column_index, header in enumerate(self.headers):
+ label = Text(header)
+ if column_index == self._sort_column_index:
+ label.append(" ")
+ label.append("↓" if self._sort_reverse else "↑", style=RICH_YELLOW)
+ column = self.columns[self.column_keys[column_index]]
+ column.label = label
+ label_width = len(label.plain)
+ column.content_width = max(column.content_width, label_width)
+ if column.auto_width:
+ column.width = max(column.width, label_width)
+ self.refresh_column(column_index)
diff --git a/tests/test_cli.py b/tests/test_cli.py
index dcdc21c0..e6d16605 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -6,14 +6,10 @@
from check_datapackage.check import DataPackageError
from seedcase_soil import Address
-from seedcase_flower.build_sections import (
- BuiltSection,
- _get_template_dir,
- _load_sections_toml,
-)
+from seedcase_flower.build_sections import BuiltSection
from seedcase_flower.cli import app
from seedcase_flower.config import Config
-from seedcase_flower.styles import Style, ViewStyle
+from seedcase_flower.styles import Style
@pytest.fixture
@@ -142,39 +138,20 @@ def test_view_ignores_flower_toml(tmp_path, monkeypatch):
_, bound, _ = app.parse_args(["view"])
assert "source" not in bound.arguments
- assert "style" not in bound.arguments
+ assert "mode" not in bound.arguments
# view ====
-def test_view_styles_are_one_page():
- """Every ViewStyle member must map to a single-section (one-page) style."""
- for member in ViewStyle:
- style = Style[member.name]
- sections = _load_sections_toml(_get_template_dir(style))
- assert not sections.many_sections, (
- f"ViewStyle.{member.name} includes `Many` sections, "
- "but view styles must be single-page (exactly 1 `One` section)."
- )
- assert len(sections.one_sections) == 1, (
- f"ViewStyle.{member.name} has {len(sections.one_sections)} sections, "
- "but view styles must be single-page (exactly 1 `One` section)."
- )
-
-
def test_view_with_mocked_internals(mocker):
- """view should parse source, build sections, and render via Console."""
+ """view should parse source and route properties to the TUI by default."""
mock_parse_source = mocker.patch("seedcase_flower.cli.parse_source")
mock_read_properties = mocker.patch("seedcase_flower.cli.read_properties")
mock_check = mocker.patch("seedcase_flower.cli.check")
mock_build_sections = mocker.patch("seedcase_flower.cli.build_sections")
- mock_console_cls = mocker.patch("seedcase_flower.cli.Console")
- mock_console = mock_console_cls.return_value
-
- mock_build_sections.return_value = [
- BuiltSection(content="# Test", output_path=None)
- ]
+ mock_tui = mocker.patch("seedcase_flower.tui.run_textual_viewer")
+ mocker.patch("seedcase_flower.cli.Console")
fake_source = Address(value="file:///datapackage.json", local=True)
mock_parse_source.return_value = fake_source
@@ -184,6 +161,31 @@ def test_view_with_mocked_internals(mocker):
mock_parse_source.assert_called_once_with("datapackage.json")
mock_read_properties.assert_called_once_with(fake_source)
mock_check.assert_called_once_with(mock_read_properties.return_value, error=True)
+ mock_build_sections.assert_not_called()
+ mock_tui.assert_called_once_with(mock_read_properties.return_value)
+
+
+def test_view_with_stdout_mode(mocker):
+ """view --mode stdout should render the Quarto one-page Markdown style."""
+ mock_parse_source = mocker.patch("seedcase_flower.cli.parse_source")
+ mock_read_properties = mocker.patch("seedcase_flower.cli.read_properties")
+ mocker.patch("seedcase_flower.cli.check")
+ mock_build_sections = mocker.patch("seedcase_flower.cli.build_sections")
+ mock_console_cls = mocker.patch("seedcase_flower.cli.Console")
+ mock_console = mock_console_cls.return_value
+
+ fake_source = Address(value="file:///datapackage.json", local=True)
+ mock_parse_source.return_value = fake_source
+ mock_build_sections.return_value = [
+ BuiltSection(content="# Test Package", output_path=Path("index.qmd"))
+ ]
+
+ app(
+ ["view", "datapackage.json", "--mode", "stdout"],
+ result_action="return_value",
+ )
+
+ mock_read_properties.assert_called_once_with(fake_source)
mock_build_sections.assert_called_once_with(
mock_read_properties.return_value,
Config(style=Style.quarto_one_page),
@@ -191,6 +193,29 @@ def test_view_with_mocked_internals(mocker):
assert mock_console.print.called
+def test_view_with_tui_mode(mocker):
+ """view should route Data Package properties to the TUI viewer."""
+ mock_parse_source = mocker.patch("seedcase_flower.cli.parse_source")
+ mock_read_properties = mocker.patch("seedcase_flower.cli.read_properties")
+ mocker.patch("seedcase_flower.cli.check")
+ mock_build_sections = mocker.patch("seedcase_flower.cli.build_sections")
+ mock_textual_viewer = mocker.patch("seedcase_flower.tui.run_textual_viewer")
+ mock_console_cls = mocker.patch("seedcase_flower.cli.Console")
+
+ fake_source = Address(value="file:///datapackage.json", local=True)
+ mock_parse_source.return_value = fake_source
+
+ app(
+ ["view", "datapackage.json", "--mode", "tui"],
+ result_action="return_value",
+ )
+
+ mock_read_properties.assert_called_once_with(fake_source)
+ mock_build_sections.assert_not_called()
+ mock_textual_viewer.assert_called_once_with(mock_read_properties.return_value)
+ mock_console_cls.assert_not_called()
+
+
def test_build_raises_on_invalid_datapackage(tmp_path):
"""build should check datapackage content and fail for malformed metadata."""
json_file = tmp_path / "datapackage.json"
@@ -213,7 +238,7 @@ def test_view_raises_on_invalid_datapackage(tmp_path):
# instead of the exact full output
def test_view_renders_datapackage(capsys, datapackage_path):
"""view should render all key datapackage fields to the terminal."""
- app(["view", datapackage_path], result_action="return_value")
+ app(["view", datapackage_path, "--mode", "stdout"], result_action="return_value")
output = capsys.readouterr().out
# Package metadata
diff --git a/tests/test_tui.py b/tests/test_tui.py
new file mode 100644
index 00000000..db04e958
--- /dev/null
+++ b/tests/test_tui.py
@@ -0,0 +1,755 @@
+"""Tests for the Textual viewer helpers."""
+
+import asyncio
+import inspect
+from typing import cast
+
+from textual.binding import Binding
+from textual.widgets import ContentSwitcher, Input, ListView
+
+from seedcase_flower.tui import (
+ FlowerViewApp,
+ PageView,
+ SearchableDataTable,
+ SearchInput,
+ TableBlock,
+ TextBlock,
+ ViewPage,
+ prepare_view_pages,
+)
+
+
+def _flower_bindings() -> list[Binding]:
+ return cast(list[Binding], FlowerViewApp.BINDINGS)
+
+
+def _search_bindings() -> list[Binding]:
+ return cast(list[Binding], SearchInput.BINDINGS)
+
+
+def test_flower_view_app_has_vim_navigation_bindings():
+ visible_bindings = [binding for binding in _flower_bindings() if binding.show]
+ assert [binding.key for binding in visible_bindings] == ["q", "?"]
+ assert visible_bindings[0].description == "Quit"
+ assert visible_bindings[1].description == "Keyboard shortcuts"
+ assert FlowerViewApp.COMMAND_PALETTE_DISPLAY == "ctrl+p"
+
+ bindings = {binding.key: binding for binding in _flower_bindings()}
+ assert "escape" not in bindings
+ assert bindings["ctrl+q"].description == "Quit"
+ assert bindings["ctrl+q"].key_display == "ctrl+q |"
+ assert bindings["ctrl+p"].description == "Command Palette"
+ assert bindings["ctrl+p"].key_display == "ctrl+p"
+ assert bindings["j,down"].key_display == "down | j"
+ assert bindings["k,up"].key_display == "up | k"
+ assert bindings["l,right"].key_display == "right | l"
+ assert bindings["l,right"].description == "Select"
+ assert bindings["h,left"].key_display == "left | h"
+ assert bindings["h,left"].description == "Back"
+ assert bindings["y,c"].key_display == "c | y"
+ assert bindings["y,c"].description == "Copy"
+ assert bindings["/,ctrl+f"].key_display == "ctrl+f | /"
+ assert bindings["/,ctrl+f"].description == "Search"
+ assert bindings["ctrl+d"].description == "Jump down"
+ assert bindings["ctrl+u"].description == "Jump up"
+
+
+def test_flower_view_app_uses_ctrl_not_caret_in_key_displays():
+ app = FlowerViewApp([])
+
+ assert app.get_key_display(_flower_bindings()[-2]) == "ctrl+d"
+
+
+def test_flower_view_app_toggles_keyboard_shortcuts_panel():
+ async def run_test() -> None:
+ app = FlowerViewApp([ViewPage(label="Package", id="page-1", blocks=[])])
+
+ async with app.run_test() as pilot:
+ app.action_toggle_help_panel()
+ await pilot.pause()
+
+ assert app.screen.query("HelpPanel")
+
+ app.action_toggle_help_panel()
+ await pilot.pause()
+
+ assert not app.screen.query("HelpPanel")
+
+ asyncio.run(run_test())
+
+
+def test_search_input_supports_ctrl_backspace_word_delete():
+ assert any(binding.key == "ctrl+backspace" for binding in _search_bindings())
+
+
+def test_flower_view_app_pre_mounts_pages():
+ assert "ContentSwitcher" in inspect.getsource(FlowerViewApp.compose)
+ assert "#content-switcher" in FlowerViewApp.CSS
+ assert ".content-page" in FlowerViewApp.CSS
+
+
+def test_flower_view_app_uses_native_datatables_for_tables():
+ assert "DataTable" in inspect.getsource(PageView.compose)
+ assert "SearchableDataTable" in inspect.getsource(PageView.compose)
+ assert "field-table" in FlowerViewApp.CSS
+ assert "table-caption" not in FlowerViewApp.CSS
+ assert "#table-search" in FlowerViewApp.CSS
+ assert "color: ansi_yellow" in FlowerViewApp.CSS
+ assert "border: solid ansi_yellow" in FlowerViewApp.CSS
+
+
+def test_flower_view_app_themes_chrome_and_full_width_toc_rows():
+ assert "Header, Footer" in FlowerViewApp.CSS
+ assert "FooterLabel, FooterKey" in FlowerViewApp.CSS
+ assert "#toc" in FlowerViewApp.CSS
+ assert "#toc:focus" in FlowerViewApp.CSS
+ assert "background: #292E42" in FlowerViewApp.CSS
+ assert "background-tint: ansi_default 0%" in FlowerViewApp.CSS
+ assert "color: ansi_default" in FlowerViewApp.CSS
+ assert "Toast" in FlowerViewApp.CSS
+ assert "Toast:ansi" in FlowerViewApp.CSS
+ assert "ToastRack" in FlowerViewApp.CSS
+ assert "ListItem" in FlowerViewApp.CSS
+ assert "#toc > ListItem.-highlight" in FlowerViewApp.CSS
+ assert "#toc:focus > ListItem.-highlight" in FlowerViewApp.CSS
+ assert "background: ansi_yellow" in FlowerViewApp.CSS
+ assert "color: #1A1B26" in FlowerViewApp.CSS
+ assert "color: $footer-key-foreground" not in FlowerViewApp.CSS
+ assert "width: 100%" in FlowerViewApp.CSS
+ assert ".title" in FlowerViewApp.CSS
+ assert ".compact-list" not in FlowerViewApp.CSS
+ assert ".metadata-list" in FlowerViewApp.CSS
+ assert ".compact-heading" in FlowerViewApp.CSS
+ assert "margin: 0 0 1 0" in FlowerViewApp.CSS
+
+
+def test_prepare_view_pages_builds_package_page_from_properties():
+ pages = prepare_view_pages(
+ {
+ "name": "test-package",
+ "title": "Test Package",
+ "version": "1.0.0",
+ "description": "A test package.",
+ "licenses": [{"name": "MIT"}],
+ "contributors": [{"title": "Ada", "roles": ["author"]}],
+ "resources": [
+ {
+ "name": "species_catalog",
+ "title": "Species Catalog",
+ "description": "Species metadata.",
+ }
+ ],
+ }
+ )
+
+ assert pages[0].label == "Package"
+ assert pages[0].id == "page-1"
+ assert pages[0].blocks == [
+ TextBlock("test-package: Test Package", style="color(4) bold", classes="title"),
+ TextBlock("A test package."),
+ TextBlock(
+ "Version\n• 1.0.0",
+ classes="metadata-list",
+ spans=((0, 7, "color(3) bold"),),
+ ),
+ TextBlock("Licenses", style="color(3) bold", classes="compact-heading"),
+ TextBlock("• MIT", classes="metadata-list"),
+ TextBlock("Contributors", style="color(3) bold", classes="compact-heading"),
+ TextBlock("• Ada: author", classes="metadata-list"),
+ TextBlock("Resources", style="color(3) bold", classes="heading"),
+ TableBlock(
+ headers=["Name", "Title", "Description"],
+ rows=[["species_catalog", "Species Catalog", "Species metadata."]],
+ ),
+ ]
+
+
+def test_prepare_view_pages_builds_resource_page_from_properties():
+ pages = prepare_view_pages(
+ {
+ "name": "test-package",
+ "resources": [
+ {
+ "name": "species_catalog",
+ "title": "Species Catalog",
+ "description": "Species metadata.",
+ "path": "data/species.csv",
+ "schema": {
+ "primaryKey": "id",
+ "fields": [
+ {
+ "name": "id",
+ "title": "Identifier",
+ "type": "integer",
+ "description": "Stable identifier.",
+ },
+ {
+ "name": "species",
+ "title": "Species",
+ "type": "string",
+ "description": "Scientific name.",
+ },
+ ],
+ },
+ }
+ ],
+ }
+ )
+
+ assert pages[1].label == "species_catalog"
+ assert pages[1].id == "page-2"
+ assert pages[1].blocks == [
+ TextBlock("Species Catalog", style="color(4) bold", classes="title"),
+ TextBlock("Species metadata."),
+ TextBlock(
+ "Path\n• data/species.csv",
+ classes="metadata-list",
+ spans=((0, 4, "color(3) bold"),),
+ ),
+ TextBlock(
+ "Primary key\n• id",
+ classes="metadata-list",
+ spans=((0, 11, "color(3) bold"),),
+ ),
+ TextBlock("Fields", style="color(3) bold", classes="heading"),
+ TableBlock(
+ headers=["Name", "Title", "Type", "Description"],
+ rows=[
+ ["id", "Identifier", "integer", "Stable identifier."],
+ ["species", "Species", "string", "Scientific name."],
+ ],
+ ),
+ ]
+
+
+def test_prepare_view_pages_handles_foreign_keys():
+ pages = prepare_view_pages(
+ {
+ "name": "test-package",
+ "resources": [
+ {
+ "name": "plots",
+ "schema": {
+ "foreignKeys": [
+ {
+ "fields": ["species_id"],
+ "reference": {
+ "resource": "species",
+ "fields": ["id"],
+ },
+ }
+ ]
+ },
+ }
+ ],
+ }
+ )
+
+ assert pages[1].blocks[0] == TextBlock(
+ "plots", style="color(4) bold", classes="title"
+ )
+ assert (
+ TextBlock(
+ "Foreign keys\n• species_id → species.id",
+ classes="metadata-list",
+ spans=((0, 12, "color(3) bold"),),
+ )
+ in pages[1].blocks
+ )
+
+
+def test_prepare_view_pages_omits_resource_name_from_main_content():
+ pages = prepare_view_pages(
+ {
+ "name": "test-package",
+ "resources": [
+ {
+ "name": "species_catalog",
+ "title": "species_catalog",
+ "description": "`species_catalog`",
+ "schema": {"fields": []},
+ }
+ ],
+ }
+ )
+
+ assert pages[1].label == "species_catalog"
+ assert pages[1].blocks == [
+ TextBlock("species_catalog", style="color(4) bold", classes="title")
+ ]
+
+
+def test_flower_view_app_switches_between_pre_mounted_pages():
+ async def run_test() -> None:
+ app = FlowerViewApp(
+ [
+ ViewPage(
+ label="Package",
+ id="page-1",
+ blocks=[TextBlock("Package")],
+ ),
+ ViewPage(
+ label="species_catalog",
+ id="page-2",
+ blocks=[TextBlock("Species")],
+ ),
+ ]
+ )
+
+ async with app.run_test():
+ await app._show_page(1)
+
+ assert app.sub_title == "species_catalog"
+ switcher = app.query_one("#content-switcher", ContentSwitcher)
+ assert switcher.current == "page-2"
+
+ asyncio.run(run_test())
+
+
+def test_flower_view_app_debounces_highlight_navigation():
+ async def run_test() -> None:
+ app = FlowerViewApp(
+ [
+ ViewPage(
+ label="Package",
+ id="page-1",
+ blocks=[TextBlock("Package")],
+ ),
+ ViewPage(
+ label="species_catalog",
+ id="page-2",
+ blocks=[TextBlock("Species")],
+ ),
+ ViewPage(
+ label="location_catalog",
+ id="page-3",
+ blocks=[TextBlock("Locations")],
+ ),
+ ]
+ )
+
+ async with app.run_test() as pilot:
+ app.action_toc_down()
+ app.action_toc_down()
+
+ switcher = app.query_one("#content-switcher", ContentSwitcher)
+ assert switcher.current == "page-1"
+
+ await pilot.pause(0.15)
+
+ assert app.sub_title == "location_catalog"
+ assert switcher.current == "page-3"
+
+ asyncio.run(run_test())
+
+
+def test_flower_view_app_does_not_update_page_on_switch():
+ async def run_test() -> None:
+ app = FlowerViewApp(
+ [
+ ViewPage(
+ label="Package",
+ id="page-1",
+ blocks=[TextBlock("Package")],
+ ),
+ ViewPage(
+ label="species_catalog",
+ id="page-2",
+ blocks=[TextBlock("Species")],
+ ),
+ ]
+ )
+
+ async with app.run_test():
+ page = app.query_one("#page-2", PageView)
+ page.remove = None # type: ignore[assignment, method-assign]
+ await app._show_page(1)
+
+ switcher = app.query_one("#content-switcher", ContentSwitcher)
+ assert switcher.current == "page-2"
+
+ asyncio.run(run_test())
+
+
+def test_flower_view_app_filters_current_page_table():
+ async def run_test() -> None:
+ app = FlowerViewApp(
+ [
+ ViewPage(
+ label="Package",
+ id="page-1",
+ blocks=[
+ TableBlock(
+ headers=["Name", "Type"],
+ rows=[
+ ["species", "string"],
+ ["plot_id", "integer"],
+ ],
+ )
+ ],
+ )
+ ]
+ )
+
+ async with app.run_test() as pilot:
+ table = app.query_one(SearchableDataTable)
+
+ app.action_search_table()
+ search = app.query_one("#table-search", Input)
+ assert search.placeholder == "Search all tables"
+ await pilot.press("s", "p")
+
+ assert table.row_count == 1
+ assert table.get_row_at(0) == ["species", "string"]
+
+ app.action_clear_search()
+
+ assert table.row_count == 2
+
+ asyncio.run(run_test())
+
+
+def test_flower_view_app_filters_sidebar_to_matching_resource_tables():
+ async def run_test() -> None:
+ app = FlowerViewApp(
+ [
+ ViewPage(
+ label="Package",
+ id="page-1",
+ blocks=[TextBlock("Package")],
+ ),
+ ViewPage(
+ label="species_catalog",
+ id="page-2",
+ blocks=[
+ TableBlock(
+ headers=["Name"],
+ rows=[["species"]],
+ )
+ ],
+ ),
+ ViewPage(
+ label="location_catalog",
+ id="page-3",
+ blocks=[
+ TableBlock(
+ headers=["Name"],
+ rows=[["location"]],
+ )
+ ],
+ ),
+ ]
+ )
+
+ async with app.run_test() as pilot:
+ app.action_search_table()
+ await pilot.press("s", "p")
+
+ toc = app.query_one("#toc", ListView)
+ toc_items = toc.children
+ assert toc_items[0].display is True
+ assert toc_items[1].display is True
+ assert toc_items[2].display is False
+
+ app.action_toc_down()
+ assert toc.index == 1
+
+ app.action_toc_down()
+ assert toc.index == 1
+
+ app.action_toc_up()
+ assert toc.index == 0
+
+ app.action_clear_search()
+
+ assert all(item.display is True for item in toc_items)
+
+ asyncio.run(run_test())
+
+
+def test_flower_view_app_sorts_current_page_table():
+ async def run_test() -> None:
+ app = FlowerViewApp(
+ [
+ ViewPage(
+ label="Package",
+ id="page-1",
+ blocks=[
+ TableBlock(
+ headers=["Name", "Type"],
+ rows=[
+ ["species", "string"],
+ ["plot_id", "integer"],
+ ],
+ )
+ ],
+ )
+ ]
+ )
+
+ async with app.run_test():
+ table = app.query_one(SearchableDataTable)
+ name_key = table.column_keys[0]
+ type_key = table.column_keys[1]
+ initial_width = table.columns[name_key].width
+
+ app.action_sort_table()
+
+ assert table.get_row_at(0) == ["plot_id", "integer"]
+ assert table.columns[name_key].label.plain == "Name ↑"
+ assert table.columns[name_key].width >= initial_width
+ assert str(table.columns[name_key].label.spans[0].style) == "color(3) bold"
+
+ app.action_sort_table()
+ assert table.get_row_at(0) == ["species", "string"]
+ assert table.columns[name_key].label.plain == "Name ↓"
+
+ app.action_sort_table()
+ assert table.get_row_at(0) == ["plot_id", "integer"]
+ assert table.columns[name_key].label.plain == "Name"
+ assert table.columns[type_key].label.plain == "Type ↑"
+
+ asyncio.run(run_test())
+
+
+def test_flower_view_app_moves_focus_between_toc_and_table():
+ async def run_test() -> None:
+ app = FlowerViewApp(
+ [
+ ViewPage(
+ label="Package",
+ id="page-1",
+ blocks=[
+ TableBlock(
+ headers=["Name"],
+ rows=[["species"]],
+ )
+ ],
+ )
+ ]
+ )
+
+ async with app.run_test() as pilot:
+ table = app.query_one(SearchableDataTable)
+ toc = app.query_one("#toc", ListView)
+
+ assert app.focused == toc
+ assert table.show_cursor is False
+
+ app.action_focus_table()
+ await pilot.pause()
+ assert app.focused == cast(object, table)
+ assert table.show_cursor is True
+ assert table.cursor_type == "row"
+
+ app.action_focus_toc()
+ await pilot.pause()
+ assert app.focused == toc
+ assert table.show_cursor is False
+
+ app.action_focus_table()
+ await pilot.pause()
+ app.action_focus_toc()
+ await pilot.pause()
+ assert app.focused == toc
+
+ asyncio.run(run_test())
+
+
+def test_flower_view_app_cycles_table_column_selection():
+ async def run_test() -> None:
+ app = FlowerViewApp(
+ [
+ ViewPage(
+ label="Package",
+ id="page-1",
+ blocks=[
+ TableBlock(
+ headers=["Name", "Type"],
+ rows=[["species", "string"]],
+ )
+ ],
+ )
+ ]
+ )
+
+ async with app.run_test() as pilot:
+ table = app.query_one(SearchableDataTable)
+ toc = app.query_one("#toc", ListView)
+
+ app.action_focus_table()
+ await pilot.pause()
+
+ assert table.cursor_type == "row"
+
+ app.action_focus_table()
+ assert str(table.cursor_type) == "column"
+ assert table.cursor_column == 0
+
+ app.action_focus_table()
+ assert str(table.cursor_type) == "column"
+ assert table.cursor_column == 1
+
+ app.action_focus_toc()
+ assert str(table.cursor_type) == "column"
+ assert table.cursor_column == 0
+ assert app.focused == cast(object, table)
+
+ app.action_focus_toc()
+ assert table.cursor_type == "row"
+ assert app.focused == cast(object, table)
+
+ app.action_focus_toc()
+ await pilot.pause()
+ assert app.focused == toc
+
+ asyncio.run(run_test())
+
+
+def test_flower_view_app_uses_vim_keys_in_focused_table():
+ async def run_test() -> None:
+ app = FlowerViewApp(
+ [
+ ViewPage(
+ label="Package",
+ id="page-1",
+ blocks=[
+ TableBlock(
+ headers=["Name"],
+ rows=[["species"], ["location"]],
+ )
+ ],
+ )
+ ]
+ )
+
+ async with app.run_test() as pilot:
+ table = app.query_one(SearchableDataTable)
+
+ app.action_focus_table()
+ await pilot.pause()
+ app.action_toc_down()
+
+ assert table.cursor_row == 1
+
+ app.action_toc_up()
+
+ assert table.cursor_row == 0
+
+ asyncio.run(run_test())
+
+
+def test_flower_view_app_jumps_in_focused_table():
+ async def run_test() -> None:
+ app = FlowerViewApp(
+ [
+ ViewPage(
+ label="Package",
+ id="page-1",
+ blocks=[
+ TableBlock(
+ headers=["Name"],
+ rows=[[str(index)] for index in range(10)],
+ )
+ ],
+ )
+ ]
+ )
+
+ async with app.run_test() as pilot:
+ table = app.query_one(SearchableDataTable)
+
+ app.action_focus_table()
+ await pilot.pause()
+ app.action_jump_down()
+
+ assert table.cursor_row == 6
+
+ app.action_jump_up()
+
+ assert table.cursor_row == 0
+
+ asyncio.run(run_test())
+
+
+def test_searchable_data_table_copies_selected_row_or_column():
+ async def run_test() -> None:
+ copied: list[str] = []
+ app = FlowerViewApp(
+ [
+ ViewPage(
+ label="Package",
+ id="page-1",
+ blocks=[
+ TableBlock(
+ headers=["Name", "Type"],
+ rows=[
+ ["species", "string"],
+ ["plot_id", "integer"],
+ ],
+ )
+ ],
+ )
+ ]
+ )
+ app.copy_to_clipboard = copied.append # type: ignore[assignment, method-assign]
+
+ async with app.run_test() as pilot:
+ table = app.query_one(SearchableDataTable)
+
+ app.action_focus_table()
+ await pilot.pause()
+ table.move_cursor(row=1)
+ table.action_copy_selection()
+ await pilot.pause()
+
+ assert copied[-1] == "plot_id\tinteger"
+
+ table.select_next_column()
+ app.action_copy_selection()
+ await pilot.pause()
+
+ assert copied[-1] == "species\nplot_id"
+
+ asyncio.run(run_test())
+
+
+def test_flower_view_app_selecting_toc_item_does_not_focus_table():
+ async def run_test() -> None:
+ app = FlowerViewApp(
+ [
+ ViewPage(
+ label="Package",
+ id="page-1",
+ blocks=[TextBlock("Package")],
+ ),
+ ViewPage(
+ label="species_catalog",
+ id="page-2",
+ blocks=[
+ TableBlock(
+ headers=["Name"],
+ rows=[["species"]],
+ )
+ ],
+ ),
+ ]
+ )
+
+ async with app.run_test() as pilot:
+ table = app.query_one(SearchableDataTable)
+ toc = app.query_one("#toc", ListView)
+
+ toc.index = 1
+ toc.action_select_cursor()
+ await pilot.pause()
+
+ assert app.focused == toc
+ assert table.show_cursor is False
+
+ app.action_focus_table()
+ await pilot.pause()
+
+ assert app.focused == cast(object, table)
+
+ asyncio.run(run_test())
diff --git a/uv.lock b/uv.lock
index 9d885885..a8cddf19 100644
--- a/uv.lock
+++ b/uv.lock
@@ -227,11 +227,11 @@ css = [
[[package]]
name = "certifi"
-version = "2026.2.25"
+version = "2026.4.22"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580", size = 137077, upload-time = "2026-04-22T11:26:11.191Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" },
+ { url = "https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", size = 135707, upload-time = "2026-04-22T11:26:09.372Z" },
]
[[package]]
@@ -375,7 +375,7 @@ wheels = [
[[package]]
name = "check-datapackage"
-version = "0.34.0"
+version = "0.35.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jsonschema" },
@@ -385,21 +385,21 @@ dependencies = [
{ name = "seedcase-soil" },
{ name = "types-jsonschema" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/d5/ac/77af7c0c6ebc5dde15da31891365b6c0ec9427b9a6b1786a53f1024972a3/check_datapackage-0.34.0.tar.gz", hash = "sha256:494f8c5c3df6d2f54ef8a41a497ea19a0acfb5d2d77ca3b16a0d06ce26c09a58", size = 1086921, upload-time = "2026-04-30T08:28:47.958Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/53/20/49504c0d5e51a88e313db9ea31b97982e67a71781369b7121201111f6722/check_datapackage-0.35.0.tar.gz", hash = "sha256:48e4cb97530b13c87f06bac76933a98e9e4591fdde8056b8570bee8b377393bd", size = 1087041, upload-time = "2026-05-04T08:31:05.629Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/19/4d/2ac332e5de86c049a67f9a95ada7cd4ca559a4f38c7e66603f4b6c8cbe16/check_datapackage-0.34.0-py3-none-any.whl", hash = "sha256:f63c19b2cf1d9be03574620c3819f4e4bafb898efa269a140c401a4d89ce70b0", size = 36206, upload-time = "2026-04-30T08:28:46.698Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/d9/7b555152eb7fa88a47d6f900df6b126e54fea7dd0fc34aa46872d0473bf5/check_datapackage-0.35.0-py3-none-any.whl", hash = "sha256:5261b629f574d39671dd31c0053da7ca829fb6692e4f299e8d51c13130714a06", size = 36206, upload-time = "2026-05-04T08:31:04.438Z" },
]
[[package]]
name = "click"
-version = "8.3.2"
+version = "8.3.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/57/75/31212c6bf2503fdf920d87fee5d7a86a2e3bcf444984126f13d8e4016804/click-8.3.2.tar.gz", hash = "sha256:14162b8b3b3550a7d479eafa77dfd3c38d9dc8951f6f69c78913a8f9a7540fd5", size = 302856, upload-time = "2026-04-03T19:14:45.118Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/bb/63/f9e1ea081ce35720d8b92acde70daaedace594dc93b693c869e0d5910718/click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2", size = 328061, upload-time = "2026-04-22T15:11:27.506Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl", hash = "sha256:1924d2c27c5653561cd2cae4548d1406039cb79b858b747cfea24924bbc1616d", size = 108379, upload-time = "2026-04-03T19:14:43.505Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613", size = 110502, upload-time = "2026-04-22T15:11:25.044Z" },
]
[[package]]
@@ -422,7 +422,7 @@ wheels = [
[[package]]
name = "commitizen"
-version = "4.13.10"
+version = "4.15.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "argcomplete" },
@@ -438,9 +438,9 @@ dependencies = [
{ name = "termcolor" },
{ name = "tomlkit" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/37/95/da2c71ed6a1c06836cdd4eb60a8b9e1bf05f4ce7029ab508081745171be9/commitizen-4.13.10.tar.gz", hash = "sha256:402b5bcd466be69ba79a3f380be6ba5b55ac658c7d2a93e82fc99668a6eb2673", size = 64106, upload-time = "2026-04-11T06:49:12.907Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/ac/2a/ac219a23e89210aa3ee9244dc076e39bc532bc3f352024f3d478f3e79b85/commitizen-4.15.1.tar.gz", hash = "sha256:cca192e07b2f9d77734044c631da294b3007ef9aa10cc8f0600290aa662e9fa3", size = 65718, upload-time = "2026-05-06T04:14:45.159Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/11/3a/ad70b3c7dc3da1255668a9396429b1d820c15b74a501668158e4574c1edd/commitizen-4.13.10-py3-none-any.whl", hash = "sha256:95a281317990ac613501fdfe65745cec1fa4042bc5d003a72d332a74926e3039", size = 85746, upload-time = "2026-04-11T06:49:11.167Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/5d/12e74d633a622474cf3af6b27656c7da8b96caf87e1c6672436fcff85138/commitizen-4.15.1-py3-none-any.whl", hash = "sha256:8207ee3e0344b483c5e59103d59ce19b96eb7204ccf28c72b65596fa524b06e2", size = 87876, upload-time = "2026-05-06T04:14:43.754Z" },
]
[[package]]
@@ -529,7 +529,7 @@ wheels = [
[[package]]
name = "cyclopts"
-version = "4.11.0"
+version = "4.11.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs" },
@@ -537,9 +537,9 @@ dependencies = [
{ name = "rich" },
{ name = "rich-rst" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/f9/fa/eff8f1abae783bade9b5e9bafafd0040d4dbf51988f9384bfdc0326ba1fc/cyclopts-4.11.0.tar.gz", hash = "sha256:1ffcb9990dbd56b90da19980d31596de9e99019980a215a5d76cf88fe452e94d", size = 170690, upload-time = "2026-04-23T00:23:36.858Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/e4/f7/3ee212c1bc314551094fc8fda7b4b63c647ac5c32d06daa285d04d33edfc/cyclopts-4.11.2.tar.gz", hash = "sha256:8c9b77921660fa1ee52c150e2217ced672323efb3434e9b338077de1bc551ff4", size = 175935, upload-time = "2026-05-04T00:11:57.857Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/7c/37/197db187c260d24d4be1f09d427f59f3fb9a89bcf1354e23865c7bff7607/cyclopts-4.11.0-py3-none-any.whl", hash = "sha256:34318e3823b44b5baa754a5e37ec70a5c17dc81c65e4295ed70e17bc1aeae50d", size = 208494, upload-time = "2026-04-23T00:23:34.948Z" },
+ { url = "https://files.pythonhosted.org/packages/23/18/4cedda786e7da429e7489549a9e5461530d4133130e541f25fb94f015776/cyclopts-4.11.2-py3-none-any.whl", hash = "sha256:838020120b939549ff7c8423aca29c86764b5dd1d8a5d7f3753a6327861f537b", size = 213537, upload-time = "2026-05-04T00:11:56.103Z" },
]
[[package]]
@@ -649,11 +649,11 @@ wheels = [
[[package]]
name = "filelock"
-version = "3.25.2"
+version = "3.29.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/94/b8/00651a0f559862f3bb7d6f7477b192afe3f583cc5e26403b44e59a55ab34/filelock-3.25.2.tar.gz", hash = "sha256:b64ece2b38f4ca29dd3e810287aa8c48182bbecd1ae6e9ae126c9b35f1382694", size = 40480, upload-time = "2026-03-11T20:45:38.487Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", size = 57571, upload-time = "2026-04-19T15:39:10.068Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl", hash = "sha256:ca8afb0da15f229774c9ad1b455ed96e85a81373065fb10446672f64444ddf70", size = 26759, upload-time = "2026-03-11T20:45:37.437Z" },
+ { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812, upload-time = "2026-04-19T15:39:08.752Z" },
]
[[package]]
@@ -754,20 +754,20 @@ wheels = [
[[package]]
name = "identify"
-version = "2.6.18"
+version = "2.6.19"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/46/c4/7fb4db12296cdb11893d61c92048fe617ee853f8523b9b296ac03b43757e/identify-2.6.18.tar.gz", hash = "sha256:873ac56a5e3fd63e7438a7ecbc4d91aca692eb3fefa4534db2b7913f3fc352fd", size = 99580, upload-time = "2026-03-15T18:39:50.319Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", size = 99567, upload-time = "2026-04-17T18:39:50.265Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/46/33/92ef41c6fad0233e41d3d84ba8e8ad18d1780f1e5d99b3c683e6d7f98b63/identify-2.6.18-py2.py3-none-any.whl", hash = "sha256:8db9d3c8ea9079db92cafb0ebf97abdc09d52e97f4dcf773a2e694048b7cd737", size = 99394, upload-time = "2026-03-15T18:39:48.915Z" },
+ { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", size = 99397, upload-time = "2026-04-17T18:39:49.221Z" },
]
[[package]]
name = "idna"
-version = "3.11"
+version = "3.13"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", size = 194210, upload-time = "2026-04-22T16:42:42.314Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", size = 68629, upload-time = "2026-04-22T16:42:40.909Z" },
]
[[package]]
@@ -826,7 +826,7 @@ wheels = [
[[package]]
name = "ipython"
-version = "9.12.0"
+version = "9.13.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
@@ -836,13 +836,14 @@ dependencies = [
{ name = "matplotlib-inline" },
{ name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
{ name = "prompt-toolkit" },
+ { name = "psutil" },
{ name = "pygments" },
{ name = "stack-data" },
{ name = "traitlets" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/3a/73/7114f80a8f9cabdb13c27732dce24af945b2923dcab80723602f7c8bc2d8/ipython-9.12.0.tar.gz", hash = "sha256:01daa83f504b693ba523b5a407246cabde4eb4513285a3c6acaff11a66735ee4", size = 4428879, upload-time = "2026-03-27T09:42:45.312Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/cd/c4/87cda5842cf5c31837c06ddb588e11c3c35d8ece89b7a0108c06b8c9b00a/ipython-9.13.0.tar.gz", hash = "sha256:7e834b6afc99f020e3f05966ced34792f40267d64cb1ea9043886dab0dde5967", size = 4430549, upload-time = "2026-04-24T12:24:55.221Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/59/22/906c8108974c673ebef6356c506cebb6870d48cedea3c41e949e2dd556bb/ipython-9.12.0-py3-none-any.whl", hash = "sha256:0f2701e8ee86e117e37f50563205d36feaa259d2e08d4a6bc6b6d74b18ce128d", size = 625661, upload-time = "2026-03-27T09:42:42.831Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/86/3060e8029b7cc505cce9a0137431dda81d0a3fde93a8f0f50ee0bf37a795/ipython-9.13.0-py3-none-any.whl", hash = "sha256:57f9d4639e20818d328d287c7b549af3d05f12486ea8f2e7f73e52a36ec4d201", size = 627274, upload-time = "2026-04-24T12:24:53.038Z" },
]
[[package]]
@@ -887,14 +888,14 @@ wheels = [
[[package]]
name = "jedi"
-version = "0.19.2"
+version = "0.20.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "parso" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/46/b7/a3635f6a2d7cf5b5dd98064fc1d5fbbafcb25477bcea204a3a92145d158b/jedi-0.20.0.tar.gz", hash = "sha256:c3f4ccbd276696f4b19c54618d4fb18f9fc24b0aef02acf704b23f487daa1011", size = 3119416, upload-time = "2026-05-01T23:38:47.814Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/93/242e2eab5fe682ffcb8b0084bde703a41d51e17ee0f3a31ff0d9d813620a/jedi-0.20.0-py2.py3-none-any.whl", hash = "sha256:7bdd9c2634f56713299976f4cbd59cb3fa92165cc5e05ea811fb253480728b67", size = 4884812, upload-time = "2026-05-01T23:38:43.919Z" },
]
[[package]]
@@ -1034,7 +1035,7 @@ wheels = [
[[package]]
name = "jupyter-events"
-version = "0.12.0"
+version = "0.12.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jsonschema", extra = ["format-nongpl"] },
@@ -1046,9 +1047,9 @@ dependencies = [
{ name = "rfc3986-validator" },
{ name = "traitlets" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196, upload-time = "2025-02-03T17:23:41.485Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/18/f8/475c4241b2b75af0deaae453ed003c6c851766dbc44d332d8baf245dc931/jupyter_events-0.12.1.tar.gz", hash = "sha256:faff25f77218335752f35f23c5fe6e4a392a7bd99a5939ccb9b8fbf594636cf3", size = 62854, upload-time = "2026-04-20T23:17:50.66Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430, upload-time = "2025-02-03T17:23:38.643Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/6c/6fcde0c8f616ed360ffd3587f7db9e225a7e62b583a04494d2f069cf64ea/jupyter_events-0.12.1-py3-none-any.whl", hash = "sha256:c366585253f537a627da52fa7ca7410c5b5301fe893f511e7b077c2d93ec8bcf", size = 19512, upload-time = "2026-04-20T23:17:48.927Z" },
]
[[package]]
@@ -1065,7 +1066,7 @@ wheels = [
[[package]]
name = "jupyter-server"
-version = "2.17.0"
+version = "2.18.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
@@ -1087,9 +1088,9 @@ dependencies = [
{ name = "traitlets" },
{ name = "websocket-client" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949, upload-time = "2025-08-21T14:42:54.042Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/ca/15/1eacb0fcb79ef86e8a0a79a708e6ad7435f6f223097dd29a4ce861fabc44/jupyter_server-2.18.2.tar.gz", hash = "sha256:06b4f40d8a7a00bb39d5216859c81374a0e7cfefe6d8a5a7facc5a5c37c679a7", size = 753177, upload-time = "2026-05-06T07:04:36.274Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221, upload-time = "2025-08-21T14:42:52.034Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/50/ecf4f70d65bdb7519b28a33d1b2fee8a4b4ba1ae1a92f15d97e877c5de21/jupyter_server-2.18.2-py3-none-any.whl", hash = "sha256:fa5e46539ded65791838035a2b6001f13e54d5f64b8b3752eb1e91fdd641a5b8", size = 391907, upload-time = "2026-05-06T07:04:34.014Z" },
]
[[package]]
@@ -1107,7 +1108,7 @@ wheels = [
[[package]]
name = "jupyterlab"
-version = "4.5.6"
+version = "4.5.7"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "async-lru" },
@@ -1124,9 +1125,9 @@ dependencies = [
{ name = "tornado" },
{ name = "traitlets" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/ac/d5/730628e03fff2e8a8e8ccdaedde1489ab1309f9a4fa2536248884e30b7c7/jupyterlab-4.5.6.tar.gz", hash = "sha256:642fe2cfe7f0f5922a8a558ba7a0d246c7bc133b708dfe43f7b3a826d163cf42", size = 23970670, upload-time = "2026-03-11T14:17:04.531Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/2b/22/8440ec827762146e7cdecf04335bd348795899d29dc6ae82238707353a2c/jupyterlab-4.5.7.tar.gz", hash = "sha256:55a9822c4754da305f41e113452c68383e214dcf96de760146af89ce5d5117b0", size = 23992763, upload-time = "2026-04-29T16:43:51.328Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/e1/1b/dad6fdcc658ed7af26fdf3841e7394072c9549a8b896c381ab49dd11e2d9/jupyterlab-4.5.6-py3-none-any.whl", hash = "sha256:d6b3dac883aa4d9993348e0f8e95b24624f75099aed64eab6a4351a9cdd1e580", size = 12447124, upload-time = "2026-03-11T14:17:00.229Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/aa/537b8f7d80e799af19af35fb3ddfc970b951088a13c57dd9387dcfbb7f61/jupyterlab-4.5.7-py3-none-any.whl", hash = "sha256:fba4cb0e2c44a52859669d8c98b45de029d5e515f8407bf8534d2a8fc5f0964d", size = 12450123, upload-time = "2026-04-29T16:43:46.639Z" },
]
[[package]]
@@ -1176,62 +1177,74 @@ wheels = [
[[package]]
name = "librt"
-version = "0.9.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/eb/6b/3d5c13fb3e3c4f43206c8f9dfed13778c2ed4f000bacaa0b7ce3c402a265/librt-0.9.0.tar.gz", hash = "sha256:a0951822531e7aee6e0dfb556b30d5ee36bbe234faf60c20a16c01be3530869d", size = 184368, upload-time = "2026-04-09T16:06:26.173Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/bf/90/89ddba8e1c20b0922783cd93ed8e64f34dc05ab59c38a9c7e313632e20ff/librt-0.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9b3e3bc363f71bda1639a4ee593cb78f7fbfeacc73411ec0d4c92f00730010a4", size = 68332, upload-time = "2026-04-09T16:05:00.09Z" },
- { url = "https://files.pythonhosted.org/packages/a8/40/7aa4da1fb08bdeeb540cb07bfc8207cb32c5c41642f2594dbd0098a0662d/librt-0.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0a09c2f5869649101738653a9b7ab70cf045a1105ac66cbb8f4055e61df78f2d", size = 70581, upload-time = "2026-04-09T16:05:01.213Z" },
- { url = "https://files.pythonhosted.org/packages/48/ac/73a2187e1031041e93b7e3a25aae37aa6f13b838c550f7e0f06f66766212/librt-0.9.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5ca8e133d799c948db2ab1afc081c333a825b5540475164726dcbf73537e5c2f", size = 203984, upload-time = "2026-04-09T16:05:02.542Z" },
- { url = "https://files.pythonhosted.org/packages/5e/3d/23460d571e9cbddb405b017681df04c142fb1b04cbfce77c54b08e28b108/librt-0.9.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:603138ee838ee1583f1b960b62d5d0007845c5c423feb68e44648b1359014e27", size = 215762, upload-time = "2026-04-09T16:05:04.127Z" },
- { url = "https://files.pythonhosted.org/packages/de/1e/42dc7f8ab63e65b20640d058e63e97fd3e482c1edbda3570d813b4d0b927/librt-0.9.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4003f70c56a5addd6aa0897f200dd59afd3bf7bcd5b3cce46dd21f925743bc2", size = 230288, upload-time = "2026-04-09T16:05:05.883Z" },
- { url = "https://files.pythonhosted.org/packages/dc/08/ca812b6d8259ad9ece703397f8ad5c03af5b5fedfce64279693d3ce4087c/librt-0.9.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:78042f6facfd98ecb25e9829c7e37cce23363d9d7c83bc5f72702c5059eb082b", size = 224103, upload-time = "2026-04-09T16:05:07.148Z" },
- { url = "https://files.pythonhosted.org/packages/b6/3f/620490fb2fa66ffd44e7f900254bc110ebec8dac6c1b7514d64662570e6f/librt-0.9.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a361c9434a64d70a7dbb771d1de302c0cc9f13c0bffe1cf7e642152814b35265", size = 232122, upload-time = "2026-04-09T16:05:08.386Z" },
- { url = "https://files.pythonhosted.org/packages/e9/83/12864700a1b6a8be458cf5d05db209b0d8e94ae281e7ec261dbe616597b4/librt-0.9.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:dd2c7e082b0b92e1baa4da28163a808672485617bc855cc22a2fd06978fa9084", size = 225045, upload-time = "2026-04-09T16:05:09.707Z" },
- { url = "https://files.pythonhosted.org/packages/fd/1b/845d339c29dc7dbc87a2e992a1ba8d28d25d0e0372f9a0a2ecebde298186/librt-0.9.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7e6274fd33fc5b2a14d41c9119629d3ff395849d8bcbc80cf637d9e8d2034da8", size = 227372, upload-time = "2026-04-09T16:05:10.942Z" },
- { url = "https://files.pythonhosted.org/packages/8d/fe/277985610269d926a64c606f761d58d3db67b956dbbf40024921e95e7fcb/librt-0.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5093043afb226ecfa1400120d1ebd4442b4f99977783e4f4f7248879009b227f", size = 248224, upload-time = "2026-04-09T16:05:12.254Z" },
- { url = "https://files.pythonhosted.org/packages/92/1b/ee486d244b8de6b8b5dbaefabe6bfdd4a72e08f6353edf7d16d27114da8d/librt-0.9.0-cp312-cp312-win32.whl", hash = "sha256:9edcc35d1cae9fd5320171b1a838c7da8a5c968af31e82ecc3dff30b4be0957f", size = 55986, upload-time = "2026-04-09T16:05:13.529Z" },
- { url = "https://files.pythonhosted.org/packages/89/7a/ba1737012308c17dc6d5516143b5dce9a2c7ba3474afd54e11f44a4d1ef3/librt-0.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:3cc2917258e131ae5f958a4d872e07555b51cb7466a43433218061c74ef33745", size = 63260, upload-time = "2026-04-09T16:05:14.68Z" },
- { url = "https://files.pythonhosted.org/packages/36/e4/01752c113da15127f18f7bf11142f5640038f062407a611c059d0036c6aa/librt-0.9.0-cp312-cp312-win_arm64.whl", hash = "sha256:90e6d5420fc8a300518d4d2288154ff45005e920425c22cbbfe8330f3f754bd9", size = 53694, upload-time = "2026-04-09T16:05:16.095Z" },
- { url = "https://files.pythonhosted.org/packages/5f/d7/1b3e26fffde1452d82f5666164858a81c26ebe808e7ae8c9c88628981540/librt-0.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f29b68cd9714531672db62cc54f6e8ff981900f824d13fa0e00749189e13778e", size = 68367, upload-time = "2026-04-09T16:05:17.243Z" },
- { url = "https://files.pythonhosted.org/packages/a5/5b/c61b043ad2e091fbe1f2d35d14795e545d0b56b03edaa390fa1dcee3d160/librt-0.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d5c8a5929ac325729f6119802070b561f4db793dffc45e9ac750992a4ed4d22", size = 70595, upload-time = "2026-04-09T16:05:18.471Z" },
- { url = "https://files.pythonhosted.org/packages/a3/22/2448471196d8a73370aa2f23445455dc42712c21404081fcd7a03b9e0749/librt-0.9.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:756775d25ec8345b837ab52effee3ad2f3b2dfd6bbee3e3f029c517bd5d8f05a", size = 204354, upload-time = "2026-04-09T16:05:19.593Z" },
- { url = "https://files.pythonhosted.org/packages/ac/5e/39fc4b153c78cfd2c8a2dcb32700f2d41d2312aa1050513183be4540930d/librt-0.9.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b8f5d00b49818f4e2b1667db994488b045835e0ac16fe2f924f3871bd2b8ac5", size = 216238, upload-time = "2026-04-09T16:05:20.868Z" },
- { url = "https://files.pythonhosted.org/packages/d7/42/bc2d02d0fa7badfa63aa8d6dcd8793a9f7ef5a94396801684a51ed8d8287/librt-0.9.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c81aef782380f0f13ead670aae01825eb653b44b046aa0e5ebbb79f76ed4aa11", size = 230589, upload-time = "2026-04-09T16:05:22.305Z" },
- { url = "https://files.pythonhosted.org/packages/c8/7b/e2d95cc513866373692aa5edf98080d5602dd07cabfb9e5d2f70df2f25f7/librt-0.9.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66b58fed90a545328e80d575467244de3741e088c1af928f0b489ebec3ef3858", size = 224610, upload-time = "2026-04-09T16:05:23.647Z" },
- { url = "https://files.pythonhosted.org/packages/31/d5/6cec4607e998eaba57564d06a1295c21b0a0c8de76e4e74d699e627bd98c/librt-0.9.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e78fb7419e07d98c2af4b8567b72b3eaf8cb05caad642e9963465569c8b2d87e", size = 232558, upload-time = "2026-04-09T16:05:25.025Z" },
- { url = "https://files.pythonhosted.org/packages/95/8c/27f1d8d3aaf079d3eb26439bf0b32f1482340c3552e324f7db9dca858671/librt-0.9.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c3786f0f4490a5cd87f1ed6cefae833ad6b1060d52044ce0434a2e85893afd0", size = 225521, upload-time = "2026-04-09T16:05:26.311Z" },
- { url = "https://files.pythonhosted.org/packages/6b/d8/1e0d43b1c329b416017619469b3c3801a25a6a4ef4a1c68332aeaa6f72ca/librt-0.9.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:8494cfc61e03542f2d381e71804990b3931175a29b9278fdb4a5459948778dc2", size = 227789, upload-time = "2026-04-09T16:05:27.624Z" },
- { url = "https://files.pythonhosted.org/packages/2c/b4/d3d842e88610fcd4c8eec7067b0c23ef2d7d3bff31496eded6a83b0f99be/librt-0.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:07cf11f769831186eeac424376e6189f20ace4f7263e2134bdb9757340d84d4d", size = 248616, upload-time = "2026-04-09T16:05:29.181Z" },
- { url = "https://files.pythonhosted.org/packages/ec/28/527df8ad0d1eb6c8bdfa82fc190f1f7c4cca5a1b6d7b36aeabf95b52d74d/librt-0.9.0-cp313-cp313-win32.whl", hash = "sha256:850d6d03177e52700af605fd60db7f37dcb89782049a149674d1a9649c2138fd", size = 56039, upload-time = "2026-04-09T16:05:30.709Z" },
- { url = "https://files.pythonhosted.org/packages/f3/a7/413652ad0d92273ee5e30c000fc494b361171177c83e57c060ecd3c21538/librt-0.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:a5af136bfba820d592f86c67affcef9b3ff4d4360ac3255e341e964489b48519", size = 63264, upload-time = "2026-04-09T16:05:31.881Z" },
- { url = "https://files.pythonhosted.org/packages/a4/0a/92c244309b774e290ddb15e93363846ae7aa753d9586b8aad511c5e6145b/librt-0.9.0-cp313-cp313-win_arm64.whl", hash = "sha256:4c4d0440a3a8e31d962340c3e1cc3fc9ee7febd34c8d8f770d06adb947779ea5", size = 53728, upload-time = "2026-04-09T16:05:33.31Z" },
- { url = "https://files.pythonhosted.org/packages/cd/c1/184e539543f06ea2912f4b92a5ffaede4f9b392689e3f00acbf8134bee92/librt-0.9.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:3f05d145df35dca5056a8bc3838e940efebd893a54b3e19b2dda39ceaa299bcb", size = 67830, upload-time = "2026-04-09T16:05:34.517Z" },
- { url = "https://files.pythonhosted.org/packages/f3/ad/23399bdcb7afca819acacdef31b37ee59de261bd66b503a7995c03c4b0dc/librt-0.9.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1c587494461ebd42229d0f1739f3aa34237dd9980623ecf1be8d3bcba79f4499", size = 70280, upload-time = "2026-04-09T16:05:35.649Z" },
- { url = "https://files.pythonhosted.org/packages/9f/0b/4542dc5a2b8772dbf92cafb9194701230157e73c14b017b6961a23598b03/librt-0.9.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b0a2040f801406b93657a70b72fa12311063a319fee72ce98e1524da7200171f", size = 201925, upload-time = "2026-04-09T16:05:36.739Z" },
- { url = "https://files.pythonhosted.org/packages/31/d4/8ee7358b08fd0cfce051ef96695380f09b3c2c11b77c9bfbc367c921cce5/librt-0.9.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f38bc489037eca88d6ebefc9c4d41a4e07c8e8b4de5188a9e6d290273ad7ebb1", size = 212381, upload-time = "2026-04-09T16:05:38.043Z" },
- { url = "https://files.pythonhosted.org/packages/f2/94/a2025fe442abedf8b038038dab3dba942009ad42b38ea064a1a9e6094241/librt-0.9.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3fd278f5e6bf7c75ccd6d12344eb686cc020712683363b66f46ac79d37c799f", size = 227065, upload-time = "2026-04-09T16:05:39.394Z" },
- { url = "https://files.pythonhosted.org/packages/7c/e9/b9fcf6afa909f957cfbbf918802f9dada1bd5d3c1da43d722fd6a310dc3f/librt-0.9.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fcbdf2a9ca24e87bbebb47f1fe34e531ef06f104f98c9ccfc953a3f3344c567a", size = 221333, upload-time = "2026-04-09T16:05:40.999Z" },
- { url = "https://files.pythonhosted.org/packages/ac/7c/ba54cd6aa6a3c8cd12757a6870e0c79a64b1e6327f5248dcff98423f4d43/librt-0.9.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e306d956cfa027fe041585f02a1602c32bfa6bb8ebea4899d373383295a6c62f", size = 229051, upload-time = "2026-04-09T16:05:42.605Z" },
- { url = "https://files.pythonhosted.org/packages/4b/4b/8cfdbad314c8677a0148bf0b70591d6d18587f9884d930276098a235461b/librt-0.9.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:465814ab157986acb9dfa5ccd7df944be5eefc0d08d31ec6e8d88bc71251d845", size = 222492, upload-time = "2026-04-09T16:05:43.842Z" },
- { url = "https://files.pythonhosted.org/packages/1f/d1/2eda69563a1a88706808decdce035e4b32755dbfbb0d05e1a65db9547ed1/librt-0.9.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:703f4ae36d6240bfe24f542bac784c7e4194ec49c3ba5a994d02891649e2d85b", size = 223849, upload-time = "2026-04-09T16:05:45.054Z" },
- { url = "https://files.pythonhosted.org/packages/04/44/b2ed37df6be5b3d42cfe36318e0598e80843d5c6308dd63d0bf4e0ce5028/librt-0.9.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3be322a15ee5e70b93b7a59cfd074614f22cc8c9ff18bd27f474e79137ea8d3b", size = 245001, upload-time = "2026-04-09T16:05:46.34Z" },
- { url = "https://files.pythonhosted.org/packages/47/e7/617e412426df89169dd2a9ed0cc8752d5763336252c65dbf945199915119/librt-0.9.0-cp314-cp314-win32.whl", hash = "sha256:b8da9f8035bb417770b1e1610526d87ad4fc58a2804dc4d79c53f6d2cf5a6eb9", size = 51799, upload-time = "2026-04-09T16:05:47.738Z" },
- { url = "https://files.pythonhosted.org/packages/24/ed/c22ca4db0ca3cbc285e4d9206108746beda561a9792289c3c31281d7e9df/librt-0.9.0-cp314-cp314-win_amd64.whl", hash = "sha256:b8bd70d5d816566a580d193326912f4a76ec2d28a97dc4cd4cc831c0af8e330e", size = 59165, upload-time = "2026-04-09T16:05:49.198Z" },
- { url = "https://files.pythonhosted.org/packages/24/56/875398fafa4cbc8f15b89366fc3287304ddd3314d861f182a4b87595ace0/librt-0.9.0-cp314-cp314-win_arm64.whl", hash = "sha256:fc5758e2b7a56532dc33e3c544d78cbaa9ecf0a0f2a2da2df882c1d6b99a317f", size = 49292, upload-time = "2026-04-09T16:05:50.362Z" },
- { url = "https://files.pythonhosted.org/packages/4c/61/bc448ecbf9b2d69c5cff88fe41496b19ab2a1cbda0065e47d4d0d51c0867/librt-0.9.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:f24b90b0e0c8cc9491fb1693ae91fe17cb7963153a1946395acdbdd5818429a4", size = 70175, upload-time = "2026-04-09T16:05:51.564Z" },
- { url = "https://files.pythonhosted.org/packages/60/f2/c47bb71069a73e2f04e70acbd196c1e5cc411578ac99039a224b98920fd4/librt-0.9.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3fe56e80badb66fdcde06bef81bbaa5bfcf6fbd7aefb86222d9e369c38c6b228", size = 72951, upload-time = "2026-04-09T16:05:52.699Z" },
- { url = "https://files.pythonhosted.org/packages/29/19/0549df59060631732df758e8886d92088da5fdbedb35b80e4643664e8412/librt-0.9.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:527b5b820b47a09e09829051452bb0d1dd2122261254e2a6f674d12f1d793d54", size = 225864, upload-time = "2026-04-09T16:05:53.895Z" },
- { url = "https://files.pythonhosted.org/packages/9d/f8/3b144396d302ac08e50f89e64452c38db84bc7b23f6c60479c5d3abd303c/librt-0.9.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d429bdd4ac0ab17c8e4a8af0ed2a7440b16eba474909ab357131018fe8c7e71", size = 241155, upload-time = "2026-04-09T16:05:55.191Z" },
- { url = "https://files.pythonhosted.org/packages/7a/ce/ee67ec14581de4043e61d05786d2aed6c9b5338816b7859bcf07455c6a9f/librt-0.9.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7202bdcac47d3a708271c4304a474a8605a4a9a4a709e954bf2d3241140aa938", size = 252235, upload-time = "2026-04-09T16:05:56.549Z" },
- { url = "https://files.pythonhosted.org/packages/8a/fa/0ead15daa2b293a54101550b08d4bafe387b7d4a9fc6d2b985602bae69b6/librt-0.9.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0d620e74897f8c2613b3c4e2e9c1e422eb46d2ddd07df540784d44117836af3", size = 244963, upload-time = "2026-04-09T16:05:57.858Z" },
- { url = "https://files.pythonhosted.org/packages/29/68/9fbf9a9aa704ba87689e40017e720aced8d9a4d2b46b82451d8142f91ec9/librt-0.9.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d69fc39e627908f4c03297d5a88d9284b73f4d90b424461e32e8c2485e21c283", size = 257364, upload-time = "2026-04-09T16:05:59.686Z" },
- { url = "https://files.pythonhosted.org/packages/1a/8d/9d60869f1b6716c762e45f66ed945b1e5dd649f7377684c3b176ae424648/librt-0.9.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:c2640e23d2b7c98796f123ffd95cf2022c7777aa8a4a3b98b36c570d37e85eee", size = 247661, upload-time = "2026-04-09T16:06:00.938Z" },
- { url = "https://files.pythonhosted.org/packages/70/ff/a5c365093962310bfdb4f6af256f191085078ffb529b3f0cbebb5b33ebe2/librt-0.9.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:451daa98463b7695b0a30aa56bf637831ea559e7b8101ac2ef6382e8eb15e29c", size = 248238, upload-time = "2026-04-09T16:06:02.537Z" },
- { url = "https://files.pythonhosted.org/packages/a0/3c/2d34365177f412c9e19c0a29f969d70f5343f27634b76b765a54d8b27705/librt-0.9.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:928bd06eca2c2bbf4349e5b817f837509b0604342e65a502de1d50a7570afd15", size = 269457, upload-time = "2026-04-09T16:06:03.833Z" },
- { url = "https://files.pythonhosted.org/packages/bc/cd/de45b239ea3bdf626f982a00c14bfcf2e12d261c510ba7db62c5969a27cd/librt-0.9.0-cp314-cp314t-win32.whl", hash = "sha256:a9c63e04d003bc0fb6a03b348018b9a3002f98268200e22cc80f146beac5dc40", size = 52453, upload-time = "2026-04-09T16:06:05.229Z" },
- { url = "https://files.pythonhosted.org/packages/7f/f9/bfb32ae428aa75c0c533915622176f0a17d6da7b72b5a3c6363685914f70/librt-0.9.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f162af66a2ed3f7d1d161a82ca584efd15acd9c1cff190a373458c32f7d42118", size = 60044, upload-time = "2026-04-09T16:06:06.398Z" },
- { url = "https://files.pythonhosted.org/packages/aa/47/7d70414bcdbb3bc1f458a8d10558f00bbfdb24e5a11740fc8197e12c3255/librt-0.9.0-cp314-cp314t-win_arm64.whl", hash = "sha256:a4b25c6c25cac5d0d9d6d6da855195b254e0021e513e0249f0e3b444dc6e0e61", size = 50009, upload-time = "2026-04-09T16:06:07.995Z" },
+version = "0.10.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/39/cb/c1945e506893b5b8577fb45a60c80e3ffe4a82092a04a6f29b0b951d9a24/librt-0.10.0.tar.gz", hash = "sha256:1aba1e8aa4e3307a7be68a74149545fde7451964dc0235a8bec5704a17bdda42", size = 191799, upload-time = "2026-05-05T16:31:23.535Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/12/8e/cbb5b6f6e45e65c10a42449a69eaccc44d73e6a081ea752fbc5221c6dc1c/librt-0.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b4b58a44b407e91f633dafee008de9ddea6aa2a555ed94929c099260910bd0ba", size = 77327, upload-time = "2026-05-05T16:29:38.919Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/3d/8233cbee8e99e6a8992f02bfc2dec8d787509566a511d1fde2574ee7473f/librt-0.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:950b79b11762531bdf45a9df909d2f9a2a8445c70c88665c01d14c8511a27dc5", size = 79971, upload-time = "2026-05-05T16:29:40.96Z" },
+ { url = "https://files.pythonhosted.org/packages/87/6f/5264b298cef2b72fc97d2dde56c66181eda35204bf5dcd1ed0c3d0a0a782/librt-0.10.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4538453f51be197633b425912c150e25b0667252d3741c53e8368176d98d9d37", size = 246559, upload-time = "2026-05-05T16:29:42.701Z" },
+ { url = "https://files.pythonhosted.org/packages/07/7b/19b1b859cc60d5f99276cc2b3144d91556c6d1b1e4ebb50359696bebf7a8/librt-0.10.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:70b955f091beac93e994a0b7ec616934f63b3ea5c3d6d7af847562f935aceca7", size = 235216, upload-time = "2026-05-05T16:29:44.193Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/56/a2f40717142a8af46289f57874ef914353d8faccd5e4f8e594ab1e16e8c7/librt-0.10.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:483e685e06b6163728ba6c85d74315176be7190f432ec2a41226e5e14355d5f0", size = 263108, upload-time = "2026-05-05T16:29:46.365Z" },
+ { url = "https://files.pythonhosted.org/packages/67/ca/15c625c3bdc0167c01e04ef8878317e9713f3bfa788438342f7a94c7b22c/librt-0.10.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7ac53d946a009d1a38c44a60812708c9458fb2a239a5f630d8e625571386650f", size = 255280, upload-time = "2026-05-05T16:29:48.087Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/c5/ba301d571d9e05844e2435b73aba30bee77bb75ce155c9affcfd2173dd03/librt-0.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bc8771c9fcf0ea894ca41fdc2abd83572c2fbda221f232d86e718614e57ff513", size = 268829, upload-time = "2026-05-05T16:29:49.628Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/60/af70e135bc1f1fe15dd3894b1e4bbefc7ecdf911749a925a39eb86ceb2a1/librt-0.10.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:70805dbc5257892ac572f86290a61e3c8d90224ecce1a8b2d1f7ed51965417f4", size = 262051, upload-time = "2026-05-05T16:29:51.244Z" },
+ { url = "https://files.pythonhosted.org/packages/83/c2/c8236eb8b421bac5a172ba208f965abaa89805da2a3fa112bdf1764caf8f/librt-0.10.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d3b4f300f7bcba6e2ff73fb8bef1898479e9772bfa2682998c636391633ec826", size = 264347, upload-time = "2026-05-05T16:29:53.013Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/f5/15b6d32bc25dacd4a60886a683d8128d6219910c122202b995a40dd4f8d2/librt-0.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:943bc943f92f4fb3408fae62485c6a3ad68ce4f2ee205643a39641525c19a276", size = 286482, upload-time = "2026-05-05T16:29:54.675Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/8e/b1b959bacd323eb4360579db992513e1406d1c6ef7edb57b5511fd0666fd/librt-0.10.0-cp312-cp312-win32.whl", hash = "sha256:6065c1a758fba1010b41401013903d3d5d2750eab425ddedd584abac31d0630e", size = 62955, upload-time = "2026-05-05T16:29:56.39Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/4c/d4cd6e4b9fc24098e63cc85537d1b6689682aee96809c38f08072067cc2b/librt-0.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:d788ecbe208ab352dab0e105cc06057bf9a2fc7e58cabb0d751ad9e30062b9e2", size = 71191, upload-time = "2026-05-05T16:29:57.682Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/19/8641da1f63d24b92354a492f893c022d6b3a0df44e70c8eff49364613983/librt-0.10.0-cp312-cp312-win_arm64.whl", hash = "sha256:6003d1f295bdba02656dc81308208fc060d0a51d8c0d0a6db70f7f3c57b9ba0a", size = 61432, upload-time = "2026-05-05T16:29:58.971Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/29/681a75c82f4cc90d29e4b257a3299b79fe13fe927a04c57b8109d70b6957/librt-0.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f0ede79d682e73f91c1b599a76d78b7464b9b5d213754cedb13372d9df36e596", size = 77299, upload-time = "2026-05-05T16:30:00.209Z" },
+ { url = "https://files.pythonhosted.org/packages/62/24/0c7ca445a55d04be79cac19819437fd094782347fa116f6681844fa6143e/librt-0.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e0ba0b131fdb336c8b9c948e397f4a7e649d0f783b529f07b647bf4961df392e", size = 79930, upload-time = "2026-05-05T16:30:01.555Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/1f/1e2b8f6443ef9e9a81e89486ca70e22f3684f93db003ce6eaefc3d0839b9/librt-0.10.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2728117da2afb96fb957768725ee43dc9a2d73b031e02da424b818a3cdd3a275", size = 246195, upload-time = "2026-05-05T16:30:03.261Z" },
+ { url = "https://files.pythonhosted.org/packages/74/61/9dc9e03de0439ad84c1c240aac8b747f12c90cb797ea6042f7bdb8d3410f/librt-0.10.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:723ba80594c49cdf0584196fc430752262605dc9449902fc9bd3d9b79976cb77", size = 234951, upload-time = "2026-05-05T16:30:04.881Z" },
+ { url = "https://files.pythonhosted.org/packages/55/f4/635223117d7590875bca441275065a3bf491203ad4208bd1cc3ffd90c5a1/librt-0.10.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7292edaaca294a61a978c53a3c7d6130d099b0dfbc8f0a65916cdc6b891b9852", size = 262768, upload-time = "2026-05-05T16:30:06.638Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/66/b04152d0cd8b6ca2b428a8bd3230343230c35ed304a932f35b5375f2f828/librt-0.10.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:89fe9d539f2c10a1666633eeeac507ce95dd06d9ecc58de3c6390dba156a3d3a", size = 255075, upload-time = "2026-05-05T16:30:08.216Z" },
+ { url = "https://files.pythonhosted.org/packages/35/1e/25bac4c7f2ca36f0e612cade186970683cf79153d96beccc3a11a9e19b97/librt-0.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4efa7b9587503fa5b67f40593302b9c8836d211d222ff9f7cafe67be5f8f0b10", size = 268559, upload-time = "2026-05-05T16:30:10.1Z" },
+ { url = "https://files.pythonhosted.org/packages/18/54/4601faab35b6632a13200faa146ca62bfd111ffbe2568be430d65c89493a/librt-0.10.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:22dc982ef59df0136df36092ccbdbb570ced8aafb33e49585739b2f1de1c13b6", size = 261753, upload-time = "2026-05-05T16:30:11.912Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/cf/39f4023509e94fade8b074666fa3292db9cb6b34ea5dcbe7af53df9fca1d/librt-0.10.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:6f2e5f3606253a84cea719c94a3bb1c54487b5d617d0254d46e0920d8a06be3f", size = 264055, upload-time = "2026-05-05T16:30:13.465Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/00/40247209fc46a8e308a91412d5206aedf8efb667ee89eb625820106a5c2f/librt-0.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:40884bfaa1e29f6b6a9be255007d8f359bfc9e61d68bdef8ed3158bfcbc95df9", size = 286190, upload-time = "2026-05-05T16:30:15.073Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/6e/5566beb94431a985abe1787af5ef86e087750172ff9d0bbf20f93e88132d/librt-0.10.0-cp313-cp313-win32.whl", hash = "sha256:3cd34cd8254eba756660bff6c2da91278248184301054fe3e4feb073bdd49b14", size = 62949, upload-time = "2026-05-05T16:30:16.503Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/c2/3ea3301d6c8dff51d39dbe8ed75db3dc92896947d4afb5eeadf821c1e67f/librt-0.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:7baac5313e2d8dce1386f97777a8d03ab28f5fe1e780b3b9ac2ee7544551fedc", size = 71152, upload-time = "2026-05-05T16:30:17.766Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/de/5d49cb92cadcbc77d3abc27b93fd6030ed8437487dde2eae38cab5e6704d/librt-0.10.0-cp313-cp313-win_arm64.whl", hash = "sha256:afc5b4406c8e2515698d922a5c7823a009312835ea58196671fff40e35cb8166", size = 61336, upload-time = "2026-05-05T16:30:19.021Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/64/7165e08108cc185a13a9c069f0685e6ef92e70e07fddf7edf5e7348c6316/librt-0.10.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:f09588a30e6a22ec624090d72a3ab1a6d4d5485c3ed739603e76aa3c16efa688", size = 76794, upload-time = "2026-05-05T16:30:20.392Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/ef/bf8613febf651b90c5222ee79dea5ae58d4cc2b544df69d3033424448934/librt-0.10.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:131ade118d12bd7a0adc4e655474a553f1b76cf78385868885944d21d51e45e0", size = 79662, upload-time = "2026-05-05T16:30:22.025Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/67/9eddd165c1d8397bdf99b38bf12b5a55b3def5035b49eedb49f2775d1430/librt-0.10.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8b9ab28e40d011c373a189eae900c916e66d6fbecf7983e9e4883089ee085ef", size = 242390, upload-time = "2026-05-05T16:30:23.51Z" },
+ { url = "https://files.pythonhosted.org/packages/10/d1/d95da80334501866cd37004ab5d7483220d05862fab4b5405394f0264f0d/librt-0.10.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:67c39bb30da73bae1f293d1ed8bc2f8f6642649dd0928d3600aeff3041ac23d6", size = 232603, upload-time = "2026-05-05T16:30:25.198Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/fa/e6d64d28718bc1be4e1736fcb037ca1c4dfca927e7167df75a7d5215665e/librt-0.10.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8c3273c6b774614f093c8927c2bf1b077d0fefde988fe98f46a333734e5597ab", size = 259187, upload-time = "2026-05-05T16:30:26.772Z" },
+ { url = "https://files.pythonhosted.org/packages/72/3f/3fdb77e7f937dad59cfd76b720be7e7643400ec76b2da35befab8d66ba30/librt-0.10.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9dd7c1b86a4baa583ab5db977484b93a2c474e69e96ef3e9538387ea54229cb9", size = 251846, upload-time = "2026-05-05T16:30:28.56Z" },
+ { url = "https://files.pythonhosted.org/packages/18/ca/f4d49133dd86a6f55d79eca30bf412fa722f511a9abe67f62f57aa64e66a/librt-0.10.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a77385c5a202e831149f7ad03be9e67cf80e957e52c614e83dcb822c95222eb8", size = 264936, upload-time = "2026-05-05T16:30:30.491Z" },
+ { url = "https://files.pythonhosted.org/packages/de/66/a8df2fbadc1f6c1827a096d11c40175bd526133480bd3bc88ec64a03d257/librt-0.10.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c6a5eafa74b5655bad59886138ed68426f098a6beb8cb95a71f2cc3cd8bb33fe", size = 258699, upload-time = "2026-05-05T16:30:32.002Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/73/1e3c83613fe05451bb969e27b68a573d177f08d5f63533cc29fec0989658/librt-0.10.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:1fc93d0439204c50ab4d1512611ce2c206f1b369b419f69c7c27c761561e3291", size = 259825, upload-time = "2026-05-05T16:30:35.077Z" },
+ { url = "https://files.pythonhosted.org/packages/09/24/5e2f926ee9d3ef348d9339526d7062abb5c44d8419e3179528c01d78c102/librt-0.10.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:79e713c178bc7a744adfbee6b4619a288eecc0c914da2a9313a20255abe2f0cf", size = 282548, upload-time = "2026-05-05T16:30:36.639Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/7d/3e89ed6ad0162561fa8bef9df3195e24263104c955713cd0237d3711fad2/librt-0.10.0-cp314-cp314-win32.whl", hash = "sha256:2eba9d955a68c41d9f326be3da42f163ec3518b7ab20f1c826224e7bed71e0bf", size = 58970, upload-time = "2026-05-05T16:30:38.183Z" },
+ { url = "https://files.pythonhosted.org/packages/76/25/579e731c94a7086a268bfa3e7a4945cd47836bebd3cbf3faeafd2e7eaef9/librt-0.10.0-cp314-cp314-win_amd64.whl", hash = "sha256:cbfaf7f5145e9917f5d18bffa298eff6a19d74e7b8b11dabdca95785befe8dbf", size = 67260, upload-time = "2026-05-05T16:30:39.804Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/f8/235822b7ae0b2334f12ee18bcf2476d07924077a5efeea57dbe927704be2/librt-0.10.0-cp314-cp314-win_arm64.whl", hash = "sha256:8d6d385d1969849a6b1397114df22714b6ded917bada98668e3e974dc663477e", size = 57156, upload-time = "2026-05-05T16:30:41.412Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/e3/9b919cbf1e8eb770bf91bb7df28125e0f1daf4587169afefd95402636e9a/librt-0.10.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:6c3a82d3bd32631ef5c79922dfc028520c9ad840255979ab4d908271818039ee", size = 79150, upload-time = "2026-05-05T16:30:42.761Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/f5/72a944aa3bc3498169a168087eff58ca48b58bf1b704e59d091fd30739f3/librt-0.10.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d64cc66005dc324c9bb1fa3fc2841f529002f6eb15966d55e46d430f56955a6a", size = 82304, upload-time = "2026-05-05T16:30:44.082Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/e3/fcc290a33e295019759472dfa794d204e43504b276ac65eab7fd9da20ea3/librt-0.10.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bb562cd28c88cd2c6a9a6c78f99dc39348d6b16c94adc25de0e574acf1176e9", size = 272556, upload-time = "2026-05-05T16:30:45.497Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/54/546975e4c997573885e7f040a05012f8838e06fb12b0c3c1fbb76254e9d7/librt-0.10.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:b809aa2854d019c28773b03605df22adc675ee4f3f4402d673581313e8906119", size = 256941, upload-time = "2026-05-05T16:30:47.059Z" },
+ { url = "https://files.pythonhosted.org/packages/70/8c/f1d03401571b331653acddbd4e8cd955c06d945241dd08b25192fac0d04b/librt-0.10.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cc15acabdd519bd4176fdadc2119e5e3093485d86f89138daf47e5b4cedb983a", size = 285855, upload-time = "2026-05-05T16:30:48.86Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/08/62cf80ff046c339faf56718b3a940244d4beb70f1c6407289b5830ec11e9/librt-0.10.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b1b2d835307d08ddadd94568e2369648ec9173bd3eea6d7f52a1abe717c81f98", size = 275321, upload-time = "2026-05-05T16:30:50.63Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/ea/da5918d4070362e9a4d2ee9cd34f9dc84902daad8fd4275f8504a727ff4e/librt-0.10.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d261c6a2f93335a5167887fb0223e8b98ffce20ee3fde242e8e58a37ece6d0e5", size = 293993, upload-time = "2026-05-05T16:30:52.577Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/8d/68b6086bed1fcdc314c640ea04e31e52d18052e08059fa595409d66a51a9/librt-0.10.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e2ffd44963f8e7f68995504d90f9881d64e94dc1d8e310039b9526108fc0c0f7", size = 284254, upload-time = "2026-05-05T16:30:55.086Z" },
+ { url = "https://files.pythonhosted.org/packages/06/c8/b810f1d84ec34a5a7ed93d7b510ab04164d75fbdf23088d5c3fbe6b08357/librt-0.10.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5f285f6455ed495791c4d8630e5af732960adea93cac4c893d15619f2eae53e8", size = 284925, upload-time = "2026-05-05T16:30:56.728Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/00/3c82d4158c5a2c62528b8fccce65a8c9ad700e480e86f9389387435089a5/librt-0.10.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f6034ff52e663d34c7b82ef2aa2f94ad7c1d939e2368e63b06844bc4d127d2e1", size = 307830, upload-time = "2026-05-05T16:30:58.377Z" },
+ { url = "https://files.pythonhosted.org/packages/99/3a/9c635ac3e8a00383ff689161d3eac8a30b3b2ddc711b40471e6b8983ea29/librt-0.10.0-cp314-cp314t-win32.whl", hash = "sha256:657860fd877fba6a241ea088ef99f63ca819945d3c715265da670bad56c37ebe", size = 60147, upload-time = "2026-05-05T16:31:00.293Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/e8/6f65f3e565d4ac212cddddd552eacc8035ffdf941ca0ad6fe945a211d41f/librt-0.10.0-cp314-cp314t-win_amd64.whl", hash = "sha256:56ded2d66010203a0cb5af063b609e3f079531a0e5e576d618dece859fd2e1af", size = 68649, upload-time = "2026-05-05T16:31:01.778Z" },
+ { url = "https://files.pythonhosted.org/packages/51/78/a0705a67cacd81e5fa01a5035b3adbdfbb43a7b8d4bd27e2b282ae61baf2/librt-0.10.0-cp314-cp314t-win_arm64.whl", hash = "sha256:1ee63f30abf18ed4830fdbaf87b2b6f4bba1e198d46085c314edde4045e56715", size = 58247, upload-time = "2026-05-05T16:31:03.191Z" },
+]
+
+[[package]]
+name = "linkify-it-py"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "uc-micro-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2e/c9/06ea13676ef354f0af6169587ae292d3e2406e212876a413bf9eece4eb23/linkify_it_py-2.1.0.tar.gz", hash = "sha256:43360231720999c10e9328dc3691160e27a718e280673d444c38d7d3aaa3b98b", size = 29158, upload-time = "2026-03-01T07:48:47.683Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b4/de/88b3be5c31b22333b3ca2f6ff1de4e863d8fe45aaea7485f591970ec1d3e/linkify_it_py-2.1.0-py3-none-any.whl", hash = "sha256:0d252c1594ecba2ecedc444053db5d3a9b7ec1b0dd929c8f1d74dce89f86c05e", size = 19878, upload-time = "2026-03-01T07:48:46.098Z" },
]
[[package]]
@@ -1246,6 +1259,11 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
]
+[package.optional-dependencies]
+linkify = [
+ { name = "linkify-it-py" },
+]
+
[[package]]
name = "markupsafe"
version = "3.0.3"
@@ -1321,6 +1339,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" },
]
+[[package]]
+name = "mdit-py-plugins"
+version = "0.5.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown-it-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b2/fd/a756d36c0bfba5f6e39a1cdbdbfdd448dc02692467d83816dff4592a1ebc/mdit_py_plugins-0.5.0.tar.gz", hash = "sha256:f4918cb50119f50446560513a8e311d574ff6aaed72606ddae6d35716fe809c6", size = 44655, upload-time = "2025-08-11T07:25:49.083Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fb/86/dd6e5db36df29e76c7a7699123569a4a18c1623ce68d826ed96c62643cae/mdit_py_plugins-0.5.0-py3-none-any.whl", hash = "sha256:07a08422fc1936a5d26d146759e9155ea466e842f5ab2f7d2266dd084c8dab1f", size = 57205, upload-time = "2025-08-11T07:25:47.597Z" },
+]
+
[[package]]
name = "mdurl"
version = "0.1.2"
@@ -1332,11 +1362,11 @@ wheels = [
[[package]]
name = "mistune"
-version = "3.2.0"
+version = "3.2.1"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/9d/55/d01f0c4b45ade6536c51170b9043db8b2ec6ddf4a35c7ea3f5f559ac935b/mistune-3.2.0.tar.gz", hash = "sha256:708487c8a8cdd99c9d90eb3ed4c3ed961246ff78ac82f03418f5183ab70e398a", size = 95467, upload-time = "2025-12-23T11:36:34.994Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/ca/84/620cc3f7e3adf6f5067e10f4dbae71295d8f9e16d5d3f9ef97c40f2f592c/mistune-3.2.1.tar.gz", hash = "sha256:7c8e5501d38bac1582e067e46c8343f17d57ea1aaa735823f3aba1fd59c88a28", size = 98003, upload-time = "2026-05-03T14:33:22.312Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598, upload-time = "2025-12-23T11:36:33.211Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/7f/a946aa4f8752b37102b41e64dca18a1976ac705c3a0d1dfe74d820a02552/mistune-3.2.1-py3-none-any.whl", hash = "sha256:78cdb0ba5e938053ccf63651b352508d2efa9411dc8810bfb05f2dc5140c0048", size = 53749, upload-time = "2026-05-03T14:33:20.551Z" },
]
[[package]]
@@ -1466,7 +1496,7 @@ wheels = [
[[package]]
name = "notebook"
-version = "7.5.5"
+version = "7.5.6"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jupyter-server" },
@@ -1475,9 +1505,9 @@ dependencies = [
{ name = "notebook-shim" },
{ name = "tornado" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/1f/6d/41052c48d6f6349ca0a7c4d1f6a78464de135e6d18f5829ba2510e62184c/notebook-7.5.5.tar.gz", hash = "sha256:dc0bfab0f2372c8278c457423d3256c34154ac2cc76bf20e9925260c461013c3", size = 14169167, upload-time = "2026-03-11T16:32:51.922Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/2a/c2/cf59bd2e6f2c8b976b52477e3e53bf6f97bc714ed046a51821afb428eaee/notebook-7.5.6.tar.gz", hash = "sha256:621174aade80108f0020b0f00738000b215f75fa3cd90771ad7aa0f24536a4e1", size = 14170814, upload-time = "2026-04-30T11:46:26.613Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f8/aa/cbd1deb9f07446241e88f8d5fecccd95b249bca0b4e5482214a4d1714c49/notebook-7.5.5-py3-none-any.whl", hash = "sha256:a7c14dbeefa6592e87f72290ca982e0c10f5bbf3786be2a600fda9da2764a2b8", size = 14578929, upload-time = "2026-03-11T16:32:48.021Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/d6/1fd0646b9bbd9efbb0b8ae21b2325fbef515769a5621c03e31d8eb8da587/notebook-7.5.6-py3-none-any.whl", hash = "sha256:4dde3f8fb55fa8fb7946d58c6e869ce9baf46d00fc070664f62604569d0faca0", size = 14581730, upload-time = "2026-04-30T11:46:22.342Z" },
]
[[package]]
@@ -1494,11 +1524,11 @@ wheels = [
[[package]]
name = "packaging"
-version = "26.0"
+version = "26.2"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
+ { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" },
]
[[package]]
@@ -1512,20 +1542,20 @@ wheels = [
[[package]]
name = "parso"
-version = "0.8.6"
+version = "0.8.7"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/81/76/a1e769043c0c0c9fe391b702539d594731a4362334cdf4dc25d0c09761e7/parso-0.8.6.tar.gz", hash = "sha256:2b9a0332696df97d454fa67b81618fd69c35a7b90327cbe6ba5c92d2c68a7bfd", size = 401621, upload-time = "2026-02-09T15:45:24.425Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/30/4b/90c937815137d43ce71ba043cd3566221e9df6b9c805f24b5d138c9d40a7/parso-0.8.7.tar.gz", hash = "sha256:eaaac4c9fdd5e9e8852dc778d2d7405897ec510f2a298071453e5e3a07914bb1", size = 401824, upload-time = "2026-05-01T23:13:02.138Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/b6/61/fae042894f4296ec49e3f193aff5d7c18440da9e48102c3315e1bc4519a7/parso-0.8.6-py2.py3-none-any.whl", hash = "sha256:2c549f800b70a5c4952197248825584cb00f033b29c692671d3bf08bf380baff", size = 106894, upload-time = "2026-02-09T15:45:21.391Z" },
+ { url = "https://files.pythonhosted.org/packages/99/5d/8268b644392ee874ee82a635cd0df1773de230bde356c38de28e298392cc/parso-0.8.7-py2.py3-none-any.whl", hash = "sha256:a8926eb2a1b915486941fdbd31e86a4baf88fe8c210f25f2f35ecec5b574ca1c", size = 107025, upload-time = "2026-05-01T23:12:58.867Z" },
]
[[package]]
name = "pathspec"
-version = "1.0.4"
+version = "1.1.1"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" },
]
[[package]]
@@ -1629,27 +1659,27 @@ wheels = [
[[package]]
name = "plum-dispatch"
-version = "2.8.0"
+version = "2.9.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "beartype" },
{ name = "rich" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/5e/cf/2f2b0dd84edbb2951a845ba98d29f651bbbd467039c368fcfa22904905cd/plum_dispatch-2.8.0.tar.gz", hash = "sha256:453fc7bc67d2a39492c834b00c94d816871d148b5a0a5d3f49e2bbf2391e2619", size = 241272, upload-time = "2026-03-17T21:24:41.338Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/1b/b7/84146ae5ff6c40d11357acdb36aafe3db7e104de01c1026d8e1b0ce3e7f1/plum_dispatch-2.9.0.tar.gz", hash = "sha256:fb45c5b2dd4dadd57def51bcf321dfa3a258df5c725f43adea7e7f6db3b79b52", size = 244502, upload-time = "2026-04-28T08:38:34.442Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/e9/a3/cdb8130cc05a13c75237d2be4821f38c0b99d1a64980b6529d788a43a501/plum_dispatch-2.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fca6b6dbed8c686f6f827e9c95f60334ba70ee27cccef1f44a50d42a30221748", size = 165288, upload-time = "2026-03-17T21:24:31.203Z" },
- { url = "https://files.pythonhosted.org/packages/25/fe/b1dbbdd1864d4ca825b3b5079fca852ea5e5a4f223aa866702f751b02dba/plum_dispatch-2.8.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:599025e7bd7e16f198e5ccaad0ca51036fcbeb43eb41525a5ef705b9a25bb192", size = 194360, upload-time = "2026-03-17T21:24:32.531Z" },
- { url = "https://files.pythonhosted.org/packages/6b/01/a8947d5c92824a6bc019696e5d9f150178736ecd8e6766db38b38e0f0fda/plum_dispatch-2.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:c0e6146881b71eb6a6355d18476bed356071d1dff45a7cf4ae31f7f4bffb01b9", size = 146826, upload-time = "2026-03-17T21:24:34.076Z" },
- { url = "https://files.pythonhosted.org/packages/68/25/380300b3468417999ca0db0522eeae1017798519fe28753e8ad110718174/plum_dispatch-2.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d60c0040207495afddab3f80c498a5e8f9dab29f8d143468c51d668fe70ed291", size = 165256, upload-time = "2026-03-17T21:24:35.341Z" },
- { url = "https://files.pythonhosted.org/packages/59/2f/94e4e62ad437996341d03471bd398f3f6bf4c5f3a1fa524ba53f02b6896d/plum_dispatch-2.8.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f88aaf08a562e7a559851679a051b32306b67fd403ed6070915a966f048a83e9", size = 193632, upload-time = "2026-03-17T21:24:37.035Z" },
- { url = "https://files.pythonhosted.org/packages/fb/d2/772d1e3071971a30e70b78df421f51788354337a7f94957d910ba3cd8a5a/plum_dispatch-2.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:53bc084b335e5071b72353830a9f2cdacd58c9e959089be5778b6d638b5062f9", size = 146931, upload-time = "2026-03-17T21:24:38.8Z" },
- { url = "https://files.pythonhosted.org/packages/4b/7d/6d1a0a5851fb590564045471bdd6f405426ae4214cafe530ceba297e5c0d/plum_dispatch-2.8.0-py3-none-any.whl", hash = "sha256:f5dfffc46de1d8208ba281fdb0f41d6065c7341c1fde76fc83b4b78810c30c7e", size = 44547, upload-time = "2026-03-17T21:24:40.059Z" },
+ { url = "https://files.pythonhosted.org/packages/82/d6/fc6591336731b5e291319ec3c43d81cd6cc7940c9079183b333b85ed4d77/plum_dispatch-2.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:39a325b0b041fad687271d71abc11b5271d5a3b62af2c6b1271f4ececc3b59de", size = 175166, upload-time = "2026-04-28T08:38:24.467Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/4d/5418649397b477ae08839564c97596ede5ef36523147899bb913bbe959d1/plum_dispatch-2.9.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d39b20a1af776a39e4a0833e97c6258d938e5d874c7f3537bb7d772c39718c1e", size = 205988, upload-time = "2026-04-28T08:38:25.838Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/a5/28a6c4e45c4465a6e1a30d65206e913c217690752dc3c9261d78a9187aed/plum_dispatch-2.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:beb9b92c6994404a0d2dc83c857263f5da49519575e5cbb8a13060652746c44c", size = 152563, upload-time = "2026-04-28T08:38:27.37Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/18/19e01dbbaececb75815abb37bc71e10d87a7561829b4eae47ec3b342c94f/plum_dispatch-2.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:78987caf558fbdd675a7a4a5c144069f1f9524610195123fb7d0f0234d0af01a", size = 174490, upload-time = "2026-04-28T08:38:28.881Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/29/7b3de57cd86430fd00d71bc5a8a078bf2c63d4ada7fdfb30853fe976a19f/plum_dispatch-2.9.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:36662d76ae6d87aaa041fade036d2242f0b88b68c9fb4c96b7ba0026320065d3", size = 204734, upload-time = "2026-04-28T08:38:30.398Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/98/23d19326af0da251bb98a39f517ab6da983e5aad5eb9cc398b60933df2cc/plum_dispatch-2.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:a0d16daf09482a6588025e9f133a338d99474e8dd3c3dbbc4c5282a4fffe5a0e", size = 152624, upload-time = "2026-04-28T08:38:31.886Z" },
+ { url = "https://files.pythonhosted.org/packages/64/a7/ee4d01d26032b060d379f44a29124180f756d907e3840d3bc450f8a0d2a7/plum_dispatch-2.9.0-py3-none-any.whl", hash = "sha256:5a516cdac5460343937a2b813562ac00b0eeac973ac023916e538610bdf34397", size = 45328, upload-time = "2026-04-28T08:38:33.022Z" },
]
[[package]]
name = "pre-commit"
-version = "4.5.1"
+version = "4.6.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cfgv" },
@@ -1658,9 +1688,9 @@ dependencies = [
{ name = "pyyaml" },
{ name = "virtualenv" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/40/f1/6d86a29246dfd2e9b6237f0b5823717f60cad94d47ddc26afa916d21f525/pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61", size = 198232, upload-time = "2025-12-16T21:14:33.552Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/8e/22/2de9408ac81acbb8a7d05d4cc064a152ccf33b3d480ebe0cd292153db239/pre_commit-4.6.0.tar.gz", hash = "sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9", size = 198525, upload-time = "2026-04-21T20:31:41.613Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437, upload-time = "2025-12-16T21:14:32.409Z" },
+ { url = "https://files.pythonhosted.org/packages/80/6e/4b28b62ecb6aae56769c34a8ff1d661473ec1e9519e2d5f8b2c150086b26/pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b", size = 226472, upload-time = "2026-04-21T20:31:40.092Z" },
]
[[package]]
@@ -1741,7 +1771,7 @@ wheels = [
[[package]]
name = "pydantic"
-version = "2.13.0"
+version = "2.13.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "annotated-types" },
@@ -1749,84 +1779,84 @@ dependencies = [
{ name = "typing-extensions" },
{ name = "typing-inspection" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/84/6b/69fd5c7194b21ebde0f8637e2a4ddc766ada29d472bfa6a5ca533d79549a/pydantic-2.13.0.tar.gz", hash = "sha256:b89b575b6e670ebf6e7448c01b41b244f471edd276cd0b6fe02e7e7aca320070", size = 843468, upload-time = "2026-04-13T10:51:35.571Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/d9/e4/40d09941a2cebcb20609b86a559817d5b9291c49dd6f8c87e5feffbe703a/pydantic-2.13.3.tar.gz", hash = "sha256:af09e9d1d09f4e7fe37145c1f577e1d61ceb9a41924bf0094a36506285d0a84d", size = 844068, upload-time = "2026-04-20T14:46:43.632Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/01/d7/c3a52c61f5b7be648e919005820fbac33028c6149994cd64453f49951c17/pydantic-2.13.0-py3-none-any.whl", hash = "sha256:ab0078b90da5f3e2fd2e71e3d9b457ddcb35d0350854fbda93b451e28d56baaf", size = 471872, upload-time = "2026-04-13T10:51:33.343Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/0a/fd7d723f8f8153418fb40cf9c940e82004fce7e987026b08a68a36dd3fe7/pydantic-2.13.3-py3-none-any.whl", hash = "sha256:6db14ac8dfc9a1e57f87ea2c0de670c251240f43cb0c30a5130e9720dc612927", size = 471981, upload-time = "2026-04-20T14:46:41.402Z" },
]
[[package]]
name = "pydantic-core"
-version = "2.46.0"
+version = "2.46.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/6f/0a/9414cddf82eda3976b14048cc0fa8f5b5d1aecb0b22e1dcd2dbfe0e139b1/pydantic_core-2.46.0.tar.gz", hash = "sha256:82d2498c96be47b47e903e1378d1d0f770097ec56ea953322f39936a7cf34977", size = 471441, upload-time = "2026-04-13T09:06:33.813Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/a7/d2/206c72ad47071559142a35f71efc29eb16448a4a5ae9487230ab8e4e292b/pydantic_core-2.46.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:66ccedb02c934622612448489824955838a221b3a35875458970521ef17b2f9c", size = 2117060, upload-time = "2026-04-13T09:04:47.443Z" },
- { url = "https://files.pythonhosted.org/packages/17/2c/7a53b33f91c8b77e696b1a6aa3bed609bf9374bdc0f8dcda681bc7d922b8/pydantic_core-2.46.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a44f27f4d2788ef9876ec47a43739b118c5904d74f418f53398f6ced3bbcacf2", size = 1951802, upload-time = "2026-04-13T09:05:34.591Z" },
- { url = "https://files.pythonhosted.org/packages/fc/20/90e548c1f6d38800ef11c915881525770ce270d8e5e887563ff046a08674/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26a1032bcce6ca4b4670eb3f7d8195bd0a8b8f255f1307823e217ca3cfa7c27", size = 1976621, upload-time = "2026-04-13T09:04:03.909Z" },
- { url = "https://files.pythonhosted.org/packages/20/3c/9c5810ca70b60c623488cdd80f7e9ee1a0812df81e97098b64788719860f/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1b8d1412f725060527e56675904b17a2d421dddcf861eecf7c75b9dda47921a4", size = 2056721, upload-time = "2026-04-13T09:04:40.992Z" },
- { url = "https://files.pythonhosted.org/packages/1a/a3/d6e5f4cdec84278431c75540f90838c9d0a4dfe9402a8f3902073660ff28/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc3d1569edd859cabaa476cabce9eecd05049a7966af7b4a33b541bfd4ca1104", size = 2239634, upload-time = "2026-04-13T09:03:52.478Z" },
- { url = "https://files.pythonhosted.org/packages/46/42/ef58aacf330d8de6e309d62469aa1f80e945eaf665929b4037ac1bfcebc1/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:38108976f2d8afaa8f5067fd1390a8c9f5cc580175407cda636e76bc76e88054", size = 2315739, upload-time = "2026-04-13T09:05:04.971Z" },
- { url = "https://files.pythonhosted.org/packages/8b/86/c63b12fafa2d86a515bfd1840b39c23a49302f02b653161bf9c3a0566c50/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5a06d8ed01dad5575056b5187e5959b336793c6047920a3441ee5b03533836", size = 2098169, upload-time = "2026-04-13T09:07:27.151Z" },
- { url = "https://files.pythonhosted.org/packages/76/19/b5b33a2f6be4755b21a20434293c4364be255f4c1a108f125d101d4cc4ee/pydantic_core-2.46.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:04017ace142da9ce27cafd423a480872571b5c7e80382aec22f7d715ca8eb870", size = 2170830, upload-time = "2026-04-13T09:04:39.448Z" },
- { url = "https://files.pythonhosted.org/packages/99/ae/7559f99a29b7d440012ddb4da897359304988a881efaca912fd2f655652e/pydantic_core-2.46.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2629ad992ed1b1c012e6067f5ffafd3336fcb9b54569449fabb85621f1444ed3", size = 2203901, upload-time = "2026-04-13T09:04:01.048Z" },
- { url = "https://files.pythonhosted.org/packages/dd/0e/b0ef945a39aeb4ac58da316813e1106b7fbdfbf20ac141c1c27904355ac5/pydantic_core-2.46.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3068b1e7bd986aebc88f6859f8353e72072538dcf92a7fb9cf511a0f61c5e729", size = 2191789, upload-time = "2026-04-13T09:06:39.915Z" },
- { url = "https://files.pythonhosted.org/packages/90/f4/830484e07188c1236b013995818888ab93bab8fd88aa9689b1d8fd22220d/pydantic_core-2.46.0-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:1e366916ff69ff700aa9326601634e688581bc24c5b6b4f8738d809ec7d72611", size = 2344423, upload-time = "2026-04-13T09:05:12.252Z" },
- { url = "https://files.pythonhosted.org/packages/fd/ba/e455c18cbdc333177af754e740be4fe9d1de173d65bbe534daf88da02ac0/pydantic_core-2.46.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:485a23e8f4618a1b8e23ac744180acde283fffe617f96923d25507d5cade62ec", size = 2384037, upload-time = "2026-04-13T09:06:24.503Z" },
- { url = "https://files.pythonhosted.org/packages/78/1f/b35d20d73144a41e78de0ae398e60fdd8bed91667daa1a5a92ab958551ba/pydantic_core-2.46.0-cp312-cp312-win32.whl", hash = "sha256:520940e1b702fe3b33525d0351777f25e9924f1818ca7956447dabacf2d339fd", size = 1967068, upload-time = "2026-04-13T09:05:23.374Z" },
- { url = "https://files.pythonhosted.org/packages/d1/84/4b6252e9606e8295647b848233cc4137ee0a04ebba8f0f9fb2977655b38c/pydantic_core-2.46.0-cp312-cp312-win_amd64.whl", hash = "sha256:90d2048e0339fa365e5a66aefe760ddd3b3d0a45501e088bc5bc7f4ed9ff9571", size = 2071008, upload-time = "2026-04-13T09:05:21.392Z" },
- { url = "https://files.pythonhosted.org/packages/39/95/d08eb508d4d5560ccbd226ee5971e5ef9b749aba9b413c0c4ed6e406d4f6/pydantic_core-2.46.0-cp312-cp312-win_arm64.whl", hash = "sha256:a70247649b7dffe36648e8f34be5ce8c5fa0a27ff07b071ea780c20a738c05ce", size = 2036634, upload-time = "2026-04-13T09:05:48.299Z" },
- { url = "https://files.pythonhosted.org/packages/df/05/ab3b0742bad1d51822f1af0c4232208408902bdcfc47601f3b812e09e6c2/pydantic_core-2.46.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:a05900c37264c070c683c650cbca8f83d7cbb549719e645fcd81a24592eac788", size = 2116814, upload-time = "2026-04-13T09:04:12.41Z" },
- { url = "https://files.pythonhosted.org/packages/98/08/30b43d9569d69094a0899a199711c43aa58fce6ce80f6a8f7693673eb995/pydantic_core-2.46.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8de8e482fd4f1e3f36c50c6aac46d044462615d8f12cfafc6bebeaa0909eea22", size = 1951867, upload-time = "2026-04-13T09:04:02.364Z" },
- { url = "https://files.pythonhosted.org/packages/db/a0/bf9a1ba34537c2ed3872a48195291138fdec8fe26c4009776f00d63cf0c8/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c525ecf8a4cdf198327b65030a7d081867ad8e60acb01a7214fff95cf9832d47", size = 1977040, upload-time = "2026-04-13T09:06:16.088Z" },
- { url = "https://files.pythonhosted.org/packages/71/70/0ba03c20e1e118219fc18c5417b008b7e880f0e3fb38560ec4465984d471/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f14581aeb12e61542ce73b9bfef2bca5439d65d9ab3efe1a4d8e346b61838f9b", size = 2055284, upload-time = "2026-04-13T09:05:25.125Z" },
- { url = "https://files.pythonhosted.org/packages/58/cf/1e320acefbde7fb7158a9e5def55e0adf9a4634636098ce28dc6b978e0d3/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c108067f2f7e190d0dbd81247d789ec41f9ea50ccd9265a3a46710796ac60530", size = 2238896, upload-time = "2026-04-13T09:05:01.345Z" },
- { url = "https://files.pythonhosted.org/packages/df/f5/ea8ba209756abe9eba891bb0ef3772b4c59a894eb9ad86cd5bd0dd4e3e52/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ac10967e9a7bb1b96697374513f9a1a90a59e2fb41566b5e00ee45392beac59", size = 2314353, upload-time = "2026-04-13T09:06:07.942Z" },
- { url = "https://files.pythonhosted.org/packages/e8/f8/5885350203b72e96438eee7f94de0d8f0442f4627237ca8ef75de34db1cd/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7897078fe8a13b73623c0955dfb2b3d2c9acb7177aac25144758c9e5a5265aaa", size = 2098522, upload-time = "2026-04-13T09:04:23.239Z" },
- { url = "https://files.pythonhosted.org/packages/bf/88/5930b0e828e371db5a556dd3189565417ddc3d8316bb001058168aadcf5f/pydantic_core-2.46.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:e69ce405510a419a082a78faed65bb4249cfb51232293cc675645c12f7379bf7", size = 2168757, upload-time = "2026-04-13T09:07:12.46Z" },
- { url = "https://files.pythonhosted.org/packages/da/75/63d563d3035a0548e721c38b5b69fd5626fdd51da0f09ff4467503915b82/pydantic_core-2.46.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fd28d13eea0d8cf351dc1fe274b5070cc8e1cca2644381dee5f99de629e77cf3", size = 2202518, upload-time = "2026-04-13T09:05:44.418Z" },
- { url = "https://files.pythonhosted.org/packages/a7/53/1958eacbfddc41aadf5ae86dd85041bf054b675f34a2fa76385935f96070/pydantic_core-2.46.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:ee1547a6b8243e73dd10f585555e5a263395e55ce6dea618a078570a1e889aef", size = 2190148, upload-time = "2026-04-13T09:06:56.151Z" },
- { url = "https://files.pythonhosted.org/packages/c7/17/098cc6d3595e4623186f2bc6604a6195eb182e126702a90517236391e9ce/pydantic_core-2.46.0-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:c3dc68dcf62db22a18ddfc3ad4960038f72b75908edc48ae014d7ac8b391d57a", size = 2342925, upload-time = "2026-04-13T09:04:17.286Z" },
- { url = "https://files.pythonhosted.org/packages/71/a7/abdb924620b1ac535c690b36ad5b8871f376104090f8842c08625cecf1d3/pydantic_core-2.46.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:004a2081c881abfcc6854a4623da6a09090a0d7c1398a6ae7133ca1256cee70b", size = 2383167, upload-time = "2026-04-13T09:04:52.643Z" },
- { url = "https://files.pythonhosted.org/packages/d7/c9/2ddd10f50e4b7350d2574629a0f53d8d4eb6573f9c19a6b43e6b1487a31d/pydantic_core-2.46.0-cp313-cp313-win32.whl", hash = "sha256:59d24ec8d5eaabad93097525a69d0f00f2667cb353eb6cda578b1cfff203ceef", size = 1965660, upload-time = "2026-04-13T09:06:05.877Z" },
- { url = "https://files.pythonhosted.org/packages/b5/e7/1efc38ed6f2680c032bcefa0e3ebd496a8c77e92dfdb86b07d0f2fc632b1/pydantic_core-2.46.0-cp313-cp313-win_amd64.whl", hash = "sha256:71186dad5ac325c64d68fe0e654e15fd79802e7cc42bc6f0ff822d5ad8b1ab25", size = 2069563, upload-time = "2026-04-13T09:07:14.738Z" },
- { url = "https://files.pythonhosted.org/packages/c3/1e/a325b4989e742bf7e72ed35fa124bc611fd76539c9f8cd2a9a7854473533/pydantic_core-2.46.0-cp313-cp313-win_arm64.whl", hash = "sha256:8e4503f3213f723842c9a3b53955c88a9cfbd0b288cbd1c1ae933aebeec4a1b4", size = 2034966, upload-time = "2026-04-13T09:04:21.629Z" },
- { url = "https://files.pythonhosted.org/packages/36/3b/914891d384cdbf9a6f464eb13713baa22ea1e453d4da80fb7da522079370/pydantic_core-2.46.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:4fc801c290342350ffc82d77872054a934b2e24163727263362170c1db5416ca", size = 2113349, upload-time = "2026-04-13T09:04:59.407Z" },
- { url = "https://files.pythonhosted.org/packages/35/95/3a0c6f65e231709fb3463e32943c69d10285cb50203a2130a4732053a06d/pydantic_core-2.46.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0a36f2cc88170cc177930afcc633a8c15907ea68b59ac16bd180c2999d714940", size = 1949170, upload-time = "2026-04-13T09:06:09.935Z" },
- { url = "https://files.pythonhosted.org/packages/d1/63/d845c36a608469fe7bee226edeff0984c33dbfe7aecd755b0e7ab5a275c4/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a3912e0c568a1f99d4d6d3e41def40179d61424c0ca1c8c87c4877d7f6fd7fb", size = 1977914, upload-time = "2026-04-13T09:04:56.16Z" },
- { url = "https://files.pythonhosted.org/packages/08/6f/f2e7a7f85931fb31671f5378d1c7fc70606e4b36d59b1b48e1bd1ef5d916/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3534c3415ed1a19ab23096b628916a827f7858ec8db49ad5d7d1e44dc13c0d7b", size = 2050538, upload-time = "2026-04-13T09:05:06.789Z" },
- { url = "https://files.pythonhosted.org/packages/8c/97/f4aa7181dd9a16dd9059a99fc48fdab0c2aab68307283a5c04cf56de68c4/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21067396fc285609323a4db2f63a87570044abe0acddfcca8b135fc7948e3db7", size = 2236294, upload-time = "2026-04-13T09:07:03.2Z" },
- { url = "https://files.pythonhosted.org/packages/24/c1/6a5042fc32765c87101b500f394702890af04239c318b6002cfd627b710d/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2afd85b7be186e2fe7cdbb09a3d964bcc2042f65bbcc64ad800b3c7915032655", size = 2312954, upload-time = "2026-04-13T09:06:11.919Z" },
- { url = "https://files.pythonhosted.org/packages/cb/e4/566101a561492ce8454f0844ca29c3b675a6b3a7b3ff577db85ed05c8c50/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67e2c2e171b78db8154da602de72ffdc473c6ee51de8a9d80c0f1cd4051abfc7", size = 2102533, upload-time = "2026-04-13T09:06:58.664Z" },
- { url = "https://files.pythonhosted.org/packages/3e/ac/adc11ee1646a5c4dd9abb09a00e7909e6dc25beddc0b1310ca734bb9b48e/pydantic_core-2.46.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c16ae1f3170267b1a37e16dba5c297bdf60c8b5657b147909ca8774ce7366644", size = 2169447, upload-time = "2026-04-13T09:04:11.143Z" },
- { url = "https://files.pythonhosted.org/packages/26/73/408e686b45b82d28ac19e8229e07282254dbee6a5d24c5c7cf3cf3716613/pydantic_core-2.46.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:133b69e1c1ba34d3702eed73f19f7f966928f9aa16663b55c2ebce0893cca42e", size = 2200672, upload-time = "2026-04-13T09:03:54.056Z" },
- { url = "https://files.pythonhosted.org/packages/0a/3b/807d5b035ec891b57b9079ce881f48263936c37bd0d154a056e7fd152afb/pydantic_core-2.46.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:15ed8e5bde505133d96b41702f31f06829c46b05488211a5b1c7877e11de5eb5", size = 2188293, upload-time = "2026-04-13T09:07:07.614Z" },
- { url = "https://files.pythonhosted.org/packages/f1/ed/719b307516285099d1196c52769fdbe676fd677da007b9c349ae70b7226d/pydantic_core-2.46.0-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:8cfc29a1c66a7f0fcb36262e92f353dd0b9c4061d558fceb022e698a801cb8ae", size = 2335023, upload-time = "2026-04-13T09:04:05.176Z" },
- { url = "https://files.pythonhosted.org/packages/8d/90/8718e4ae98c4e8a7325afdc079be82be1e131d7a47cb6c098844a9531ffe/pydantic_core-2.46.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e1155708540f13845bf68d5ac511a55c76cfe2e057ed12b4bf3adac1581fc5c2", size = 2377155, upload-time = "2026-04-13T09:06:18.081Z" },
- { url = "https://files.pythonhosted.org/packages/dd/dc/7172789283b963f81da2fc92b186e22de55687019079f71c4d570822502b/pydantic_core-2.46.0-cp314-cp314-win32.whl", hash = "sha256:de5635a48df6b2eef161d10ea1bc2626153197333662ba4cd700ee7ec1aba7f5", size = 1963078, upload-time = "2026-04-13T09:05:30.615Z" },
- { url = "https://files.pythonhosted.org/packages/e0/69/03a7ea4b6264def3a44eabf577528bcec2f49468c5698b2044dea54dc07e/pydantic_core-2.46.0-cp314-cp314-win_amd64.whl", hash = "sha256:f07a5af60c5e7cf53dd1ff734228bd72d0dc9938e64a75b5bb308ca350d9681e", size = 2068439, upload-time = "2026-04-13T09:04:57.729Z" },
- { url = "https://files.pythonhosted.org/packages/f5/eb/1c3afcfdee2ab6634b802ab0a0f1966df4c8b630028ec56a1cb0a710dc58/pydantic_core-2.46.0-cp314-cp314-win_arm64.whl", hash = "sha256:e7a77eca3c7d5108ff509db20aae6f80d47c7ed7516d8b96c387aacc42f3ce0f", size = 2026470, upload-time = "2026-04-13T09:05:08.654Z" },
- { url = "https://files.pythonhosted.org/packages/5c/30/1177dde61b200785c4739665e3aa03a9d4b2c25d2d0408b07d585e633965/pydantic_core-2.46.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:5e7cdd4398bee1aaeafe049ac366b0f887451d9ae418fd8785219c13fea2f928", size = 2107447, upload-time = "2026-04-13T09:05:46.314Z" },
- { url = "https://files.pythonhosted.org/packages/b1/60/4e0f61f99bdabbbc309d364a2791e1ba31e778a4935bc43391a7bdec0744/pydantic_core-2.46.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5c2c92d82808e27cef3f7ab3ed63d657d0c755e0dbe5b8a58342e37bdf09bd2e", size = 1926927, upload-time = "2026-04-13T09:06:20.371Z" },
- { url = "https://files.pythonhosted.org/packages/1d/d0/67f89a8269152c1d6eaa81f04e75a507372ebd8ca7382855a065222caa80/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bab80af91cd7014b45d1089303b5f844a9d91d7da60eabf3d5f9694b32a6655", size = 1966613, upload-time = "2026-04-13T09:07:05.389Z" },
- { url = "https://files.pythonhosted.org/packages/cd/07/8dfdc3edc78f29a80fb31f366c50203ec904cff6a4c923599bf50ac0d0ff/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e49ffdb714bc990f00b39d1ad1d683033875b5af15582f60c1f34ad3eeccfaa", size = 2032902, upload-time = "2026-04-13T09:06:42.47Z" },
- { url = "https://files.pythonhosted.org/packages/b0/2a/111c5e8fe24f99c46bcad7d3a82a8f6dbc738066e2c72c04c71f827d8c78/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ca877240e8dbdeef3a66f751dc41e5a74893767d510c22a22fc5c0199844f0ce", size = 2244456, upload-time = "2026-04-13T09:05:36.484Z" },
- { url = "https://files.pythonhosted.org/packages/6b/7c/cfc5d11c15a63ece26e148572c77cfbb2c7f08d315a7b63ef0fe0711d753/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87e6843f89ecd2f596d7294e33196c61343186255b9880c4f1b725fde8b0e20d", size = 2294535, upload-time = "2026-04-13T09:06:01.689Z" },
- { url = "https://files.pythonhosted.org/packages/c4/2c/f0d744e3dab7bd026a3f4670a97a295157cff923a2666d30a15a70a7e3d0/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e20bc5add1dd9bc3b9a3600d40632e679376569098345500799a6ad7c5d46c72", size = 2104621, upload-time = "2026-04-13T09:04:34.388Z" },
- { url = "https://files.pythonhosted.org/packages/a7/64/e7cc4698dc024264d214b51d5a47a2404221b12060dd537d76f831b2120a/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:ee6ff79a5f0289d64a9d6696a3ce1f98f925b803dd538335a118231e26d6d827", size = 2130718, upload-time = "2026-04-13T09:04:26.23Z" },
- { url = "https://files.pythonhosted.org/packages/0b/a8/224e655fec21f7d4441438ad2ecaccb33b5a3876ce7bb2098c74a49efc14/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:52d35cfb58c26323101c7065508d7bb69bb56338cda9ea47a7b32be581af055d", size = 2180738, upload-time = "2026-04-13T09:05:50.253Z" },
- { url = "https://files.pythonhosted.org/packages/32/7b/b3025618ed4c4e4cbaa9882731c19625db6669896b621760ea95bc1125ef/pydantic_core-2.46.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d14cc5a6f260fa78e124061eebc5769af6534fc837e9a62a47f09a2c341fa4ea", size = 2171222, upload-time = "2026-04-13T09:07:29.929Z" },
- { url = "https://files.pythonhosted.org/packages/7b/e3/68170aa1d891920af09c1f2f34df61dc5ff3a746400027155523e3400e89/pydantic_core-2.46.0-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:4f7ff859d663b6635f6307a10803d07f0d09487e16c3d36b1744af51dbf948b2", size = 2320040, upload-time = "2026-04-13T09:06:35.732Z" },
- { url = "https://files.pythonhosted.org/packages/67/1b/5e65807001b84972476300c1f49aea2b4971b7e9fffb5c2654877dadd274/pydantic_core-2.46.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:8ef749be6ed0d69dba31902aaa8255a9bb269ae50c93888c4df242d8bb7acd9e", size = 2377062, upload-time = "2026-04-13T09:07:39.945Z" },
- { url = "https://files.pythonhosted.org/packages/75/03/48caa9dd5f28f7662bd52bff454d9a451f6b7e5e4af95e289e5e170749c9/pydantic_core-2.46.0-cp314-cp314t-win32.whl", hash = "sha256:d93ca72870133f86360e4bb0c78cd4e6ba2a0f9f3738a6486909ffc031463b32", size = 1951028, upload-time = "2026-04-13T09:04:20.224Z" },
- { url = "https://files.pythonhosted.org/packages/87/ed/e97ff55fe28c0e6e3cba641d622b15e071370b70e5f07c496b07b65db7c9/pydantic_core-2.46.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6ebb2668afd657e2127cb40f2ceb627dd78e74e9dfde14d9bf6cdd532a29ff59", size = 2048519, upload-time = "2026-04-13T09:05:10.464Z" },
- { url = "https://files.pythonhosted.org/packages/b6/51/e0db8267a287994546925f252e329eeae4121b1e77e76353418da5a3adf0/pydantic_core-2.46.0-cp314-cp314t-win_arm64.whl", hash = "sha256:4864f5bbb7993845baf9209bae1669a8a76769296a018cb569ebda9dcb4241f5", size = 2026791, upload-time = "2026-04-13T09:04:37.724Z" },
- { url = "https://files.pythonhosted.org/packages/74/0c/106ed5cc50393d90523f09adcc50d05e42e748eb107dc06aea971137f02d/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:bc0e2fefe384152d7da85b5c2fe8ce2bf24752f68a58e3f3ea42e28a29dfdeb2", size = 2104968, upload-time = "2026-04-13T09:06:26.967Z" },
- { url = "https://files.pythonhosted.org/packages/f5/71/b494cef3165e3413ee9bbbb5a9eedc9af0ea7b88d8638beef6c2061b110e/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:a2ab0e785548be1b4362a62c4004f9217598b7ee465f1f420fc2123e2a5b5b02", size = 1940442, upload-time = "2026-04-13T09:06:29.332Z" },
- { url = "https://files.pythonhosted.org/packages/7e/3e/a4d578c8216c443e26a1124f8c1e07c0654264ce5651143d3883d85ff140/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16d45aecb18b8cba1c68eeb17c2bb2d38627ceed04c5b30b882fc9134e01f187", size = 1999672, upload-time = "2026-04-13T09:04:42.798Z" },
- { url = "https://files.pythonhosted.org/packages/cd/c1/9114560468685525a21770138382fd0cb849aaf351ff2c7b97f760d121e0/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5078f6c377b002428e984259ac327ef8902aacae6c14b7de740dd4869a491501", size = 2154533, upload-time = "2026-04-13T09:04:50.868Z" },
+sdist = { url = "https://files.pythonhosted.org/packages/2a/ef/f7abb56c49382a246fd2ce9c799691e3c3e7175ec74b14d99e798bcddb1a/pydantic_core-2.46.3.tar.gz", hash = "sha256:41c178f65b8c29807239d47e6050262eb6bf84eb695e41101e62e38df4a5bc2c", size = 471412, upload-time = "2026-04-20T14:40:56.672Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4b/cb/5b47425556ecc1f3fe18ed2a0083188aa46e1dd812b06e406475b3a5d536/pydantic_core-2.46.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b11b59b3eee90a80a36701ddb4576d9ae31f93f05cb9e277ceaa09e6bf074a67", size = 2101946, upload-time = "2026-04-20T14:40:52.581Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/4f/2fb62c2267cae99b815bbf4a7b9283812c88ca3153ef29f7707200f1d4e5/pydantic_core-2.46.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:af8653713055ea18a3abc1537fe2ebc42f5b0bbb768d1eb79fd74eb47c0ac089", size = 1951612, upload-time = "2026-04-20T14:42:42.996Z" },
+ { url = "https://files.pythonhosted.org/packages/50/6e/b7348fd30d6556d132cddd5bd79f37f96f2601fe0608afac4f5fb01ec0b3/pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75a519dab6d63c514f3a81053e5266c549679e4aa88f6ec57f2b7b854aceb1b0", size = 1977027, upload-time = "2026-04-20T14:42:02.001Z" },
+ { url = "https://files.pythonhosted.org/packages/82/11/31d60ee2b45540d3fb0b29302a393dbc01cd771c473f5b5147bcd353e593/pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6cd87cb1575b1ad05ba98894c5b5c96411ef678fa2f6ed2576607095b8d9789", size = 2063008, upload-time = "2026-04-20T14:44:17.952Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/db/3a9d1957181b59258f44a2300ab0f0be9d1e12d662a4f57bb31250455c52/pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f80a55484b8d843c8ada81ebf70a682f3f00a3d40e378c06cf17ecb44d280d7d", size = 2233082, upload-time = "2026-04-20T14:40:57.934Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/e1/3277c38792aeb5cfb18c2f0c5785a221d9ff4e149abbe1184d53d5f72273/pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3861f1731b90c50a3266316b9044f5c9b405eecb8e299b0a7120596334e4fe9c", size = 2304615, upload-time = "2026-04-20T14:42:12.584Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/d5/e3d9717c9eba10855325650afd2a9cba8e607321697f18953af9d562da2f/pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb528e295ed31570ac3dcc9bfdd6e0150bc11ce6168ac87a8082055cf1a67395", size = 2094380, upload-time = "2026-04-20T14:43:05.522Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/20/abac35dedcbfd66c6f0b03e4e3564511771d6c9b7ede10a362d03e110d9b/pydantic_core-2.46.3-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:367508faa4973b992b271ba1494acaab36eb7e8739d1e47be5035fb1ea225396", size = 2135429, upload-time = "2026-04-20T14:41:55.549Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/a5/41bfd1df69afad71b5cf0535055bccc73022715ad362edbc124bc1e021d7/pydantic_core-2.46.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ad3c826fe523e4becf4fe39baa44286cff85ef137c729a2c5e269afbfd0905d", size = 2174582, upload-time = "2026-04-20T14:41:45.96Z" },
+ { url = "https://files.pythonhosted.org/packages/79/65/38d86ea056b29b2b10734eb23329b7a7672ca604df4f2b6e9c02d4ee22fe/pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ec638c5d194ef8af27db69f16c954a09797c0dc25015ad6123eb2c73a4d271ca", size = 2187533, upload-time = "2026-04-20T14:40:55.367Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/55/a1129141678a2026badc539ad1dee0a71d06f54c2f06a4bd68c030ac781b/pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:28ed528c45446062ee66edb1d33df5d88828ae167de76e773a3c7f64bd14e976", size = 2332985, upload-time = "2026-04-20T14:44:13.05Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/60/cb26f4077719f709e54819f4e8e1d43f4091f94e285eb6bd21e1190a7b7c/pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aed19d0c783886d5bd86d80ae5030006b45e28464218747dcf83dabfdd092c7b", size = 2373670, upload-time = "2026-04-20T14:41:53.421Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/7e/c3f21882bdf1d8d086876f81b5e296206c69c6082551d776895de7801fa0/pydantic_core-2.46.3-cp312-cp312-win32.whl", hash = "sha256:06d5d8820cbbdb4147578c1fe7ffcd5b83f34508cb9f9ab76e807be7db6ff0a4", size = 1966722, upload-time = "2026-04-20T14:44:30.588Z" },
+ { url = "https://files.pythonhosted.org/packages/57/be/6b5e757b859013ebfbd7adba02f23b428f37c86dcbf78b5bb0b4ffd36e99/pydantic_core-2.46.3-cp312-cp312-win_amd64.whl", hash = "sha256:c3212fda0ee959c1dd04c60b601ec31097aaa893573a3a1abd0a47bcac2968c1", size = 2072970, upload-time = "2026-04-20T14:42:54.248Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/f8/a989b21cc75e9a32d24192ef700eea606521221a89faa40c919ce884f2b1/pydantic_core-2.46.3-cp312-cp312-win_arm64.whl", hash = "sha256:f1f8338dd7a7f31761f1f1a3c47503a9a3b34eea3c8b01fa6ee96408affb5e72", size = 2035963, upload-time = "2026-04-20T14:44:20.4Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/3c/9b5e8eb9821936d065439c3b0fb1490ffa64163bfe7e1595985a47896073/pydantic_core-2.46.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:12bc98de041458b80c86c56b24df1d23832f3e166cbaff011f25d187f5c62c37", size = 2102109, upload-time = "2026-04-20T14:41:24.219Z" },
+ { url = "https://files.pythonhosted.org/packages/91/97/1c41d1f5a19f241d8069f1e249853bcce378cdb76eec8ab636d7bc426280/pydantic_core-2.46.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:85348b8f89d2c3508b65b16c3c33a4da22b8215138d8b996912bb1532868885f", size = 1951820, upload-time = "2026-04-20T14:42:14.236Z" },
+ { url = "https://files.pythonhosted.org/packages/30/b4/d03a7ae14571bc2b6b3c7b122441154720619afe9a336fa3a95434df5e2f/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1105677a6df914b1fb71a81b96c8cce7726857e1717d86001f29be06a25ee6f8", size = 1977785, upload-time = "2026-04-20T14:42:31.648Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/0c/4086f808834b59e3c8f1aa26df8f4b6d998cdcf354a143d18ef41529d1fe/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:87082cd65669a33adeba5470769e9704c7cf026cc30afb9cc77fd865578ebaad", size = 2062761, upload-time = "2026-04-20T14:40:37.093Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/71/a649be5a5064c2df0db06e0a512c2281134ed2fcc981f52a657936a7527c/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60e5f66e12c4f5212d08522963380eaaeac5ebd795826cfd19b2dfb0c7a52b9c", size = 2232989, upload-time = "2026-04-20T14:42:59.254Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/84/7756e75763e810b3a710f4724441d1ecc5883b94aacb07ca71c5fb5cfb69/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6cdf19bf84128d5e7c37e8a73a0c5c10d51103a650ac585d42dd6ae233f2b7f", size = 2303975, upload-time = "2026-04-20T14:41:32.287Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/35/68a762e0c1e31f35fa0dac733cbd9f5b118042853698de9509c8e5bf128b/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:031bb17f4885a43773c8c763089499f242aee2ea85cf17154168775dccdecf35", size = 2095325, upload-time = "2026-04-20T14:42:47.685Z" },
+ { url = "https://files.pythonhosted.org/packages/77/bf/1bf8c9a8e91836c926eae5e3e51dce009bf495a60ca56060689d3df3f340/pydantic_core-2.46.3-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:bcf2a8b2982a6673693eae7348ef3d8cf3979c1d63b54fca7c397a635cc68687", size = 2133368, upload-time = "2026-04-20T14:41:22.766Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/50/87d818d6bab915984995157ceb2380f5aac4e563dddbed6b56f0ed057aba/pydantic_core-2.46.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28e8cf2f52d72ced402a137145923a762cbb5081e48b34312f7a0c8f55928ec3", size = 2173908, upload-time = "2026-04-20T14:42:52.044Z" },
+ { url = "https://files.pythonhosted.org/packages/91/88/a311fb306d0bd6185db41fa14ae888fb81d0baf648a761ae760d30819d33/pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:17eaface65d9fc5abb940003020309c1bf7a211f5f608d7870297c367e6f9022", size = 2186422, upload-time = "2026-04-20T14:43:29.55Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/79/28fd0d81508525ab2054fef7c77a638c8b5b0afcbbaeee493cf7c3fef7e1/pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:93fd339f23408a07e98950a89644f92c54d8729719a40b30c0a30bb9ebc55d23", size = 2332709, upload-time = "2026-04-20T14:42:16.134Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/21/795bf5fe5c0f379308b8ef19c50dedab2e7711dbc8d0c2acf08f1c7daa05/pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:23cbdb3aaa74dfe0837975dbf69b469753bbde8eacace524519ffdb6b6e89eb7", size = 2372428, upload-time = "2026-04-20T14:41:10.974Z" },
+ { url = "https://files.pythonhosted.org/packages/45/b3/ed14c659cbe7605e3ef063077680a64680aec81eb1a04763a05190d49b7f/pydantic_core-2.46.3-cp313-cp313-win32.whl", hash = "sha256:610eda2e3838f401105e6326ca304f5da1e15393ae25dacae5c5c63f2c275b13", size = 1965601, upload-time = "2026-04-20T14:41:42.128Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/bb/adb70d9a762ddd002d723fbf1bd492244d37da41e3af7b74ad212609027e/pydantic_core-2.46.3-cp313-cp313-win_amd64.whl", hash = "sha256:68cc7866ed863db34351294187f9b729964c371ba33e31c26f478471c52e1ed0", size = 2071517, upload-time = "2026-04-20T14:43:36.096Z" },
+ { url = "https://files.pythonhosted.org/packages/52/eb/66faefabebfe68bd7788339c9c9127231e680b11906368c67ce112fdb47f/pydantic_core-2.46.3-cp313-cp313-win_arm64.whl", hash = "sha256:f64b5537ac62b231572879cd08ec05600308636a5d63bcbdb15063a466977bec", size = 2035802, upload-time = "2026-04-20T14:43:38.507Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/db/a7bcb4940183fda36022cd18ba8dd12f2dff40740ec7b58ce7457befa416/pydantic_core-2.46.3-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:afa3aa644f74e290cdede48a7b0bee37d1c35e71b05105f6b340d484af536d9b", size = 2097614, upload-time = "2026-04-20T14:44:38.374Z" },
+ { url = "https://files.pythonhosted.org/packages/24/35/e4066358a22e3e99519db370494c7528f5a2aa1367370e80e27e20283543/pydantic_core-2.46.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ced3310e51aa425f7f77da8bbbb5212616655bedbe82c70944320bc1dbe5e018", size = 1951896, upload-time = "2026-04-20T14:40:53.996Z" },
+ { url = "https://files.pythonhosted.org/packages/87/92/37cf4049d1636996e4b888c05a501f40a43ff218983a551d57f9d5e14f0d/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e29908922ce9da1a30b4da490bd1d3d82c01dcfdf864d2a74aacee674d0bfa34", size = 1979314, upload-time = "2026-04-20T14:41:49.446Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/36/9ff4d676dfbdfb2d591cf43f3d90ded01e15b1404fd101180ed2d62a2fd3/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0c9ff69140423eea8ed2d5477df3ba037f671f5e897d206d921bc9fdc39613e7", size = 2056133, upload-time = "2026-04-20T14:42:23.574Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/f0/405b442a4d7ba855b06eec8b2bf9c617d43b8432d099dfdc7bf999293495/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b675ab0a0d5b1c8fdb81195dc5bcefea3f3c240871cdd7ff9a2de8aa50772eb2", size = 2228726, upload-time = "2026-04-20T14:44:22.816Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/f8/65cd92dd5a0bd89ba277a98ecbfaf6fc36bbd3300973c7a4b826d6ab1391/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0087084960f209a9a4af50ecd1fb063d9ad3658c07bb81a7a53f452dacbfb2ba", size = 2301214, upload-time = "2026-04-20T14:44:48.792Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/86/ef96a4c6e79e7a2d0410826a68fbc0eccc0fd44aa733be199d5fcac3bb87/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed42e6cc8e1b0e2b9b96e2276bad70ae625d10d6d524aed0c93de974ae029f9f", size = 2099927, upload-time = "2026-04-20T14:41:40.196Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/53/269caf30e0096e0a8a8f929d1982a27b3879872cca2d917d17c2f9fdf4fe/pydantic_core-2.46.3-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:f1771ce258afb3e4201e67d154edbbae712a76a6081079fe247c2f53c6322c22", size = 2128789, upload-time = "2026-04-20T14:41:15.868Z" },
+ { url = "https://files.pythonhosted.org/packages/00/b0/1a6d9b6a587e118482910c244a1c5acf4d192604174132efd12bf0ac486f/pydantic_core-2.46.3-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a7610b6a5242a6c736d8ad47fd5fff87fcfe8f833b281b1c409c3d6835d9227f", size = 2173815, upload-time = "2026-04-20T14:44:25.152Z" },
+ { url = "https://files.pythonhosted.org/packages/87/56/e7e00d4041a7e62b5a40815590114db3b535bf3ca0bf4dca9f16cef25246/pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:ff5e7783bcc5476e1db448bf268f11cb257b1c276d3e89f00b5727be86dd0127", size = 2181608, upload-time = "2026-04-20T14:41:28.933Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/22/4bd23c3d41f7c185d60808a1de83c76cf5aeabf792f6c636a55c3b1ec7f9/pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:9d2e32edcc143bc01e95300671915d9ca052d4f745aa0a49c48d4803f8a85f2c", size = 2326968, upload-time = "2026-04-20T14:42:03.962Z" },
+ { url = "https://files.pythonhosted.org/packages/24/ac/66cd45129e3915e5ade3b292cb3bc7fd537f58f8f8dbdaba6170f7cabb74/pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6e42d83d1c6b87fa56b521479cff237e626a292f3b31b6345c15a99121b454c1", size = 2369842, upload-time = "2026-04-20T14:41:35.52Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/51/dd4248abb84113615473aa20d5545b7c4cd73c8644003b5259686f93996c/pydantic_core-2.46.3-cp314-cp314-win32.whl", hash = "sha256:07bc6d2a28c3adb4f7c6ae46aa4f2d2929af127f587ed44057af50bf1ce0f505", size = 1959661, upload-time = "2026-04-20T14:41:00.042Z" },
+ { url = "https://files.pythonhosted.org/packages/20/eb/59980e5f1ae54a3b86372bd9f0fa373ea2d402e8cdcd3459334430f91e91/pydantic_core-2.46.3-cp314-cp314-win_amd64.whl", hash = "sha256:8940562319bc621da30714617e6a7eaa6b98c84e8c685bcdc02d7ed5e7c7c44e", size = 2071686, upload-time = "2026-04-20T14:43:16.471Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/db/1cf77e5247047dfee34bc01fa9bca134854f528c8eb053e144298893d370/pydantic_core-2.46.3-cp314-cp314-win_arm64.whl", hash = "sha256:5dcbbcf4d22210ced8f837c96db941bdb078f419543472aca5d9a0bb7cddc7df", size = 2026907, upload-time = "2026-04-20T14:43:31.732Z" },
+ { url = "https://files.pythonhosted.org/packages/57/c0/b3df9f6a543276eadba0a48487b082ca1f201745329d97dbfa287034a230/pydantic_core-2.46.3-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:d0fe3dce1e836e418f912c1ad91c73357d03e556a4d286f441bf34fed2dbeecf", size = 2095047, upload-time = "2026-04-20T14:42:37.982Z" },
+ { url = "https://files.pythonhosted.org/packages/66/57/886a938073b97556c168fd99e1a7305bb363cd30a6d2c76086bf0587b32a/pydantic_core-2.46.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9ce92e58abc722dac1bf835a6798a60b294e48eb0e625ec9fd994b932ac5feee", size = 1934329, upload-time = "2026-04-20T14:43:49.655Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/7c/b42eaa5c34b13b07ecb51da21761297a9b8eb43044c864a035999998f328/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03e6467f0f5ab796a486146d1b887b2dc5e5f9b3288898c1b1c3ad974e53e4a", size = 1974847, upload-time = "2026-04-20T14:42:10.737Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/9b/92b42db6543e7de4f99ae977101a2967b63122d4b6cf7773812da2d7d5b5/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2798b6ba041b9d70acfb9071a2ea13c8456dd1e6a5555798e41ba7b0790e329c", size = 2041742, upload-time = "2026-04-20T14:40:44.262Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/19/46fbe1efabb5aa2834b43b9454e70f9a83ad9c338c1291e48bdc4fecf167/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9be3e221bdc6d69abf294dcf7aff6af19c31a5cdcc8f0aa3b14be29df4bd03b1", size = 2236235, upload-time = "2026-04-20T14:41:27.307Z" },
+ { url = "https://files.pythonhosted.org/packages/77/da/b3f95bc009ad60ec53120f5d16c6faa8cabdbe8a20d83849a1f2b8728148/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f13936129ce841f2a5ddf6f126fea3c43cd128807b5a59588c37cf10178c2e64", size = 2282633, upload-time = "2026-04-20T14:44:33.271Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/6e/401336117722e28f32fb8220df676769d28ebdf08f2f4469646d404c43a3/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28b5f2ef03416facccb1c6ef744c69793175fd27e44ef15669201601cf423acb", size = 2109679, upload-time = "2026-04-20T14:44:41.065Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/53/b289f9bc8756a32fe718c46f55afaeaf8d489ee18d1a1e7be1db73f42cc4/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:830d1247d77ad23852314f069e9d7ddafeec5f684baf9d7e7065ed46a049c4e6", size = 2108342, upload-time = "2026-04-20T14:42:50.144Z" },
+ { url = "https://files.pythonhosted.org/packages/10/5b/8292fc7c1f9111f1b2b7c1b0dcf1179edcd014fc3ea4517499f50b829d71/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0793c90c1a3c74966e7975eaef3ed30ebdff3260a0f815a62a22adc17e4c01c", size = 2157208, upload-time = "2026-04-20T14:42:08.133Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/9e/f80044e9ec07580f057a89fc131f78dda7a58751ddf52bbe05eaf31db50f/pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d2d0aead851b66f5245ec0c4fb2612ef457f8bbafefdf65a2bf9d6bac6140f47", size = 2167237, upload-time = "2026-04-20T14:42:25.412Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/84/6781a1b037f3b96be9227edbd1101f6d3946746056231bf4ac48cdff1a8d/pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:2f40e4246676beb31c5ce77c38a55ca4e465c6b38d11ea1bd935420568e0b1ab", size = 2312540, upload-time = "2026-04-20T14:40:40.313Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/db/19c0839feeb728e7df03255581f198dfdf1c2aeb1e174a8420b63c5252e5/pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:cf489cf8986c543939aeee17a09c04d6ffb43bfef8ca16fcbcc5cfdcbed24dba", size = 2369556, upload-time = "2026-04-20T14:41:09.427Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/15/3228774cb7cd45f5f721ddf1b2242747f4eb834d0c491f0c02d606f09fed/pydantic_core-2.46.3-cp314-cp314t-win32.whl", hash = "sha256:ffe0883b56cfc05798bf994164d2b2ff03efe2d22022a2bb080f3b626176dd56", size = 1949756, upload-time = "2026-04-20T14:41:25.717Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/2a/c79cf53fd91e5a87e30d481809f52f9a60dd221e39de66455cf04deaad37/pydantic_core-2.46.3-cp314-cp314t-win_amd64.whl", hash = "sha256:706d9d0ce9cf4593d07270d8e9f53b161f90c57d315aeec4fb4fd7a8b10240d8", size = 2051305, upload-time = "2026-04-20T14:43:18.627Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/db/d8182a7f1d9343a032265aae186eb063fe26ca4c40f256b21e8da4498e89/pydantic_core-2.46.3-cp314-cp314t-win_arm64.whl", hash = "sha256:77706aeb41df6a76568434701e0917da10692da28cb69d5fb6919ce5fdb07374", size = 2026310, upload-time = "2026-04-20T14:41:01.778Z" },
+ { url = "https://files.pythonhosted.org/packages/34/42/f426db557e8ab2791bc7562052299944a118655496fbff99914e564c0a94/pydantic_core-2.46.3-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:b12dd51f1187c2eb489af8e20f880362db98e954b54ab792fa5d92e8bcc6b803", size = 2091877, upload-time = "2026-04-20T14:43:27.091Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/4f/86a832a9d14df58e663bfdf4627dc00d3317c2bd583c4fb23390b0f04b8e/pydantic_core-2.46.3-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f00a0961b125f1a47af7bcc17f00782e12f4cd056f83416006b30111d941dfa3", size = 1932428, upload-time = "2026-04-20T14:40:45.781Z" },
+ { url = "https://files.pythonhosted.org/packages/11/1a/fe857968954d93fb78e0d4b6df5c988c74c4aaa67181c60be7cfe327c0ca/pydantic_core-2.46.3-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57697d7c056aca4bbb680200f96563e841a6386ac1129370a0102592f4dddff5", size = 1997550, upload-time = "2026-04-20T14:44:02.425Z" },
+ { url = "https://files.pythonhosted.org/packages/17/eb/9d89ad2d9b0ba8cd65393d434471621b98912abb10fbe1df08e480ba57b5/pydantic_core-2.46.3-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd35aa21299def8db7ef4fe5c4ff862941a9a158ca7b63d61e66fe67d30416b4", size = 2137657, upload-time = "2026-04-20T14:42:45.149Z" },
]
[[package]]
@@ -1894,15 +1924,15 @@ wheels = [
[[package]]
name = "python-discovery"
-version = "1.2.2"
+version = "1.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "filelock" },
{ name = "platformdirs" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/de/ef/3bae0e537cfe91e8431efcba4434463d2c5a65f5a89edd47c6cf2f03c55f/python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb", size = 58872, upload-time = "2026-04-07T17:28:49.249Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/ae/e0/cc5a8653e9a24f6cf84768f05064aa8ed5a83dcefd5e2a043db14a1c5f44/python_discovery-1.3.0.tar.gz", hash = "sha256:d098f1e86be5d45fe4d14bf1029294aabbd332f4321179dec85e76cddce834b0", size = 63925, upload-time = "2026-05-05T14:38:39.769Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/d8/db/795879cc3ddfe338599bddea6388cc5100b088db0a4caf6e6c1af1c27e04/python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a", size = 31894, upload-time = "2026-04-07T17:28:48.09Z" },
+ { url = "https://files.pythonhosted.org/packages/30/d4/24d543ab8b8158b7f5a97113c831205f5c900c92c8762b1e7f44b7ea0405/python_discovery-1.3.0-py3-none-any.whl", hash = "sha256:441d9ced3dfce36e113beb35ca302c71c7ef06f3c0f9c227a0b9bb3bd49b9e9f", size = 33124, upload-time = "2026-05-05T14:38:38.539Z" },
]
[[package]]
@@ -2301,6 +2331,7 @@ dependencies = [
{ name = "python-jsonpath" },
{ name = "rich" },
{ name = "seedcase-soil" },
+ { name = "textual" },
]
[package.dev-dependencies]
@@ -2330,6 +2361,7 @@ requires-dist = [
{ name = "python-jsonpath", specifier = ">=2.0.2" },
{ name = "rich", specifier = ">=14.3.3" },
{ name = "seedcase-soil", specifier = ">=0.11.0" },
+ { name = "textual", specifier = ">=8.2.5" },
]
[package.metadata.requires-dev]
@@ -2352,15 +2384,15 @@ dev = [
[[package]]
name = "seedcase-soil"
-version = "0.12.0"
+version = "0.13.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cyclopts" },
{ name = "rich" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/0c/0d/12a0eb4f8973aabe9236390f2640844a514a7369f99eea8f0a072295f1fb/seedcase_soil-0.12.0.tar.gz", hash = "sha256:8be8d78c7251acfd86d75bb248527ba8b78e04263285e0c7a9c659f999be4ebc", size = 1044701, upload-time = "2026-04-30T08:27:54.556Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/bd/4b/fbad245a6d83c6f135a33674be528b94597cd48c61d2a1260a131f7fa642/seedcase_soil-0.13.0.tar.gz", hash = "sha256:6c69b35b35f26979a0e6e950a9b9a95345128fb8d967e54fdddc940a3744a80a", size = 1044803, upload-time = "2026-05-04T08:31:23.583Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/3c/5c/619b9b60ce1c41e8dd38c4030fbeeedcab38cec48cad9c6cf8037204261b/seedcase_soil-0.12.0-py3-none-any.whl", hash = "sha256:fae6691931779ed52a8c9f791b99746ba40bc94bec1cc7efbaa988c2239a6773", size = 17801, upload-time = "2026-04-30T08:27:53.344Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/ca/d131b714cfa764c4134e7ea8438b9164da6e91c5d662244ed5ae58ecf213/seedcase_soil-0.13.0-py3-none-any.whl", hash = "sha256:a4ac906a228389b7e99a80ea97db556762e92c49d7bad7d05dcf21655dfb9ec0", size = 17803, upload-time = "2026-05-04T08:31:22.704Z" },
]
[[package]]
@@ -2468,6 +2500,23 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" },
]
+[[package]]
+name = "textual"
+version = "8.2.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown-it-py", extra = ["linkify"] },
+ { name = "mdit-py-plugins" },
+ { name = "platformdirs" },
+ { name = "pygments" },
+ { name = "rich" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/62/1e/1eedc5bac184d00aaa5f9a99095f7e266af3ec46fa926c1051be5d358da1/textual-8.2.5.tar.gz", hash = "sha256:6c894e65a879dadb4f6cf46ddcfedb0173ff7e0cb1fe605ff7b357a597bdbc90", size = 1851596, upload-time = "2026-04-30T08:02:58.956Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/cd/01/c4555f9c8a692ff83d84930150540f743ce94c89234f9e9a15ff4baba3a8/textual-8.2.5-py3-none-any.whl", hash = "sha256:247d2aa2faf222749c321f88a736247f37ee2c023604079c7490bfacddfcd4b2", size = 727050, upload-time = "2026-04-30T08:03:01.421Z" },
+]
+
[[package]]
name = "tinycss2"
version = "1.4.0"
@@ -2508,11 +2557,11 @@ wheels = [
[[package]]
name = "traitlets"
-version = "5.14.3"
+version = "5.15.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/1b/22/40f55b26baeab80c2d7b3f1db0682f8954e4617fee7d90ce634022ef05c6/traitlets-5.15.0.tar.gz", hash = "sha256:4fead733f81cf1c4c938e06f8ca4633896833c9d89eff878159457f4d4392971", size = 163197, upload-time = "2026-05-06T08:05:58.016Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" },
+ { url = "https://files.pythonhosted.org/packages/da/98/a9937a969d018a23badfea0b381f66783649d48e0ea6c41923265c3cbeb3/traitlets-5.15.0-py3-none-any.whl", hash = "sha256:fb36a18867a6803deab09f3c5e0fa81bb7b26a5c9e82501c9933f759166eff40", size = 85877, upload-time = "2026-05-06T08:05:55.853Z" },
]
[[package]]
@@ -2559,28 +2608,37 @@ wheels = [
[[package]]
name = "typos"
-version = "1.45.1"
+version = "1.46.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/69/c2/0cd9200d030f8e3c71ac30bc0ee86736d9d7d0a9b02c1b050f40138c19c0/typos-1.45.1.tar.gz", hash = "sha256:a1ac7ab02e74d4c4a2f8525b1529e1ce6261051df3229701836175fb91bb0583", size = 1820481, upload-time = "2026-04-13T15:03:01.549Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/24/87/8769161e958d715ed00b6cc110452c1a3921009a239944b66279acb63898/typos-1.46.0.tar.gz", hash = "sha256:afcc399b3ef9aedc0b037de935ebdef60654a3cc616bc160aac14de7fb4d5592", size = 1822140, upload-time = "2026-04-30T16:20:18.779Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/6d/49/e0e0614d635f4847de1c3464ee068be579dfe14a81dd9051fa6fc3653305/typos-1.45.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f3cd3d7e7e35f971e04974c7b34563dc1efb101841be3a39fec36c51f3d6ca2d", size = 3480310, upload-time = "2026-04-13T15:02:43.19Z" },
- { url = "https://files.pythonhosted.org/packages/5a/f5/b0fc73ab073eb844e888cf47c8fc1fab3b59eaf8becbb901b58e46ded7e2/typos-1.45.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:be6f26c580915e63df107f88bc766f131efe5f7d01d41c7bad83e6f9e5fe42be", size = 3381483, upload-time = "2026-04-13T15:02:45.415Z" },
- { url = "https://files.pythonhosted.org/packages/8c/e1/1b1c8ff64d61143206e700fe4ae6732749053e44d10a33d9da1eceecbadc/typos-1.45.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd6a6ccbb1fc4fb8f0d9fee0201642d7a7560bd1661ebbefb9eac2da1ae4a5c", size = 8247207, upload-time = "2026-04-13T15:02:47.658Z" },
- { url = "https://files.pythonhosted.org/packages/8b/6b/79ccb79cab37c04a10759709042476b8534f3f2f6a89180f67821f396482/typos-1.45.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d33c7750a29524dff020a17f356ed079227f36f43ec57f193e9681606a35749b", size = 7361395, upload-time = "2026-04-13T15:02:49.564Z" },
- { url = "https://files.pythonhosted.org/packages/e0/4c/b97fbabf0413edda31e1e830befb267f934e990a417a11e1f6f6b2e1235e/typos-1.45.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:745b0584eeead4593858671113fceed3c28b8ca67bdc7a517120127aa509c6a6", size = 7757620, upload-time = "2026-04-13T15:02:51.664Z" },
- { url = "https://files.pythonhosted.org/packages/69/f8/1b757c9b83750100b6c2f09fb6d84d4521ca158c74d9a437495329fca58e/typos-1.45.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e962d414fb92ad31dc4c930fc5d07ac9e4b55fdd4f42688468040fc5649d92da", size = 7111197, upload-time = "2026-04-13T15:02:53.831Z" },
- { url = "https://files.pythonhosted.org/packages/63/76/65c1d4248d9cb1b12fb4bad81b829bd5cc3da7564ffe0a794fac3126f1f4/typos-1.45.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f39afdfcc2d159705f3ffb11162e13e8affd994d07836738c8d2a592194604ab", size = 8180810, upload-time = "2026-04-13T15:02:55.901Z" },
- { url = "https://files.pythonhosted.org/packages/a2/b5/65b3e0509c3d698faf1a965a9afcfff3ebff50c850e789891945735f8066/typos-1.45.1-py3-none-win32.whl", hash = "sha256:212fdbb7b90d40522fe77efb69c15f7063c146812df01d5605e5d7816a3f37d3", size = 3135956, upload-time = "2026-04-13T15:02:57.934Z" },
- { url = "https://files.pythonhosted.org/packages/ea/50/a9ec45215912d8e8600ba903b09382144071b450ad2f7adebc63e7699b99/typos-1.45.1-py3-none-win_amd64.whl", hash = "sha256:67a56bd1f06184f3761883f4f75dd3cc196f939180de595d0980164d4a19d363", size = 3318717, upload-time = "2026-04-13T15:02:59.829Z" },
+ { url = "https://files.pythonhosted.org/packages/85/61/241cc5a28e7daf78e9f00345776a06d34b43a7901ec127875c18d5e864c4/typos-1.46.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:21709d52d62c32010151edb1ae4b2c9278f93f6d3a57cd6ab1a5ff3425de1e1c", size = 3473633, upload-time = "2026-04-30T16:20:01.865Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/a8/5c465e2f09fb2aead5af646bb1027d9c86eb2def7fe110a8e2a42a986562/typos-1.46.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7d9811d112420cb866d2ed2b23a7eb4c97ea5fecfa81f9bb6ab5b57e59bd70b6", size = 3378427, upload-time = "2026-04-30T16:20:04.337Z" },
+ { url = "https://files.pythonhosted.org/packages/49/ec/38b5b2edbb88b5a610bb7ba35b991558ed7df3584091f48546d2fe26dcf6/typos-1.46.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d612b6ace64f2219da5a18c9ac008042b37079a5fbaabcd6a20f060686205ac", size = 8234098, upload-time = "2026-04-30T16:20:05.981Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/63/ec68ddb454e56dcecc8c7f57efab4a1d527881fd5121a1c926cd914abc39/typos-1.46.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3b0859517d73d13537a3f4a3662ceadb988e6bb5bdb8ba53bc6de86302d5154", size = 7325493, upload-time = "2026-04-30T16:20:08.508Z" },
+ { url = "https://files.pythonhosted.org/packages/36/4e/a6eb51e56dd80468086543aa84f554cffb99942d31b49f452e6999d377dd/typos-1.46.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:696b94e7d73cc74ee47d05d8aab1f1a3d50ee427b7e2a30337430eaa613b8f9c", size = 7741777, upload-time = "2026-04-30T16:20:10.297Z" },
+ { url = "https://files.pythonhosted.org/packages/89/31/7cf4a2b59797284feb81933ef6c793db6e5a9150a5ca76eb7cfd39a5657f/typos-1.46.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7b9b32bca025049d68f6c571baccb2dbaded8e32299b91bd184ef1b0ec2755ae", size = 7093146, upload-time = "2026-04-30T16:20:11.96Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/3a/cab42c900888a49049b8bb33acea64f8b0c76cbb1a6e69a2771a6f11feae/typos-1.46.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7284909bd27e487de31c5eb3b53817df9e705e14b96f226315dca8a8c653363f", size = 8128222, upload-time = "2026-04-30T16:20:13.587Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/e3/f0e2a727af4b1ac6f231d454f7ba85565039c930c9a4197c6345326ac1f9/typos-1.46.0-py3-none-win32.whl", hash = "sha256:563c54404f253450f195e2ec1cd4ca5e0d659e78c5d23b4062cea5cf2150fc9f", size = 3135787, upload-time = "2026-04-30T16:20:15.285Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/04/cf00d7df41e910b7a5bd7d83ac2fa0d771aa2ca3a2fde17388725ee1c20f/typos-1.46.0-py3-none-win_amd64.whl", hash = "sha256:595e614b9b9967247a68c2cb3a4712ced7a5cc434f2cabcf945afbebaccf885b", size = 3310337, upload-time = "2026-04-30T16:20:17.131Z" },
]
[[package]]
name = "tzdata"
-version = "2026.1"
+version = "2026.2"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/19/f5/cd531b2d15a671a40c0f66cf06bc3570a12cd56eef98960068ebbad1bf5a/tzdata-2026.1.tar.gz", hash = "sha256:67658a1903c75917309e753fdc349ac0efd8c27db7a0cb406a25be4840f87f98", size = 197639, upload-time = "2026-04-03T11:25:22.002Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/b0/70/d460bd685a170790ec89317e9bd33047988e4bce507b831f5db771e142de/tzdata-2026.1-py2.py3-none-any.whl", hash = "sha256:4b1d2be7ac37ceafd7327b961aa3a54e467efbdb563a23655fbfe0d39cfc42a9", size = 348952, upload-time = "2026-04-03T11:25:20.313Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" },
+]
+
+[[package]]
+name = "uc-micro-py"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/78/67/9a363818028526e2d4579334460df777115bdec1bb77c08f9db88f6389f2/uc_micro_py-2.0.0.tar.gz", hash = "sha256:c53691e495c8db60e16ffc4861a35469b0ba0821fe409a8a7a0a71864d33a811", size = 6611, upload-time = "2026-03-01T06:31:27.526Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/61/73/d21edf5b204d1467e06500080a50f79d49ef2b997c79123a536d4a17d97c/uc_micro_py-2.0.0-py3-none-any.whl", hash = "sha256:3603a3859af53e5a39bc7677713c78ea6589ff188d70f4fee165db88e22b242c", size = 6383, upload-time = "2026-03-01T06:31:26.257Z" },
]
[[package]]
@@ -2603,7 +2661,7 @@ wheels = [
[[package]]
name = "virtualenv"
-version = "21.2.3"
+version = "21.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "distlib" },
@@ -2611,9 +2669,9 @@ dependencies = [
{ name = "platformdirs" },
{ name = "python-discovery" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/60/8c/bdd9f89f89e4a787ac61bb2da4d884bc45e0c287ec694dfa3170dddd5cfe/virtualenv-21.2.3.tar.gz", hash = "sha256:9bb6d1414ab55ca624371e30c7719c32f183ef44da544ef8aa44a456de7ac191", size = 5844776, upload-time = "2026-04-14T01:10:36.692Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/ec/0d/915c02c94d207b85580eb09bffab54438a709e7288524094fe781da526c2/virtualenv-21.3.1.tar.gz", hash = "sha256:c2305bc1fddeec40699b8370d13f8d431b0701f00ce895061ce493aeded4426b", size = 7613791, upload-time = "2026-05-05T01:34:31.402Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/95/19/bc7c4e05f42532863cf2ae7e7e847beab25835934e0410160b47eeff1e35/virtualenv-21.2.3-py3-none-any.whl", hash = "sha256:486652347ea8526d91e9807c0274583cb7ba31dd4942ff10fb5621402f0fe0d8", size = 5828329, upload-time = "2026-04-14T01:10:34.809Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/4f/f71e641e504111a5a74e3a20bc52d01bd86788b22699dd3fee1c63253cf6/virtualenv-21.3.1-py3-none-any.whl", hash = "sha256:d1a71cf58f2f9228fff23a1f6ec15d39785c6b32e03658d104974247145edd35", size = 7594539, upload-time = "2026-05-05T01:34:28.98Z" },
]
[[package]]
@@ -2651,11 +2709,11 @@ wheels = [
[[package]]
name = "wcwidth"
-version = "0.6.0"
+version = "0.7.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/35/a2/8e3becb46433538a38726c948d3399905a4c7cabd0df578ede5dc51f0ec2/wcwidth-0.6.0.tar.gz", hash = "sha256:cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159", size = 159684, upload-time = "2026-02-06T19:19:40.919Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/2c/ee/afaf0f85a9a18fe47a67f1e4422ed6cf1fe642f0ae0a2f81166231303c52/wcwidth-0.7.0.tar.gz", hash = "sha256:90e3a7ea092341c44b99562e75d09e4d5160fe7a3974c6fb842a101a95e7eed0", size = 182132, upload-time = "2026-05-02T16:04:12.653Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad", size = 94189, upload-time = "2026-02-06T19:19:39.646Z" },
+ { url = "https://files.pythonhosted.org/packages/41/52/e465037f5375f43533d1a80b6923955201596a99142ed524d77b571a1418/wcwidth-0.7.0-py3-none-any.whl", hash = "sha256:5d69154c429a82910e241c738cd0e2976fac8a2dd47a1a805f4afed1c0f136f2", size = 110825, upload-time = "2026-05-02T16:04:11.033Z" },
]
[[package]]