diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index ff4f8d4..0dc5c8d 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -13,9 +13,6 @@ concurrency: permissions: contents: read -env: - NO_MKDOCS_2_WARNING: "1" - jobs: build: name: Build docs @@ -23,13 +20,11 @@ jobs: steps: - uses: actions/checkout@v7 - uses: astral-sh/setup-uv@v9.0.0 - with: - enable-cache: true - uses: actions/setup-python@v7 with: python-version: "3.14" - - name: Build MkDocs site - run: uv run --group docs mkdocs build --strict + - name: Build documentation site + run: uv run --frozen --group docs zensical build --strict --clean - name: Upload Pages artifact if: github.event_name == 'push' && github.ref == 'refs/heads/master' uses: actions/upload-pages-artifact@v5 diff --git a/Makefile b/Makefile index fbdb5a3..f995fdf 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ lint: uv run mypy py_clickhouse_migrator/ docs: - NO_MKDOCS_2_WARNING=1 uv run --group docs mkdocs build --strict + uv run --frozen --group docs zensical build --strict --clean docs-serve: - NO_MKDOCS_2_WARNING=1 uv run --group docs mkdocs serve + uv run --frozen --group docs zensical serve diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index de1b57c..0000000 --- a/docs/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# PyClickHouseMigrator documentation - -PyClickHouseMigrator is a SQL-first ClickHouse migration runner for teams that want migration files in Git and a simple, reliable CLI in CI/CD. - -Start with the root [README](../README.md) if you are new to the project. - -## Guides - -- [Migration format](migration-format.md) — `.sql` file structure, `-- @stmt` blocks, examples, parser rules. -- [Baseline existing databases](baseline.md) — how to adopt a database that already has schema objects. -- [Cluster mode](cluster-mode.md) — service tables, replicated engines, and `ON CLUSTER` boundaries. -- [CI/CD usage](ci-cd.md) — GitHub Actions, Kubernetes Job, exit codes, deployment recommendations. -- [Docker usage](docker.md) — running the migrator in containers. -- [Python API](python-api.md) — using the migrator from Python code. -- [Troubleshooting](troubleshooting.md) — common errors and recovery steps. -- [Known limitations](known-limitations.md) — what the tool intentionally does and does not guarantee. -- [2.0 release notes](release-2.0.md) — SQL-first release notes and breaking changes. - -## Examples - -- [Basic migration](examples/basic-migration.sql) -- [Cluster migration](examples/cluster-migration.sql) -- [GitHub Actions workflow](examples/github-actions.yml) -- [Kubernetes Job](examples/kubernetes-job.yml) diff --git a/docs/assets/hero-mascot.webp b/docs/assets/hero-mascot.webp new file mode 100644 index 0000000..55a2b4f Binary files /dev/null and b/docs/assets/hero-mascot.webp differ diff --git a/docs/assets/icons/hash.svg b/docs/assets/icons/hash.svg new file mode 100644 index 0000000..30a1e20 --- /dev/null +++ b/docs/assets/icons/hash.svg @@ -0,0 +1 @@ + diff --git a/docs/assets/icons/list-plus.svg b/docs/assets/icons/list-plus.svg new file mode 100644 index 0000000..14587cc --- /dev/null +++ b/docs/assets/icons/list-plus.svg @@ -0,0 +1 @@ + diff --git a/docs/assets/icons/list-start.svg b/docs/assets/icons/list-start.svg new file mode 100644 index 0000000..1bcc100 --- /dev/null +++ b/docs/assets/icons/list-start.svg @@ -0,0 +1 @@ + diff --git a/docs/assets/icons/list-tree.svg b/docs/assets/icons/list-tree.svg new file mode 100644 index 0000000..362394d --- /dev/null +++ b/docs/assets/icons/list-tree.svg @@ -0,0 +1 @@ + diff --git a/docs/assets/icons/lock-keyhole.svg b/docs/assets/icons/lock-keyhole.svg new file mode 100644 index 0000000..1bb51e0 --- /dev/null +++ b/docs/assets/icons/lock-keyhole.svg @@ -0,0 +1 @@ + diff --git a/docs/assets/icons/square-terminal.svg b/docs/assets/icons/square-terminal.svg new file mode 100644 index 0000000..f1e0e2c --- /dev/null +++ b/docs/assets/icons/square-terminal.svg @@ -0,0 +1 @@ + diff --git a/docs/index.md b/docs/index.md index 7d8defc..6bfcfdb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,51 +1,44 @@ -# PyClickHouseMigrator +--- +title: PyClickHouseMigrator +description: SQL-first ClickHouse migrations for Python teams. +hide: + - navigation + - toc +--- -PyClickHouseMigrator is a SQL-first ClickHouse migration runner for teams that keep schema changes in Git and run them through a small, predictable CLI. +
-It stores migration state inside ClickHouse, validates checksums, supports rollback SQL, handles advisory locking, and works with single-node or cluster deployments. +
+
+

Python CLI for ClickHouse

+

Plain SQL.Auditable migrations.

+

Version schema changes in Git, validate them before execution, and run them from the CLI or CI.

+ +
-## Install +
+ PyClickHouseMigrator mascot carrying ClickHouse columns +
pip install py-clickhouse-migrator
+
+
-```sh -pip install py-clickhouse-migrator -``` - -With `uv`: - -```sh -uv add py-clickhouse-migrator -``` - -The CLI command is: - -```sh -migrator --help -``` - -## Quick start - -Set the ClickHouse connection URL. The database in the URL must already exist. - -```sh -export CLICKHOUSE_MIGRATE_URL=clickhouse://default@localhost:9000/mydb -``` - -Create a migrations directory and a first migration: - -```sh -migrator init -migrator new create_users_table -``` - -Edit the generated file in `./db/migrations`: +
+
+

Every query stays explicit.

+

Each -- @stmt block is sent to ClickHouse as one query. The same file carries the up and down SQL.

+ Format guide +
+
```sql -- migrator:up -- @stmt -CREATE TABLE IF NOT EXISTS users +CREATE TABLE IF NOT EXISTS events ( id UInt64, - name String, created_at DateTime DEFAULT now() ) ENGINE = MergeTree @@ -53,48 +46,257 @@ ORDER BY id -- migrator:down -- @stmt -DROP TABLE IF EXISTS users +DROP TABLE IF EXISTS events ``` +
+
-Preview what will run: +
+
+

A focused migration workflow

+

No ORM, schema diff, or framework. You write the SQL. The migrator handles ordering, checks, state, and advisory locking.

+
-```sh -migrator up --dry-run -``` +
+
+

Plain SQL

+

Keep migrations in versioned files. Every statement boundary is explicit and reviewable in Git.

+ 20260801120000_create_events.sql +
+
+

Integrity checks

+

Detect edited or missing migrations that the tool previously applied.

+
+
+

Rollback you control

+

Write the down SQL yourself. The stored version is used for rollback.

+
+
+

Preflight validation

+

EXPLAIN AST runs before up and rollback by default.

+
+
+

Deployment locking

+

Reduce common CI races with a TTL-based advisory lock.

+
+
+

Cluster-aware state

+

Replicate service tables while leaving migration SQL unchanged.

+
+
+
-Apply pending migrations: +
+
+

Inside migrator up

+

By default, an apply run follows this path from connection to recorded state. Select a step to inspect it.

+
-```sh -migrator up -``` +
    +
  1. + +
  2. +
  3. + +
  4. +
  5. + +
  6. +
  7. + +
  8. +
  9. + +
  10. +
  11. + +
  12. +
-Check status: +
+ -```sh -migrator show -``` + -Rollback the last applied migration: +
+
+

Compare stored checksums

+

Compare stored SHA-256 values with the current up and down blocks. A mismatch or missing file stops the run by default.

+
+
+
$ migrator up
+
Error: Checksum mismatch for applied migrations:
+
001_create_events.sql:
+
stored=dd495f29709d... actual=6a406ca4f1d7...
+
Run 'migrator repair' to update checksums.
+
+
-```sh -migrator rollback -``` + + + + + +
+
+ +
+
+

Guardrails before execution.

+

The default path checks applied history, preflights pending SQL, and coordinates migration runners.

+
+ +
+
+
+ +

Checksum integrity

Compares current blocks with the checksum stored at apply time.

+
+
+
$ migrator show
+
Applied:
+
[X] 001_create_events.sql (HEAD, modified)
+
WARNING: 1 integrity issue found
+
001_create_events.sql: checksum mismatch
+
+

A mismatch or missing checksummed file stops migrator up before pending SQL by default.

+
+ +
+
+ +

Preflight validation

Runs EXPLAIN AST before up or rollback execution.

+
+
+
$ migrator up --dry-run
+
-- 002_add_user_id.sql (up)
+
ALTER TABLE users
+
ADD COLUMN IF NOT EXISTS user_id UInt64
+
+

Dry-run uses the same validation path. This is a best-effort check, not a safety guarantee.

+
+ +
+
+ +

Advisory locking

Uses a TTL-based lock to reduce concurrent migration races.

+
+
+
$ migrator lock-info
+
Locked by: runner-01:1234:abc123ef
+
Locked at: 2026-08-01 14:30:00
+
Expires at: 2026-08-01 14:40:00
+
+

Up, rollback, and baseline use it by default. Keep one migration runner per deployment.

+
+
-## Guides + +
-- [Migration format](migration-format.md) -- [Baseline existing databases](baseline.md) -- [Cluster mode](cluster-mode.md) -- [CI/CD usage](ci-cd.md) -- [Docker usage](docker.md) -- [Python API](python-api.md) -- [Troubleshooting](troubleshooting.md) -- [Known limitations](known-limitations.md) -- [2.0 release notes](release-2.0.md) +
+
+

Choose your path

+

Pick the guide that matches your database and delivery process.

+
-## Examples + +
-- [Basic migration](examples/basic-migration.sql) -- [Cluster migration](examples/cluster-migration.sql) -- [GitHub Actions workflow](examples/github-actions.yml) -- [Kubernetes Job](examples/kubernetes-job.yml) +
diff --git a/docs/javascripts/home.js b/docs/javascripts/home.js new file mode 100644 index 0000000..49f55b1 --- /dev/null +++ b/docs/javascripts/home.js @@ -0,0 +1,54 @@ +(() => { + const initialiseFlow = (root = document) => { + const flow = root.querySelector(".pcm-flow"); + if (!flow || flow.dataset.initialised === "true") return; + + const tabs = [...flow.querySelectorAll('[role="tab"]')]; + const panels = [...flow.querySelectorAll('[role="tabpanel"]')]; + + const activate = (tab, moveFocus = false) => { + const step = tab.dataset.flowStep; + flow.dataset.activeStep = step; + + tabs.forEach((item) => { + const active = item === tab; + item.classList.toggle("is-active", active); + item.setAttribute("aria-selected", String(active)); + item.tabIndex = active ? 0 : -1; + }); + + panels.forEach((panel) => { + const active = panel.dataset.flowPanel === step; + panel.hidden = !active; + panel.classList.toggle("is-active", active); + }); + + if (moveFocus) tab.focus(); + }; + + tabs.forEach((tab, index) => { + tab.addEventListener("click", () => activate(tab)); + tab.addEventListener("keydown", (event) => { + let nextIndex; + if (event.key === "ArrowRight" || event.key === "ArrowDown") nextIndex = (index + 1) % tabs.length; + if (event.key === "ArrowLeft" || event.key === "ArrowUp") nextIndex = (index - 1 + tabs.length) % tabs.length; + if (event.key === "Home") nextIndex = 0; + if (event.key === "End") nextIndex = tabs.length - 1; + if (nextIndex === undefined) return; + event.preventDefault(); + activate(tabs[nextIndex], true); + }); + }); + + const selected = tabs.find((tab) => tab.getAttribute("aria-selected") === "true") || tabs[0]; + activate(selected); + flow.dataset.initialised = "true"; + }; + + if (typeof document$ !== "undefined") document$.subscribe(() => initialiseFlow()); + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", () => initialiseFlow(), { once: true }); + } else { + initialiseFlow(); + } +})(); diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index e1797c3..4f0211b 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -1,3 +1,38 @@ +:root > * { + --pcm-accent: #e7b92f; + --pcm-accent-strong: #8f6900; + --pcm-ink: #1b1d20; + --pcm-muted: #61646b; + --pcm-paper: #f7f7f3; + --pcm-surface: #eeefea; + --pcm-line: rgb(27 29 32 / 12%); + --pcm-code: #202327; + --pcm-success: #83c94c; + --pcm-danger: #ff5d57; + --md-default-bg-color: var(--pcm-paper); + --md-default-fg-color: var(--pcm-ink); + --md-default-fg-color--light: var(--pcm-muted); + --md-primary-fg-color: var(--pcm-ink); + --md-accent-fg-color: var(--pcm-accent-strong); +} + +[data-md-color-scheme="slate"] { + --pcm-accent-strong: #e7b92f; + --pcm-ink: #f0f1ec; + --pcm-muted: #aeb1b8; + --pcm-paper: #181a1d; + --pcm-surface: #222529; + --pcm-line: rgb(240 241 236 / 13%); + --pcm-code: #111316; + --pcm-success: #8fd357; + --pcm-danger: #ff6862; + --md-default-bg-color: var(--pcm-paper); + --md-default-fg-color: var(--pcm-ink); + --md-default-fg-color--light: var(--pcm-muted); + --md-primary-fg-color: #15171a; + --md-accent-fg-color: var(--pcm-accent); +} + .md-header__button.md-logo { margin: 0; padding: 0.1rem; @@ -8,11 +43,1076 @@ } .md-header__button.md-logo img { - height: 2.45rem; - width: 2.45rem; + height: 2.25rem; + width: 2.25rem; } .md-nav__button.md-logo img { height: 3.5rem; width: 3.5rem; } + +.md-content__inner:has(.pcm-home) { + margin: 0; + max-width: none; +} + +.md-content__inner:has(.pcm-home) > h1 { + display: none; +} + +.pcm-home { + color: var(--pcm-ink); + margin: 0 auto; + max-width: 76rem; + padding: 0 1.2rem 5rem; +} + +.pcm-home h1, +.pcm-home h2, +.pcm-home h3 { + color: var(--pcm-ink); + font-weight: 750; + letter-spacing: -0.035em; +} + +.pcm-home h2 { + font-size: clamp(2rem, 4vw, 3.5rem); + line-height: 1.03; + margin: 0 0 1rem; +} + +.pcm-home p { + color: var(--pcm-muted); + line-height: 1.65; +} + +.pcm-hero { + align-items: center; + display: grid; + gap: clamp(2rem, 5vw, 4rem); + grid-template-columns: minmax(0, 1.3fr) minmax(19rem, 0.7fr); + min-height: calc(100dvh - 5rem); + padding: clamp(3rem, 7vw, 6rem) 0 4rem; +} + +.pcm-eyebrow { + color: var(--pcm-accent-strong) !important; + font-size: 0.72rem; + font-weight: 750; + letter-spacing: 0.16em; + margin: 0 0 1.2rem; + text-transform: uppercase; +} + +.pcm-hero h1 { + font-size: clamp(3rem, 5vw, 4rem); + line-height: 0.98; + margin: 0; + max-width: 22ch; +} + +.pcm-hero h1 span { + display: block; + white-space: nowrap; +} + +.pcm-hero__lead { + font-size: clamp(1rem, 1.6vw, 1.2rem); + margin: 1.6rem 0 0; + max-width: 34rem; +} + +.pcm-actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; + margin-top: 2rem; +} + +.pcm-button { + align-items: center; + border: 1px solid transparent; + border-radius: 0.7rem; + display: inline-flex; + font-size: 0.88rem; + font-weight: 700; + justify-content: center; + min-height: 2.9rem; + padding: 0.72rem 1.15rem; + text-decoration: none !important; + transition: transform 140ms ease, background-color 140ms ease, border-color 140ms ease; + white-space: nowrap; +} + +.pcm-button:hover { + transform: translateY(-1px); +} + +.pcm-button:active { + transform: translateY(1px); +} + +.pcm-button--primary { + background: var(--pcm-accent); + color: #222014 !important; +} + +.pcm-button--primary:hover { + background: #f1c84f; +} + +.pcm-button--secondary { + border-color: var(--pcm-line); + color: var(--pcm-ink) !important; +} + +.pcm-button--secondary:hover { + background: var(--pcm-surface); +} + +.pcm-hero__visual { + margin: 0; + position: relative; +} + +.pcm-hero__visual img { + aspect-ratio: 1; + border-radius: 1rem; + box-shadow: 0 2rem 5rem rgb(18 20 22 / 20%); + display: block; + width: 100%; +} + +.pcm-hero__visual figcaption { + background: var(--pcm-code); + border: 1px solid rgb(255 255 255 / 10%); + border-radius: 0.7rem; + bottom: -1.2rem; + box-shadow: 0 1.2rem 2.5rem rgb(18 20 22 / 24%); + color: #f3f3ed; + left: -2rem; + padding: 0.9rem 1.1rem; + position: absolute; +} + +.pcm-hero__visual figcaption code { + background: transparent; + color: inherit; + font-size: 0.76rem; + white-space: nowrap; +} + +.pcm-code-story { + align-items: center; + display: grid; + gap: clamp(2rem, 7vw, 7rem); + grid-template-columns: minmax(0, 0.72fr) minmax(25rem, 1.28fr); + margin: clamp(4rem, 8vw, 7rem) 0 clamp(6rem, 12vw, 10rem); +} + +.pcm-section-copy { + max-width: 42rem; + min-width: 0; +} + +.pcm-section-copy > p:last-child { + margin-bottom: 0; +} + +.pcm-text-link { + color: var(--pcm-ink) !important; + display: inline-block; + font-weight: 700; + margin-top: 1rem; + text-decoration: none !important; +} + +.pcm-text-link span { + color: var(--pcm-accent-strong); + display: inline-block; + margin-left: 0.25rem; + transition: transform 140ms ease; +} + +.pcm-text-link:hover span { + transform: translateX(0.25rem); +} + +.pcm-code-story__code { + min-width: 0; +} + +.pcm-code-story__code .highlight { + border-radius: 1rem; + box-shadow: 0 1.8rem 4rem rgb(18 20 22 / 16%); + margin: 0; + overflow: hidden; +} + +.pcm-code-story__code pre { + min-height: 22rem; + padding: 1.4rem; +} + +.pcm-capabilities, +.pcm-flow, +.pcm-guardrails, +.pcm-paths { + margin-bottom: clamp(6rem, 12vw, 10rem); +} + +.pcm-capabilities > .pcm-section-copy, +.pcm-paths > .pcm-section-copy { + margin-bottom: 2.5rem; +} + +.pcm-bento { + display: grid; + gap: 0.9rem; + grid-template-columns: repeat(4, 1fr); +} + +.pcm-tile { + background: var(--pcm-surface); + border: 1px solid var(--pcm-line); + border-radius: 1rem; + min-height: 13rem; + padding: 1.35rem; +} + +.pcm-tile--wide, +.pcm-tile--accent { + grid-column: span 2; +} + +.pcm-tile--wide { + min-height: 16rem; +} + +.pcm-tile--wide code { + background: var(--pcm-code); + border-radius: 0.5rem; + color: #f2f2ec; + display: inline-block; + margin-top: 1rem; + padding: 0.55rem 0.65rem; +} + +.pcm-tile--accent { + background: var(--pcm-accent); + border-color: transparent; +} + +.pcm-tile--accent h3, +.pcm-tile--accent p { + color: #222014; +} + +.pcm-tile--code { + background: var(--pcm-code); +} + +.pcm-tile--code h3, +.pcm-tile--code p, +.pcm-tile--code code { + color: #f0f1ec; +} + +.pcm-tile--code code { + background: transparent; +} + +.pcm-tile--soft { + background: color-mix(in srgb, var(--pcm-accent) 14%, var(--pcm-surface)); +} + +.pcm-tile h3 { + font-size: 1.15rem; + margin: 0 0 0.8rem; +} + +.pcm-tile p { + font-size: 0.82rem; + margin: 0; +} + +.pcm-flow { + background: color-mix(in srgb, var(--pcm-surface) 48%, var(--pcm-paper)); + border: 1px solid color-mix(in srgb, var(--pcm-line) 70%, transparent); + border-radius: 1rem; + padding: clamp(1.6rem, 4vw, 2.6rem); + scroll-margin-top: 5rem; +} + +.pcm-flow > .pcm-section-copy { + margin-bottom: 1.5rem; +} + +.pcm-flow .pcm-section-copy h2 code { + background: color-mix(in srgb, var(--pcm-surface) 70%, transparent); + color: var(--pcm-ink); + font-size: 0.82em; + white-space: nowrap; +} + +.md-typeset ol.pcm-flow__steps:not([hidden]) { + display: grid; + grid-template-columns: repeat(6, minmax(0, 1fr)); + list-style: none; + margin: 0; + padding: 0; + position: relative; +} + +.pcm-flow__steps::before, +.pcm-flow__steps::after { + content: ""; + height: 2px; + left: 8.333%; + position: absolute; + top: 2.28rem; + width: 83.334%; +} + +.pcm-flow__steps::before { + background: var(--pcm-line); +} + +.pcm-flow__steps::after { + background: var(--pcm-accent); + transform: scaleX(0.4); + transform-origin: left; + transition: transform 360ms ease; +} + +.pcm-flow[data-active-step="connect"] .pcm-flow__steps::after { + transform: scaleX(0); +} + +.pcm-flow[data-active-step="lock"] .pcm-flow__steps::after { + transform: scaleX(0.2); +} + +.pcm-flow[data-active-step="verify"] .pcm-flow__steps::after { + transform: scaleX(0.4); +} + +.pcm-flow[data-active-step="validate"] .pcm-flow__steps::after { + transform: scaleX(0.6); +} + +.pcm-flow[data-active-step="apply"] .pcm-flow__steps::after { + transform: scaleX(0.8); +} + +.pcm-flow[data-active-step="record"] .pcm-flow__steps::after { + transform: scaleX(1); +} + +.pcm-flow__steps > li { + margin: 0 !important; + min-width: 0; + position: relative; + z-index: 1; +} + +.pcm-flow__step { + align-items: center; + appearance: none; + background: transparent; + border: 0; + color: inherit; + cursor: pointer; + display: flex; + flex-direction: column; + font: inherit; + margin: 0; + min-height: 10.9rem; + padding: 0 0.35rem 1rem; + text-align: center; + width: 100%; +} + +.pcm-flow__icon { + align-items: center; + background: var(--pcm-paper); + border: 2px solid var(--pcm-line); + border-radius: 50%; + box-shadow: 0 0 0 0.35rem color-mix(in srgb, var(--pcm-surface) 88%, transparent); + color: var(--pcm-ink); + display: inline-flex; + height: 4.6rem; + justify-content: center; + position: relative; + transition: border-color 160ms ease, box-shadow 160ms ease, transform 160ms ease; + width: 4.6rem; +} + +.pcm-flow__icon img { + height: 2.45rem; + width: 2.45rem; +} + +.pcm-flow__step.is-active .pcm-flow__icon { + border-color: var(--pcm-accent-strong); + box-shadow: 0 0 0 0.35rem color-mix(in srgb, var(--pcm-accent) 18%, transparent); + transform: scale(1.08); +} + +.pcm-flow__number { + color: var(--pcm-accent-strong); + font-family: var(--md-code-font-family); + font-size: 0.64rem; + font-weight: 700; + margin-top: 0.75rem; +} + +.pcm-flow__step strong { + color: var(--pcm-ink); + font-size: 0.88rem; + margin-top: 0.28rem; +} + +.pcm-flow__summary { + color: var(--pcm-muted); + font-size: 0.65rem; + line-height: 1.45; + margin-top: 0.28rem; + max-width: 8.5rem; +} + +.pcm-flow__panels { + margin: 0 auto; + max-width: 46rem; + position: relative; +} + +.pcm-flow__panel { + background: linear-gradient(145deg, #16191c, #20252a); + border: 1px solid rgb(255 255 255 / 8%); + border-radius: 0.72rem; + box-shadow: 0 1.2rem 2.8rem rgb(18 20 22 / 18%); + color: #f0f1ec; + display: grid; + grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.38fr); + min-height: 10.4rem; + opacity: 1; + overflow: visible; + position: relative; +} + +.pcm-flow__panel[hidden] { + display: none; +} + +.pcm-flow__panel::before { + border-bottom: 0.72rem solid #171a1d; + border-left: 0.7rem solid transparent; + border-right: 0.7rem solid transparent; + content: ""; + left: var(--pcm-caret, 50%); + position: absolute; + top: -0.72rem; + transform: translateX(-50%); +} + +.pcm-flow[data-active-step="connect"] .pcm-flow__panel { + --pcm-caret: 8.333%; +} + +.pcm-flow[data-active-step="lock"] .pcm-flow__panel { + --pcm-caret: 25%; +} + +.pcm-flow[data-active-step="verify"] .pcm-flow__panel { + --pcm-caret: 41.667%; +} + +.pcm-flow[data-active-step="validate"] .pcm-flow__panel { + --pcm-caret: 58.333%; +} + +.pcm-flow[data-active-step="apply"] .pcm-flow__panel { + --pcm-caret: 75%; +} + +.pcm-flow[data-active-step="record"] .pcm-flow__panel { + --pcm-caret: 91.667%; +} + +.pcm-flow__panel-copy { + padding: 1.35rem 1.4rem; +} + +.pcm-flow__panel-copy h3 { + color: var(--pcm-accent); + font-size: 0.86rem; + letter-spacing: -0.01em; + margin: 0 0 0.55rem; +} + +.pcm-flow__panel-copy p { + color: #c4c7cc; + font-size: 0.7rem; + line-height: 1.55; + margin: 0; +} + +.pcm-flow__panel-copy code { + background: rgb(255 255 255 / 7%); + color: #f0f1ec; + font-size: 0.92em; +} + +.pcm-terminal { + border-left: 2px solid var(--pcm-accent); + color: #e1e3e5; + display: flex; + flex-direction: column; + font-family: var(--md-code-font-family); + font-size: 0.64rem; + gap: 0.3rem; + justify-content: center; + line-height: 1.5; + min-width: 0; + overflow: auto; + padding: 1.2rem 1.3rem; + white-space: nowrap; +} + +.pcm-terminal code { + background: transparent; + color: #f0f1ec; + font-size: inherit; + padding: 0; +} + +.pcm-terminal__prompt, +.pcm-terminal__accent { + color: var(--pcm-accent); +} + +.pcm-terminal__ok { + color: var(--pcm-success); +} + +.pcm-terminal__error, +.pcm-terminal__message strong { + color: var(--pcm-danger); +} + +.pcm-terminal__indent { + padding-left: 0.8rem; +} + +.pcm-terminal__muted { + color: #9ca0a6; +} + +.pcm-terminal__message { + margin-top: 0.25rem; +} + +.pcm-guardrails { + background: color-mix(in srgb, var(--pcm-surface) 48%, var(--pcm-paper)); + border: 1px solid color-mix(in srgb, var(--pcm-line) 70%, transparent); + border-radius: 1rem; + padding: clamp(1.6rem, 4vw, 2.6rem); +} + +.pcm-guardrails > .pcm-section-copy { + margin-bottom: 1.6rem; +} + +.pcm-guardrails__grid { + display: grid; + gap: 1rem; + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.pcm-guardrail { + background: color-mix(in srgb, var(--pcm-paper) 86%, var(--pcm-surface)); + border: 1px solid var(--pcm-line); + border-radius: 0.8rem; + display: flex; + flex-direction: column; + min-width: 0; + padding: 0.9rem; +} + +.pcm-guardrail__heading { + align-items: center; + display: grid; + gap: 0.75rem; + grid-template-columns: 3.2rem minmax(0, 1fr); + min-height: 3.2rem; +} + +.pcm-guardrail__icon { + align-items: center; + background: var(--pcm-paper); + border: 1px solid var(--pcm-line); + border-radius: 50%; + color: var(--pcm-ink); + display: inline-flex; + height: 3.2rem; + justify-content: center; + width: 3.2rem; +} + +.pcm-guardrail__icon img { + height: 1.7rem; + width: 1.7rem; +} + +[data-md-color-scheme="slate"] .pcm-flow__icon img, +[data-md-color-scheme="slate"] .pcm-guardrail__icon img { + filter: invert(1); +} + +.pcm-guardrail h3 { + font-size: 0.86rem; + margin: 0 0 0.12rem; +} + +.pcm-guardrail__heading p { + font-size: 0.64rem; + line-height: 1.4; + margin: 0; +} + +.pcm-terminal--compact { + background: linear-gradient(145deg, #16191c, #20252a); + border: 1px solid rgb(255 255 255 / 8%); + border-radius: 0.5rem; + font-size: 0.56rem; + justify-content: flex-start; + margin: 0.85rem 0 0; + min-height: 7.2rem; + overflow-wrap: anywhere; + padding: 0.7rem 0.75rem; + white-space: normal; +} + +.pcm-guardrail > p { + font-size: 0.66rem; + line-height: 1.55; + margin: 0.7rem 0 0; +} + +.pcm-guardrail > p code { + font-size: inherit; +} + +.pcm-guardrails__footer { + align-items: start; + display: flex; + gap: 2rem; + justify-content: space-between; + margin-top: 1rem; +} + +.pcm-guardrails__footer .pcm-text-link { + flex: 0 0 auto; + margin-top: 0; +} + +.pcm-guardrails__footer > p { + color: var(--pcm-muted); + font-size: 0.66rem; + line-height: 1.55; + margin: 0; + max-width: 40rem; +} + +.pcm-guardrails__footer strong { + color: var(--pcm-ink); +} + +.pcm-paths__list { + border-top: 1px solid var(--pcm-line); +} + +.pcm-paths__list a { + align-items: center; + border-bottom: 1px solid var(--pcm-line); + color: var(--pcm-ink) !important; + display: grid; + gap: 1.2rem; + grid-template-columns: minmax(10rem, 0.8fr) minmax(15rem, 1.5fr) 2rem; + margin: 0 -0.9rem; + padding: 1.4rem 0.9rem; + text-decoration: none !important; + transition: background-color 140ms ease, padding-left 140ms ease; +} + +.pcm-paths__list a:hover { + background: var(--pcm-surface); + padding-left: 1.25rem; +} + +.pcm-paths__list strong { + font-size: 1.05rem; +} + +.pcm-paths__description { + color: var(--pcm-muted); + font-size: 0.8rem; +} + +.pcm-paths__arrow { + color: var(--pcm-accent-strong); + font-size: 1.15rem; + justify-self: end; + transition: transform 140ms ease; +} + +.pcm-paths__list a:hover .pcm-paths__arrow { + transform: translateX(0.25rem); +} + +.pcm-button:focus-visible, +.pcm-text-link:focus-visible, +.pcm-paths__list a:focus-visible, +.pcm-flow__step:focus-visible { + outline: 3px solid color-mix(in srgb, var(--pcm-accent) 65%, transparent); + outline-offset: 3px; +} + +.md-footer { + background: var(--pcm-paper); +} + +.md-footer__inner { + border-top: 1px solid var(--pcm-line); + max-width: 76rem; + padding: 1.6rem 1.2rem; +} + +body:has(.pcm-home) .md-footer__inner { + display: none; +} + +.md-footer__link { + color: var(--pcm-ink) !important; + margin: 0; + opacity: 1; + padding: 0; + text-decoration: none !important; +} + +.md-footer__direction { + color: var(--pcm-muted); + font-size: 0.62rem; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.md-footer__button { + color: var(--pcm-accent-strong); +} + +.md-footer-meta { + background: var(--pcm-paper); + border-top: 1px solid var(--pcm-line); +} + +.md-footer-meta__inner { + max-width: 76rem; + min-height: 5rem; + padding: 1.1rem 1.2rem; +} + +.md-copyright { + color: var(--pcm-muted); + font-size: 0.72rem; +} + +.md-copyright__highlight { + align-items: center; + color: var(--pcm-ink); + display: flex; + font-weight: 650; + gap: 0.7rem; +} + +.md-copyright__highlight::before { + background: url("../assets/logo.png") center / contain no-repeat; + content: ""; + display: block; + height: 2rem; + width: 2rem; +} + +.md-social { + display: flex; + gap: 0.45rem; +} + +.md-social__link { + align-items: center; + border: 1px solid var(--pcm-line); + border-radius: 0.65rem; + color: var(--pcm-ink) !important; + display: inline-flex; + height: 2.3rem; + justify-content: center; + margin: 0; + transition: background-color 140ms ease, transform 140ms ease; + width: 2.3rem; +} + +.md-social__link:hover { + background: var(--pcm-surface); + transform: translateY(-1px); +} + +@media (max-width: 60rem) { + .pcm-hero { + gap: 2.5rem; + grid-template-columns: minmax(0, 1fr) minmax(17rem, 0.8fr); + } + + .pcm-hero h1 { + font-size: clamp(2.8rem, 7vw, 4.5rem); + } + + .pcm-hero h1 span { + white-space: normal; + } + + .pcm-code-story { + gap: 2.5rem; + } + + .pcm-flow__summary { + font-size: 0.6rem; + } + + .pcm-guardrails__grid { + grid-template-columns: 1fr 1fr; + } + + .pcm-guardrail:last-child { + grid-column: 1 / -1; + } +} + +@media (max-width: 48rem) { + .pcm-home { + padding: 0 0.85rem 3rem; + } + + .pcm-hero, + .pcm-code-story { + grid-template-columns: 1fr; + } + + .pcm-hero { + min-height: 0; + padding: 3rem 0 4.5rem; + } + + .pcm-hero h1 { + font-size: clamp(2.6rem, 13vw, 4rem); + } + + .pcm-hero__visual { + margin: 0 auto; + max-width: 30rem; + width: 100%; + } + + .pcm-hero__visual figcaption { + bottom: -1rem; + left: 0.8rem; + } + + .pcm-code-story { + gap: 1.8rem; + } + + .pcm-code-story__code pre { + min-height: 0; + } + + .pcm-bento { + grid-template-columns: 1fr 1fr; + } + + .pcm-flow, + .pcm-guardrails { + border-radius: 0.8rem; + padding: 1.25rem; + } + + .md-typeset ol.pcm-flow__steps:not([hidden]) { + gap: 0; + grid-template-columns: 1fr; + } + + .pcm-flow__steps::before, + .pcm-flow__steps::after { + left: 1.7rem; + top: 1.7rem; + transform: none !important; + width: 2px; + } + + .pcm-flow__steps::before { + height: calc(100% - 3.4rem); + } + + .pcm-flow__steps::after { + height: var(--pcm-mobile-progress, 40%); + max-height: calc(100% - 3.4rem); + transition: height 360ms ease; + } + + .pcm-flow[data-active-step="connect"] { + --pcm-mobile-progress: 0%; + } + + .pcm-flow[data-active-step="lock"] { + --pcm-mobile-progress: 20%; + } + + .pcm-flow[data-active-step="verify"] { + --pcm-mobile-progress: 40%; + } + + .pcm-flow[data-active-step="validate"] { + --pcm-mobile-progress: 60%; + } + + .pcm-flow[data-active-step="apply"] { + --pcm-mobile-progress: 80%; + } + + .pcm-flow[data-active-step="record"] { + --pcm-mobile-progress: 100%; + } + + .pcm-flow__step { + align-items: start; + display: grid; + gap: 0 0.9rem; + grid-template-columns: 3.4rem 2.1rem minmax(0, 1fr); + min-height: 5.1rem; + padding: 0 0 0.8rem; + text-align: left; + } + + .pcm-flow__icon { + grid-row: 1 / 4; + height: 3.4rem; + width: 3.4rem; + } + + .pcm-flow__icon img { + height: 1.8rem; + width: 1.8rem; + } + + .pcm-flow__number { + grid-column: 2; + grid-row: 1; + margin-top: 0.2rem; + } + + .pcm-flow__step strong { + grid-column: 3; + grid-row: 1; + margin-top: 0; + } + + .pcm-flow__summary { + grid-column: 2 / 4; + grid-row: 2; + margin-top: 0.25rem; + max-width: none; + } + + .pcm-flow__panels { + margin-top: 0.7rem; + } + + .pcm-flow__panel { + grid-template-columns: 1fr; + } + + .pcm-flow__panel::before { + display: none; + } + + .pcm-terminal { + border-left: 0; + border-top: 2px solid var(--pcm-accent); + white-space: normal; + } + + .pcm-guardrails__grid { + grid-template-columns: 1fr; + } + + .pcm-guardrail:last-child { + grid-column: auto; + } + + .pcm-guardrails__footer { + display: block; + } + + .pcm-guardrails__footer > p { + margin-top: 1rem; + } + + .pcm-paths__list a { + align-items: start; + gap: 0.45rem; + grid-template-columns: 1fr auto; + margin: 0; + } + + .pcm-paths__description { + grid-column: 1 / -1; + } + + .pcm-paths__arrow { + grid-column: 2; + grid-row: 1; + } +} + +@media (max-width: 32rem) { + .pcm-actions { + align-items: stretch; + flex-direction: column; + } + + .pcm-bento { + grid-template-columns: 1fr; + } + + .pcm-tile--wide, + .pcm-tile--accent { + grid-column: auto; + } + + .pcm-hero__visual figcaption code { + font-size: 0.64rem; + } +} + +@media (prefers-reduced-motion: reduce) { + .pcm-button, + .pcm-flow__icon, + .pcm-flow__steps::after, + .pcm-paths__list a, + .pcm-paths__arrow, + .pcm-text-link span, + .md-social__link { + transition: none; + } +} diff --git a/mkdocs.yml b/mkdocs.yml index af82c29..8770c0b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -4,43 +4,51 @@ site_url: https://maksim-burtsev.github.io/PyClickHouseMigrator/ repo_url: https://github.com/Maksim-Burtsev/PyClickHouseMigrator repo_name: Maksim-Burtsev/PyClickHouseMigrator -edit_uri: blob/master/docs/ +edit_uri: edit/master/docs/ theme: name: material + variant: modern + font: false logo: assets/logo.png + favicon: assets/logo.png language: en features: - content.code.copy + - navigation.footer + - navigation.path - navigation.sections - navigation.top + - search.highlight - search.suggest palette: - scheme: default - primary: blue - accent: light blue + primary: custom + accent: custom toggle: - icon: material/weather-night + icon: lucide/moon name: Switch to dark mode - scheme: slate - primary: blue - accent: light blue + primary: custom + accent: custom toggle: - icon: material/weather-sunny + icon: lucide/sun name: Switch to light mode -plugins: - - search - extra_css: - stylesheets/extra.css +extra_javascript: + - javascripts/home.js + markdown_extensions: - admonition - attr_list - md_in_html - - pymdownx.highlight: - anchor_linenums: true + - pymdownx.emoji: + emoji_generator: zensical.extensions.emoji.to_svg + emoji_index: zensical.extensions.emoji.twemoji + - pymdownx.highlight - pymdownx.inlinehilite - pymdownx.snippets - pymdownx.superfences @@ -49,20 +57,28 @@ markdown_extensions: - toc: permalink: true -exclude_docs: | - README.md - nav: - - Overview: index.md - - Core: + - Home: index.md + - Get started: - Migration format: migration-format.md - Baseline existing databases: baseline.md - - Cluster mode: cluster-mode.md - Deployment: - CI/CD usage: ci-cd.md - Docker usage: docker.md + - Cluster mode: cluster-mode.md - Reference: - Python API: python-api.md - Troubleshooting: troubleshooting.md - Known limitations: known-limitations.md - - Release 2.0: release-2.0.md + - Releases: + - Upgrade to 2.0: release-2.0.md + +copyright: PyClickHouseMigrator + +extra: + generator: false + social: + - icon: fontawesome/brands/github + link: https://github.com/Maksim-Burtsev/PyClickHouseMigrator + - icon: fontawesome/brands/python + link: https://pypi.org/project/py-clickhouse-migrator/ diff --git a/pyproject.toml b/pyproject.toml index db8f369..b73a5fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ dev = [ "mypy>=1.19.1", ] docs = [ - "mkdocs-material>=9.6,<10", + "zensical==0.0.52", ] [build-system] diff --git a/uv.lock b/uv.lock index 3332c38..f33b5aa 100644 --- a/uv.lock +++ b/uv.lock @@ -2,38 +2,6 @@ version = 1 revision = 3 requires-python = ">=3.11" -[[package]] -name = "babel" -version = "2.18.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, -] - -[[package]] -name = "backrefs" -version = "6.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/a6/e325ec73b638d3ede4421b5445d4a0b8b219481826cc079d510100af356c/backrefs-6.2.tar.gz", hash = "sha256:f44ff4d48808b243b6c0cdc6231e22195c32f77046018141556c66f8bab72a49", size = 7012303, upload-time = "2026-02-16T19:10:15.828Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/39/3765df263e08a4df37f4f43cb5aa3c6c17a4bdd42ecfe841e04c26037171/backrefs-6.2-py310-none-any.whl", hash = "sha256:0fdc7b012420b6b144410342caeb8adc54c6866cf12064abc9bb211302e496f8", size = 381075, upload-time = "2026-02-16T19:10:04.322Z" }, - { url = "https://files.pythonhosted.org/packages/0f/f0/35240571e1b67ffb19dafb29ab34150b6f59f93f717b041082cdb1bfceb1/backrefs-6.2-py311-none-any.whl", hash = "sha256:08aa7fae530c6b2361d7bdcbda1a7c454e330cc9dbcd03f5c23205e430e5c3be", size = 392874, upload-time = "2026-02-16T19:10:06.314Z" }, - { url = "https://files.pythonhosted.org/packages/e3/63/77e8c9745b4d227cce9f5e0a6f68041278c5f9b18588b35905f5f19c1beb/backrefs-6.2-py312-none-any.whl", hash = "sha256:c3f4b9cb2af8cda0d87ab4f57800b57b95428488477be164dd2b47be54db0c90", size = 398787, upload-time = "2026-02-16T19:10:08.274Z" }, - { url = "https://files.pythonhosted.org/packages/c5/71/c754b1737ad99102e03fa3235acb6cb6d3ac9d6f596cbc3e5f236705abd8/backrefs-6.2-py313-none-any.whl", hash = "sha256:12df81596ab511f783b7d87c043ce26bc5b0288cf3bb03610fe76b8189282b2b", size = 400747, upload-time = "2026-02-16T19:10:09.791Z" }, - { url = "https://files.pythonhosted.org/packages/af/75/be12ba31a6eb20dccef2320cd8ccb3f7d9013b68ba4c70156259fee9e409/backrefs-6.2-py314-none-any.whl", hash = "sha256:e5f805ae09819caa1aa0623b4a83790e7028604aa2b8c73ba602c4454e665de7", size = 412602, upload-time = "2026-02-16T19:10:12.317Z" }, - { url = "https://files.pythonhosted.org/packages/21/f8/d02f650c47d05034dcd6f9c8cf94f39598b7a89c00ecda0ecb2911bc27e9/backrefs-6.2-py39-none-any.whl", hash = "sha256:664e33cd88c6840b7625b826ecf2555f32d491800900f5a541f772c485f7cda7", size = 381077, upload-time = "2026-02-16T19:10:13.74Z" }, -] - -[[package]] -name = "certifi" -version = "2026.4.22" -source = { registry = "https://pypi.org/simple" } -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/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]] name = "cfgv" version = "3.5.0" @@ -43,95 +11,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, ] -[[package]] -name = "charset-normalizer" -version = "3.4.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705, upload-time = "2026-04-02T09:26:02.191Z" }, - { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419, upload-time = "2026-04-02T09:26:03.583Z" }, - { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901, upload-time = "2026-04-02T09:26:04.738Z" }, - { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742, upload-time = "2026-04-02T09:26:06.36Z" }, - { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061, upload-time = "2026-04-02T09:26:08.347Z" }, - { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239, upload-time = "2026-04-02T09:26:09.823Z" }, - { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173, upload-time = "2026-04-02T09:26:10.953Z" }, - { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841, upload-time = "2026-04-02T09:26:12.142Z" }, - { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304, upload-time = "2026-04-02T09:26:13.711Z" }, - { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455, upload-time = "2026-04-02T09:26:14.941Z" }, - { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036, upload-time = "2026-04-02T09:26:16.478Z" }, - { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739, upload-time = "2026-04-02T09:26:17.751Z" }, - { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277, upload-time = "2026-04-02T09:26:18.981Z" }, - { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819, upload-time = "2026-04-02T09:26:20.295Z" }, - { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281, upload-time = "2026-04-02T09:26:21.74Z" }, - { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843, upload-time = "2026-04-02T09:26:22.901Z" }, - { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, - { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, - { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" }, - { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" }, - { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" }, - { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" }, - { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" }, - { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" }, - { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" }, - { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" }, - { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" }, - { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" }, - { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" }, - { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" }, - { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" }, - { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" }, - { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" }, - { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" }, - { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" }, - { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" }, - { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" }, - { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" }, - { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" }, - { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" }, - { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" }, - { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" }, - { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" }, - { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" }, - { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" }, - { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" }, - { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" }, - { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" }, - { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" }, - { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" }, - { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" }, - { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" }, - { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" }, - { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" }, - { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" }, - { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" }, - { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" }, - { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" }, - { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" }, - { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" }, - { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" }, - { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" }, - { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" }, - { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" }, - { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" }, - { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" }, - { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" }, - { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" }, - { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" }, - { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" }, - { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" }, - { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" }, - { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" }, - { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" }, - { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" }, - { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" }, - { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" }, - { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, -] - [[package]] name = "click" version = "8.3.1" @@ -321,6 +200,15 @@ toml = [ { name = "tomli", marker = "python_full_version <= '3.11'" }, ] +[[package]] +name = "deepmerge" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/78/6e9e20106224083cfb817d2d3c26e80e72258d617b616721a169b87081e0/deepmerge-2.1.0.tar.gz", hash = "sha256:07ca7a7b8935df596c512fa8161877c0487ac61f691c07766e7d71d2b23bdd2f", size = 21449, upload-time = "2026-06-22T05:46:07.669Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/25/2a75b47cb057b1e164c604fb81ab690a6cdb5e2260ce651194eae90f64a3/deepmerge-2.1.0-py3-none-any.whl", hash = "sha256:8f148339a91d680a75ecb74ade235d9e759a93df373a0b04e9d31c8666cfeb75", size = 14345, upload-time = "2026-06-22T05:46:06.742Z" }, +] + [[package]] name = "distlib" version = "0.4.0" @@ -339,18 +227,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f9/0b/de6f54d4a8bedfe8645c41497f3c18d749f0bd3218170c667bf4b81d0cdd/filelock-3.25.0-py3-none-any.whl", hash = "sha256:5ccf8069f7948f494968fc0713c10e5c182a9c9d9eef3a636307a20c2490f047", size = 26427, upload-time = "2026-03-01T15:08:44.593Z" }, ] -[[package]] -name = "ghp-import" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "python-dateutil" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, -] - [[package]] name = "identify" version = "2.6.17" @@ -360,15 +236,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/40/66/71c1227dff78aaeb942fed29dd5651f2aec166cc7c9aeea3e8b26a539b7d/identify-2.6.17-py2.py3-none-any.whl", hash = "sha256:be5f8412d5ed4b20f2bd41a65f920990bdccaa6a4a18a08f1eefdcd0bdd885f0", size = 99382, upload-time = "2026-03-01T20:04:11.439Z" }, ] -[[package]] -name = "idna" -version = "3.13" -source = { registry = "https://pypi.org/simple" } -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/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", size = 68629, upload-time = "2026-04-22T16:42:40.909Z" }, -] - [[package]] name = "iniconfig" version = "2.3.0" @@ -546,84 +413,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, ] -[[package]] -name = "mergedeep" -version = "1.3.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, -] - -[[package]] -name = "mkdocs" -version = "1.6.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "ghp-import" }, - { name = "jinja2" }, - { name = "markdown" }, - { name = "markupsafe" }, - { name = "mergedeep" }, - { name = "mkdocs-get-deps" }, - { name = "packaging" }, - { name = "pathspec" }, - { name = "pyyaml" }, - { name = "pyyaml-env-tag" }, - { name = "watchdog" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, -] - -[[package]] -name = "mkdocs-get-deps" -version = "0.2.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mergedeep" }, - { name = "platformdirs" }, - { name = "pyyaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/25/b3cccb187655b9393572bde9b09261d267c3bf2f2cdabe347673be5976a6/mkdocs_get_deps-0.2.2.tar.gz", hash = "sha256:8ee8d5f316cdbbb2834bc1df6e69c08fe769a83e040060de26d3c19fad3599a1", size = 11047, upload-time = "2026-03-10T02:46:33.632Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl", hash = "sha256:e7878cbeac04860b8b5e0ca31d3abad3df9411a75a32cde82f8e44b6c16ff650", size = 9555, upload-time = "2026-03-10T02:46:32.256Z" }, -] - -[[package]] -name = "mkdocs-material" -version = "9.7.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "babel" }, - { name = "backrefs" }, - { name = "colorama" }, - { name = "jinja2" }, - { name = "markdown" }, - { name = "mkdocs" }, - { name = "mkdocs-material-extensions" }, - { name = "paginate" }, - { name = "pygments" }, - { name = "pymdown-extensions" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/45/29/6d2bcf41ae40802c4beda2432396fff97b8456fb496371d1bc7aad6512ec/mkdocs_material-9.7.6.tar.gz", hash = "sha256:00bdde50574f776d328b1862fe65daeaf581ec309bd150f7bff345a098c64a69", size = 4097959, upload-time = "2026-03-19T15:41:58.161Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/01/bc663630c510822c95c47a66af9fa7a443c295b47d5f041e5e6ae62ef659/mkdocs_material-9.7.6-py3-none-any.whl", hash = "sha256:71b84353921b8ea1ba84fe11c50912cc512da8fe0881038fcc9a0761c0e635ba", size = 9305470, upload-time = "2026-03-19T15:41:55.217Z" }, -] - -[[package]] -name = "mkdocs-material-extensions" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847, upload-time = "2023-11-22T19:09:45.208Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, -] - [[package]] name = "mypy" version = "1.19.1" @@ -690,15 +479,6 @@ 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" }, ] -[[package]] -name = "paginate" -version = "0.5.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252, upload-time = "2024-08-25T14:17:24.139Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" }, -] - [[package]] name = "pathspec" version = "1.0.4" @@ -761,7 +541,7 @@ dev = [ { name = "ruff" }, ] docs = [ - { name = "mkdocs-material" }, + { name = "zensical" }, ] [package.metadata] @@ -779,28 +559,28 @@ dev = [ { name = "pytest-sugar", specifier = ">=1.0" }, { name = "ruff", specifier = ">=0.15" }, ] -docs = [{ name = "mkdocs-material", specifier = ">=9.6,<10" }] +docs = [{ name = "zensical", specifier = "==0.0.52" }] [[package]] name = "pygments" -version = "2.19.2" +version = "2.20.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] [[package]] name = "pymdown-extensions" -version = "10.21.2" +version = "11.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/08/f1c908c581fd11913da4711ea7ba32c0eee40b0190000996bb863b0c9349/pymdown_extensions-10.21.2.tar.gz", hash = "sha256:c3f55a5b8a1d0edf6699e35dcbea71d978d34ff3fa79f3d807b8a5b3fa90fbdc", size = 853922, upload-time = "2026-03-29T15:01:55.233Z" } +sdist = { url = "https://files.pythonhosted.org/packages/21/a9/5f0c535ba3b08fe09270c16808e053a968868242ecbd5676d4e3a488bf28/pymdown_extensions-11.0.1.tar.gz", hash = "sha256:dd2905ae6fc5b75582fafb139a1266ffc754705efa902aa50067fa7ff4f94ec0", size = 857113, upload-time = "2026-07-02T17:59:22.955Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/27/a2fc51a4a122dfd1015e921ae9d22fee3d20b0b8080d9a704578bf9deece/pymdown_extensions-10.21.2-py3-none-any.whl", hash = "sha256:5c0fd2a2bea14eb39af8ff284f1066d898ab2187d81b889b75d46d4348c01638", size = 268901, upload-time = "2026-03-29T15:01:53.244Z" }, + { url = "https://files.pythonhosted.org/packages/d6/54/da572c98c0b77626a91b5d3b89f0231d8bff5125c225420908632f8b342d/pymdown_extensions-11.0.1-py3-none-any.whl", hash = "sha256:db3943a62bab7e03af1364f0c4083e64b91fb097675a4b6cceccfbe9a77e5eb2", size = 269455, upload-time = "2026-07-02T17:59:21.271Z" }, ] [[package]] @@ -846,18 +626,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/87/d5/81d38a91c1fdafb6711f053f5a9b92ff788013b19821257c2c38c1e132df/pytest_sugar-1.1.1-py3-none-any.whl", hash = "sha256:2f8319b907548d5b9d03a171515c1d43d2e38e32bd8182a1781eb20b43344cc8", size = 11440, upload-time = "2025-08-23T12:19:34.894Z" }, ] -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, -] - [[package]] name = "python-discovery" version = "1.1.1" @@ -935,33 +703,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, ] -[[package]] -name = "pyyaml-env-tag" -version = "1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyyaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, -] - -[[package]] -name = "requests" -version = "2.33.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947, upload-time = "2026-03-30T16:09:13.83Z" }, -] - [[package]] name = "ruff" version = "0.15.5" @@ -987,15 +728,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fe/4e/cd76eca6db6115604b7626668e891c9dd03330384082e33662fb0f113614/ruff-0.15.5-py3-none-win_arm64.whl", hash = "sha256:b498d1c60d2fe5c10c45ec3f698901065772730b411f164ae270bb6bfcc4740b", size = 10965572, upload-time = "2026-03-05T20:06:16.984Z" }, ] -[[package]] -name = "six" -version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, -] - [[package]] name = "termcolor" version = "3.3.0" @@ -1089,15 +821,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload-time = "2025-03-05T21:17:39.857Z" }, ] -[[package]] -name = "urllib3" -version = "2.6.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, -] - [[package]] name = "virtualenv" version = "21.2.0" @@ -1114,28 +837,31 @@ wheels = [ ] [[package]] -name = "watchdog" -version = "6.0.0" +name = "zensical" +version = "0.0.52" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" }, - { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" }, - { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" }, - { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, - { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, - { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, - { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, - { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, - { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, - { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, - { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, - { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, - { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, - { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, - { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, - { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, - { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, - { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +dependencies = [ + { name = "click" }, + { name = "deepmerge" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "pyyaml" }, + { name = "tomli" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/53/f3657dc0ed7666b29cededfeb424b28b8cf1f6ca75f7066af76fca8c1bcf/zensical-0.0.52.tar.gz", hash = "sha256:b11b79dd1bb7da4c1a5293cbc5a2f4394d980bf2bf1c4c326062bc5ddcf2a2e8", size = 3991761, upload-time = "2026-07-30T10:22:51.45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/32/e143d094f832d8a2de6b56f2e20c40437d06376be69117d8e725d00e22c4/zensical-0.0.52-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:7e5fa1df686af8ef223d16637fd31fe2ab248a8b40556037c50af1102b05f5ed", size = 12839791, upload-time = "2026-07-30T10:22:24.867Z" }, + { url = "https://files.pythonhosted.org/packages/13/e6/746c00830a4149826190f99e182cf5642745978d8702372e8370c7ec8a12/zensical-0.0.52-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:20117f935e23900411e5d03ef1d15b3e5ef3f8730d9096a49eb08754fef1f2d4", size = 12723378, upload-time = "2026-07-30T10:22:27.057Z" }, + { url = "https://files.pythonhosted.org/packages/9c/5b/904fa8d57dd27682dcd2a8c683661f0d6e12c111d150b34c7d568ac80018/zensical-0.0.52-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d889b32121fa43061a902c49d976353a674ae566803ac0ea5d41f01aa5da131", size = 13173818, upload-time = "2026-07-30T10:22:29.168Z" }, + { url = "https://files.pythonhosted.org/packages/8c/28/f124a2a512ae0d5d9d158b1cf31798e3191eb9a21ac8ccfdc9cc38e09a7a/zensical-0.0.52-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61b62d254d47e82fb687bc8a74a1f0220a900a0f3ca4bb6c93eab51ca7c8391a", size = 13111975, upload-time = "2026-07-30T10:22:31.418Z" }, + { url = "https://files.pythonhosted.org/packages/10/09/bdcb062263005e0430a532e72ea32a24955208ae92191f02d38abd58b793/zensical-0.0.52-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d09e7fd0d80418639482212fbce19d09877cbef92a4122030e5d19b32dbea08", size = 13498189, upload-time = "2026-07-30T10:22:33.42Z" }, + { url = "https://files.pythonhosted.org/packages/5a/60/7c3d6cee180a65e06a22de8a143d9ae4791ebae5278fd1abd2977fdc69b0/zensical-0.0.52-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6df854d07f5d89a47f37f661058bc3f95efc64d45b0d5500ea46821244f69c16", size = 13145652, upload-time = "2026-07-30T10:22:35.871Z" }, + { url = "https://files.pythonhosted.org/packages/1d/76/e794e77745017652344463a3c4ba286073ca26a43b0c86dcb40ae0dac0b5/zensical-0.0.52-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:188e15376b3718e6e880751c4014e394b59f798329bc21e39c950cc58254a32c", size = 13349087, upload-time = "2026-07-30T10:22:38.005Z" }, + { url = "https://files.pythonhosted.org/packages/a2/ba/6a38f9c29392c1d5729b25d24c8526d3f86c8133bbd2d8481acf1d1bdc78/zensical-0.0.52-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:40cde85bf35901a4c14a56349502b6d3c754d4386de6b887d498cd7269757e00", size = 13385257, upload-time = "2026-07-30T10:22:40.785Z" }, + { url = "https://files.pythonhosted.org/packages/02/b6/c82317c747ec39e1557aeb2b762087bc22437f80a07a16df21df666ac250/zensical-0.0.52-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:d26c29272ce5bad16564a19ecdfd43bbd9b41568a57b923e8b710359de633322", size = 13550906, upload-time = "2026-07-30T10:22:42.933Z" }, + { url = "https://files.pythonhosted.org/packages/c6/77/b7c83ddced2887b03113c322036f74a2d519ae5599cbb2662e8d7f5c7e2c/zensical-0.0.52-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5a1e1c6c99ae50e98cac957bb48719aecec57aa47899462acd65b2fa9afcbcdd", size = 13485819, upload-time = "2026-07-30T10:22:45.001Z" }, + { url = "https://files.pythonhosted.org/packages/b8/88/fcaee358b7e9d380ccdeb6d3a434b24cd6df6b48ff077bdda0046d8fb6c0/zensical-0.0.52-cp310-abi3-win32.whl", hash = "sha256:4ef40c8d2e8fc84886a28704667e38b7f89663cff32a57db5e909a26cf5cf66a", size = 12410758, upload-time = "2026-07-30T10:22:47.28Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1c/d410a93763cafb8827e4e318bad369b84068047c4d658b511c9307104a62/zensical-0.0.52-cp310-abi3-win_amd64.whl", hash = "sha256:dd904e316f1cdc4fee707febdd85d0ac13f742a8ba14da9f9a4dacb8603fe480", size = 12662400, upload-time = "2026-07-30T10:22:49.503Z" }, ]