diff --git a/.agents/requirements-graphify.in b/.agents/requirements-graphify.in index 01b50857d..cdc21b1fa 100644 --- a/.agents/requirements-graphify.in +++ b/.agents/requirements-graphify.in @@ -1 +1 @@ -graphifyy==0.9.96 +graphifyy==0.4.23 diff --git a/.agents/requirements-graphify.txt b/.agents/requirements-graphify.txt index 3bf7cd63d..468c38108 100644 --- a/.agents/requirements-graphify.txt +++ b/.agents/requirements-graphify.txt @@ -1,20 +1,13 @@ -graphifyy==0.9.96 +graphifyy==0.4.23 networkx==3.6.1 -numpy==2.4.6 -pyyaml==6.0.3 -rapidfuzz==3.14.6 tree-sitter==0.25.2 -tree-sitter-bash==0.25.1 tree-sitter-c==0.24.2 tree-sitter-c-sharp==0.23.5 tree-sitter-cpp==0.23.4 tree-sitter-elixir==0.3.5 -tree-sitter-fortran==0.6.0 tree-sitter-go==0.25.0 -tree-sitter-groovy==0.1.2 tree-sitter-java==0.23.5 tree-sitter-javascript==0.25.0 -tree-sitter-json==0.24.8 tree-sitter-julia==0.23.1 tree-sitter-kotlin==1.1.0 tree-sitter-lua==0.5.0 diff --git a/.agents/skills/datadesigner-docs/SKILL.md b/.agents/skills/datadesigner-docs/SKILL.md index 139c7dfb1..7eb2365b2 100644 --- a/.agents/skills/datadesigner-docs/SKILL.md +++ b/.agents/skills/datadesigner-docs/SKILL.md @@ -356,7 +356,7 @@ Notebook tutorials are JS-driven via `` rendering converted `.ip ``` docs/notebook_source/*.py (jupytext format — canonical source, edit here) - │ make convert-execute-notebooks # jupytext --execute (needs NVIDIA_API_KEY) + │ make convert-execute-notebooks # jupytext → jupyter-execute (needs NVIDIA_API_KEY) ▼ docs/notebooks/*.ipynb (executed; outputs captured) │ diff --git a/.agents/tests/test_structural_impact.py b/.agents/tests/test_structural_impact.py index e5cc37bbc..bc5d47522 100644 --- a/.agents/tests/test_structural_impact.py +++ b/.agents/tests/test_structural_impact.py @@ -19,10 +19,15 @@ EXPORT_FAILURE = """ import runpy import sys +from pathlib import Path from unittest.mock import patch +def fail_export(graph, communities, output_path): + Path(output_path).write_text('{') + raise OSError("graph export failed") + sys.argv = sys.argv[1:] -with patch("graphify.export.to_json", return_value=False): +with patch("graphify.export.to_json", side_effect=fail_export): runpy.run_path(sys.argv[0], run_name="__main__") """ @@ -99,7 +104,7 @@ def test_full_graph_round_trip(repo_root: Path, run_tool: Callable[..., subproce assert "**no changes**" in run_tool("--full", "--previous-graph", str(graph_path)).stdout -@pytest.mark.parametrize("metadata", [{}, {"graphify_version": "0.4.23"}, {"schema_version": -1}]) +@pytest.mark.parametrize("metadata", [{}, {"graphify_version": "0.9.96"}, {"schema_version": -1}]) def test_incompatible_baseline_is_reset( repo_root: Path, run_tool: Callable[..., subprocess.CompletedProcess[str]], metadata: dict[str, object] ) -> None: @@ -139,13 +144,16 @@ def test_rejected_export_preserves_baselines( run_tool("--full") baselines = repo_root / "graphify-out/baselines.json" previous = baselines.read_bytes() + graph_path = baselines.with_name("graph.json") + previous_graph = graph_path.read_bytes() (repo_root / INTERFACE).unlink() result = run_tool("--full", reject_export=True, check=False) assert result.returncode != 0 - assert "baselines were not updated" in result.stderr + assert "graph export failed" in result.stderr assert baselines.read_bytes() == previous + assert graph_path.read_bytes() == previous_graph def test_empty_scan_preserves_baselines( diff --git a/.agents/tools/structural_impact.py b/.agents/tools/structural_impact.py index c351fbb49..16af2bce7 100644 --- a/.agents/tools/structural_impact.py +++ b/.agents/tools/structural_impact.py @@ -22,13 +22,15 @@ from graphify.analyze import god_nodes, graph_diff from graphify.build import build_from_json from graphify.cluster import cluster, score_all -from graphify.export import GRAPH_SCHEMA_VERSION, to_json +from graphify.export import to_json from graphify.extract import extract from networkx.readwrite import json_graph _REPO_ROOT_DEFAULT = Path(__file__).resolve().parent.parent.parent _REPO_ROOT = _REPO_ROOT_DEFAULT _GRAPHIFY_VERSION = version("graphifyy") +# Graphify 0.4.x does not stamp its exports, so version our saved report format. +GRAPH_SCHEMA_VERSION = 1 # DD layering: interface -> engine -> config (left depends on right). _LEGAL_DIRECTIONS = {("interface", "engine"), ("interface", "config"), ("engine", "config")} @@ -111,8 +113,12 @@ def _build_graph(files: list[Path]) -> _Analysis: """Extract, build directed graph, cluster, and find god nodes.""" if not files: raise ValueError(f"No Python source files found under {_REPO_ROOT}") - ext = extract(files, root=_REPO_ROOT, cache_root=_REPO_ROOT) + ext = extract(files, cache_root=_REPO_ROOT) G = build_from_json(ext, directed=True) + G.graph.update(graphify_version=_GRAPHIFY_VERSION, schema_version=GRAPH_SCHEMA_VERSION) + for _, node in G.nodes(data=True): + if node.get("source_file"): + node["source_file"] = _rel(node["source_file"]) comms = cluster(G) return _Analysis(graph=G, communities=comms, cohesion=score_all(G, comms), god_nodes=god_nodes(G, top_n=15)) @@ -370,8 +376,13 @@ def _full_mode(previous_graph_path: str | None = None) -> str: out_dir = _REPO_ROOT / "graphify-out" out_dir.mkdir(exist_ok=True) # This is a complete source snapshot, so deletions must replace the old graph. - if not to_json(G, communities, str(out_dir / "graph.json"), force=True): - raise RuntimeError("Could not save the structural graph; baselines were not updated") + graph_path = out_dir / "graph.json" + export_path = graph_path.with_suffix(".tmp") + try: + to_json(G, communities, str(export_path)) + export_path.replace(graph_path) + finally: + export_path.unlink(missing_ok=True) (out_dir / "baselines.json").write_text( json.dumps( { diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 446aa3690..9739ff82b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -14,6 +14,13 @@ updates: directory: /.agents schedule: interval: weekly + # Hold routine upgrades for the 0.4 adapter; keep security updates enabled. + ignore: + - dependency-name: graphifyy + update-types: + - version-update:semver-major + - version-update:semver-minor + - version-update:semver-patch groups: graphify: patterns: diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 94a34bde9..cb23a717a 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -25,13 +25,12 @@ cd DataDesigner # Install with dev dependencies make install-dev -# Or, if you use Jupyter / IPython for development +# Or, to execute the tutorial and documentation notebooks make install-dev-notebooks ``` -Notebook setup uses the patched nbconvert PyPI release, including its HTML stylesheets. -The `install-notebook-css` target reuses existing stylesheets and can restore missing assets from a -checksum-pinned wheel. Use `NOTEBOOK_CSS=0` to skip that restoration check in execution-only environments. +Notebook setup installs the kernel and execution tools used by Jupytext and the Fern notebook pipeline. +Install a Jupyter frontend separately if you want to edit notebooks in its browser interface. ### Verify Your Setup diff --git a/Makefile b/Makefile index 01ea3a357..b09dc10ce 100644 --- a/Makefile +++ b/Makefile @@ -87,7 +87,6 @@ help: @echo " generate-fern-notebooks - Convert docs/notebook_source/*.py → fern/components/notebooks/{json,ts}" @echo " generate-fern-notebooks-with-outputs - Full pipeline: execute notebooks (needs API key), colabify, convert to Fern" @echo " install-docs-deps - Install docs and notebook dependencies" - @echo " install-notebook-css - Restore nbconvert HTML export stylesheets" @echo " prepare-fern-release VERSION=X.Y.Z - Add or refresh Fern version files for release preview" @echo " check-fern-release-version VERSION=X.Y.Z - Verify Fern has a version entry for release publishing" @echo " prepare-fern-docs - Generate local Fern artifacts" @@ -179,9 +178,8 @@ test-graphify: install-graphify install-dev-notebooks: @echo "📦 Installing DataDesigner workspace with notebook dependencies..." @echo " Packages: data-designer-config → data-designer-engine → data-designer" - @echo " Groups: dev + docs + notebooks (Jupyter, jupytext, etc.)" + @echo " Groups: dev + docs + notebooks (Jupytext, kernel, execution tools)" uv sync --all-packages --group dev --group docs --group notebooks - @$(MAKE) install-notebook-css $(call install-pre-commit-hooks) @echo "✅ Dev + docs + notebooks installation complete!" @echo "" @@ -511,7 +509,7 @@ update-license-headers: DOCS_PYTHON_VERSION ?= 3.13 DOCS_PYTHON ?= .venv/bin/python DOCS_JUPYTEXT ?= .venv/bin/jupytext -NOTEBOOK_CSS ?= 1 +DOCS_NBCLIENT ?= $(if $(findstring /,$(DOCS_JUPYTEXT)),$(dir $(DOCS_JUPYTEXT)),)jupyter-execute FERN_VERSION ?= $(shell jq -r .version fern/fern.config.json) FERN ?= npx -y fern-api@$(FERN_VERSION) FERN_ORG ?= $(shell jq -r .organization fern/fern.config.json) @@ -526,16 +524,6 @@ DOCS_CERTS = SSL_CERT_FILE=$$($(DOCS_PYTHON) -c "import certifi; print(certifi.w install-docs-deps: @echo "📦 Installing docs dependencies (Python $(DOCS_PYTHON_VERSION))..." uv sync --python $(DOCS_PYTHON_VERSION) --all-packages --group docs --group notebooks - @$(MAKE) install-notebook-css - -install-notebook-css: -ifeq ($(NOTEBOOK_CSS),1) - $(DOCS_CERTS) $(DOCS_PYTHON) docs/scripts/prepare_nbconvert_css.py -else ifeq ($(NOTEBOOK_CSS),0) - @echo "Skipping nbconvert CSS (notebook execution only)." -else - $(error NOTEBOOK_CSS must be 0 or 1) -endif prepare-fern-release: ifndef VERSION @@ -599,7 +587,7 @@ serve-fern-docs-local-theme: convert-execute-notebooks: ifeq ($(USE_CACHE),1) @echo "📓 Converting Python tutorials to notebooks (with caching)..." - @$(DOCS_CERTS) DOCS_JUPYTEXT=$(DOCS_JUPYTEXT) bash docs/scripts/build_notebooks_cached.sh + @$(DOCS_CERTS) DOCS_JUPYTEXT=$(DOCS_JUPYTEXT) DOCS_NBCLIENT=$(DOCS_NBCLIENT) bash docs/scripts/build_notebooks_cached.sh else @echo "📓 Converting Python tutorials to notebooks and executing ($(DOCS_PYTHON))..." @rm -rf docs/notebooks @@ -611,7 +599,10 @@ else for f in docs/notebook_source/*.py; do \ [ -f "$$f" ] || continue; \ echo "▶ executing $$f"; \ - $(DOCS_JUPYTEXT) --to ipynb --execute "$$f" || failed="$$failed\n • $$f"; \ + if ! { $(DOCS_JUPYTEXT) --to ipynb "$$f" && $(DOCS_NBCLIENT) --inplace "$${f%.py}.ipynb"; }; then \ + rm -f "$${f%.py}.ipynb"; \ + failed="$$failed\n • $$f"; \ + fi; \ done; \ for f in docs/notebook_source/*.ipynb; do [ -f "$$f" ] && mv "$$f" docs/notebooks/; done; \ rm -rf docs/notebook_source/artifacts; \ @@ -818,7 +809,7 @@ clean-test-coverage: format format-check format-check-config format-check-engine format-check-interface \ format-config format-engine format-interface \ generate-colab-notebooks generate-fern-notebooks generate-fern-notebooks-with-outputs help \ - install install-dev install-dev-notebooks install-dev-recipes install-docs-deps install-graphify install-notebook-css \ + install install-dev install-dev-notebooks install-dev-recipes install-docs-deps install-graphify \ lint lint-config lint-engine lint-fix lint-fix-config lint-fix-engine lint-fix-interface lint-interface lock-graphify \ perf-import perf-import-runtime prepare-fern-docs prepare-fern-release publish serve-fern-docs-dev serve-fern-docs-local-theme serve-fern-docs-locally show-versions \ health-checks \ diff --git a/constraints.txt b/constraints.txt index 7144c4482..761159157 100644 --- a/constraints.txt +++ b/constraints.txt @@ -4,7 +4,6 @@ # uv pip install data-designer -c constraints.txt # uv add data-designer -c constraints.txt anyio>=4.14.2 -bleach>=6.4.0 cryptography>=50.0.0 filelock>=4.2.1 idna>=3.15 diff --git a/docs/scripts/build_notebooks_cached.sh b/docs/scripts/build_notebooks_cached.sh index 74164ca6d..fc43ad41f 100755 --- a/docs/scripts/build_notebooks_cached.sh +++ b/docs/scripts/build_notebooks_cached.sh @@ -25,6 +25,7 @@ SOURCE_DIR="$REPO_ROOT/docs/notebook_source" OUTPUT_DIR="$REPO_ROOT/docs/notebooks" CACHE_DIR="${1:-$REPO_ROOT/.notebook-cache}" DOCS_JUPYTEXT="${DOCS_JUPYTEXT:-$REPO_ROOT/.venv/bin/jupytext}" +DOCS_NBCLIENT="${DOCS_NBCLIENT:-$(dirname "$DOCS_JUPYTEXT")/jupyter-execute}" NOTEBOOK_EXECUTION_ATTEMPTS="${NOTEBOOK_EXECUTION_ATTEMPTS:-1}" NOTEBOOK_RETRY_DELAY_SECONDS="${NOTEBOOK_RETRY_DELAY_SECONDS:-15}" @@ -37,11 +38,13 @@ if [[ ! "$NOTEBOOK_RETRY_DELAY_SECONDS" =~ ^[0-9]+$ ]]; then exit 1 fi -if [ ! -x "$DOCS_JUPYTEXT" ]; then - echo "❌ Missing jupytext executable: $DOCS_JUPYTEXT" - echo "Run 'make install-dev-notebooks' first." - exit 1 -fi +for notebook_tool in "$DOCS_JUPYTEXT" "$DOCS_NBCLIENT"; do + if [ ! -x "$notebook_tool" ]; then + echo "❌ Missing notebook executable: $notebook_tool" + echo "Run 'make install-dev-notebooks' first." + exit 1 + fi +done execute_notebook() { local src="$1" @@ -51,7 +54,7 @@ execute_notebook() { for ((attempt = 1; attempt <= NOTEBOOK_EXECUTION_ATTEMPTS; attempt++)); do rm -f "$output" - if "$DOCS_JUPYTEXT" --to ipynb --execute "$src"; then + if "$DOCS_JUPYTEXT" --to ipynb "$src" && "$DOCS_NBCLIENT" --inplace "$output"; then return 0 fi rm -f "$output" diff --git a/docs/scripts/prepare_nbconvert_css.py b/docs/scripts/prepare_nbconvert_css.py deleted file mode 100644 index f5d877aa8..000000000 --- a/docs/scripts/prepare_nbconvert_css.py +++ /dev/null @@ -1,76 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -from __future__ import annotations - -import base64 -import csv -import hashlib -import io -import os -import sys -from importlib.metadata import distribution -from pathlib import Path -from urllib.request import urlopen -from zipfile import ZipFile - -WHEEL_URL = ( - "https://files.pythonhosted.org/packages/81/fd/a8d457af68848a8e5c12dd1d84ff35c415db471af78280e0703db4efbb12/" - "nbconvert-7.17.2-py3-none-any.whl" -) -WHEEL_SHA256 = "6a143c11c00bf831604da4b1be4347d36ea52367057eb920135d69bc2862fed2" -WHEEL_TEMPLATES = "nbconvert-7.17.2.data/data/share/jupyter/nbconvert/templates" -CSS_SHA256 = { - "classic/static/style.css": "5865a609f4437b0464bc121cd567b619074e540a0515a3b82f222f764eb51e01", - "lab/static/index.css": "917ff47850a7cc08fd0658026fda7672a85220aaab258e8849e891b37426f947", - "lab/static/theme-dark.css": "795f2d5069737cbeb5cba01e6b5c7cadbde227c909e43004c5a60f58d5160aec", - "lab/static/theme-light.css": "11bf3558fd3ed353a4c1401ac0c1730d01df073f6436d357c5bbf02a03bd6962", -} - - -def prepare_nbconvert_css() -> None: - """Restore the pinned nbconvert build's HTML assets without replacing its Python code.""" - installed = distribution("nbconvert") - templates = Path(sys.prefix) / "share" / "jupyter" / "nbconvert" / "templates" - if all( - (templates / name).is_file() and hashlib.sha256((templates / name).read_bytes()).hexdigest() == digest - for name, digest in CSS_SHA256.items() - ): - print("nbconvert HTML stylesheets already present.") - return - - record_entry = next( - entry for entry in installed.files or () if entry.name == "RECORD" and entry.parent.name.endswith(".dist-info") - ) - record_path = Path(installed.locate_file(record_entry)) - print("Downloading nbconvert HTML stylesheets from PyPI (256 KiB wheel)...") - with urlopen(WHEEL_URL, timeout=30) as response: - wheel = response.read() - if hashlib.sha256(wheel).hexdigest() != WHEEL_SHA256: - raise ValueError("nbconvert CSS wheel checksum mismatch") - with ZipFile(io.BytesIO(wheel)) as archive: - stylesheets = {name: archive.read(f"{WHEEL_TEMPLATES}/{name}") for name in CSS_SHA256} - for name, content in stylesheets.items(): - if hashlib.sha256(content).hexdigest() != CSS_SHA256[name]: - raise ValueError(f"nbconvert stylesheet checksum mismatch: {name}") - - paths = { - name: os.path.relpath(templates / name, record_path.parent.parent).replace(os.sep, "/") for name in stylesheets - } - records = [ - row for row in csv.reader(io.StringIO(record_path.read_text(encoding="utf-8"))) if row[0] not in paths.values() - ] - for name, content in stylesheets.items(): - destination = templates / name - destination.parent.mkdir(parents=True, exist_ok=True) - destination.write_bytes(content) - digest = base64.urlsafe_b64encode(hashlib.sha256(content).digest()).rstrip(b"=").decode() - records.append([paths[name], f"sha256={digest}", str(len(content))]) - # Track restored assets so reinstalling or uninstalling nbconvert also removes them. - with record_path.open("w", newline="", encoding="utf-8") as record: - csv.writer(record).writerows(records) - print("Restored nbconvert HTML stylesheets; installed Python code is unchanged.") - - -if __name__ == "__main__": - prepare_nbconvert_css() diff --git a/fern/components/NotebookViewer.tsx b/fern/components/NotebookViewer.tsx index 25698e95e..122959dc5 100644 --- a/fern/components/NotebookViewer.tsx +++ b/fern/components/NotebookViewer.tsx @@ -26,7 +26,7 @@ import type { ReactNode } from "react"; * The trust boundary is the converter pipeline: * * docs/notebook_source/*.py (jupytext source — code-reviewed at PR time) - * └─> jupytext --execute (runs in CI/maintainer shell with NVIDIA_API_KEY) + * └─> jupytext + jupyter-execute (runs in CI/maintainer shell with NVIDIA_API_KEY) * └─> *.ipynb (real outputs captured) * └─> fern/scripts/ipynb-to-fern-json.py * └─> fern/components/notebooks/*.{json,ts} (committed) diff --git a/packages/data-designer/tests/docs/test_build_notebooks_cached.py b/packages/data-designer/tests/docs/test_build_notebooks_cached.py index 9b9352559..4e21a8253 100644 --- a/packages/data-designer/tests/docs/test_build_notebooks_cached.py +++ b/packages/data-designer/tests/docs/test_build_notebooks_cached.py @@ -29,7 +29,8 @@ def test_rejects_invalid_retry_settings(tmp_path: Path, setting: str, value: str assert message in result.stdout -def test_retries_failed_notebook_execution(tmp_path: Path) -> None: +@pytest.mark.parametrize("failure_count", [1, 2]) +def test_retries_failed_notebook_execution(tmp_path: Path, failure_count: int) -> None: repo_root = tmp_path / "repo" script = repo_root / "docs" / "scripts" / SCRIPT_PATH.name script.parent.mkdir(parents=True) @@ -45,6 +46,14 @@ def test_retries_failed_notebook_execution(tmp_path: Path) -> None: jupytext = tmp_path / "jupytext" jupytext.write_text( """#!/usr/bin/env bash +src="${!#}" +echo '{"cells": []}' > "${src%.py}.ipynb" +""" + ) + jupytext.chmod(0o755) + nbclient = tmp_path / "jupyter-execute" + nbclient.write_text( + """#!/usr/bin/env bash set -euo pipefail attempt=0 if [ -f "$ATTEMPTS_FILE" ]; then @@ -52,26 +61,29 @@ def test_retries_failed_notebook_execution(tmp_path: Path) -> None: fi attempt=$((attempt + 1)) printf '%s' "$attempt" > "$ATTEMPTS_FILE" -if [ "$attempt" -lt 2 ]; then +if [ "$attempt" -le "$FAILURE_COUNT" ]; then exit 1 fi -src="${!#}" -printf '%s\n' '{"cells": []}' > "${src%.py}.ipynb" """ ) - jupytext.chmod(0o755) + nbclient.chmod(0o755) env = { **os.environ, "ATTEMPTS_FILE": str(attempts_file), + "FAILURE_COUNT": str(failure_count), "DOCS_JUPYTEXT": str(jupytext), + "DOCS_NBCLIENT": str(nbclient), "NOTEBOOK_CACHE_CONTEXT": "test-context", "NOTEBOOK_EXECUTION_ATTEMPTS": "2", "NOTEBOOK_RETRY_DELAY_SECONDS": "0", } - result = subprocess.run([script], check=True, capture_output=True, text=True, env=env) + result = subprocess.run([script], check=False, capture_output=True, text=True, env=env) + succeeded = failure_count == 1 + assert result.returncode == (0 if succeeded else 1) assert attempts_file.read_text() == "2" assert "Attempt 1 failed; retrying" in result.stdout - assert (repo_root / "docs" / "notebooks" / "example.ipynb").exists() - assert (repo_root / ".notebook-cache" / "example.sha256").exists() + assert (repo_root / "docs" / "notebooks" / "example.ipynb").exists() == succeeded + assert (repo_root / ".notebook-cache" / "example.sha256").exists() == succeeded + assert not (source_dir / "example.ipynb").exists() diff --git a/packages/data-designer/tests/docs/test_prepare_nbconvert_css.py b/packages/data-designer/tests/docs/test_prepare_nbconvert_css.py deleted file mode 100644 index 035e1df5c..000000000 --- a/packages/data-designer/tests/docs/test_prepare_nbconvert_css.py +++ /dev/null @@ -1,123 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -from __future__ import annotations - -import csv -import hashlib -import importlib.util -import io -from importlib.metadata import PathDistribution -from pathlib import Path -from types import ModuleType -from zipfile import ZipFile - -import pytest - -SCRIPT_PATH = Path(__file__).resolve().parents[4] / "docs" / "scripts" / "prepare_nbconvert_css.py" - - -@pytest.fixture -def css_environment(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> tuple[ModuleType, Path, Path]: - spec = importlib.util.spec_from_file_location("prepare_nbconvert_css", SCRIPT_PATH) - assert spec is not None and spec.loader is not None - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - - prefix = tmp_path / "venv" - info = prefix / "lib" / "site-packages" / "nbconvert-7.17.2.dist-info" - info.mkdir(parents=True) - (info / "METADATA").write_text("Name: nbconvert\nVersion: 7.17.2\n") - record = info / "RECORD" - record.write_text("nbconvert-7.17.2.dist-info/RECORD,,\n") - installed = PathDistribution(info) - monkeypatch.setattr(module, "distribution", lambda name: installed) - monkeypatch.setattr(module.sys, "prefix", str(prefix)) - - stylesheets = {name: f"/* {name} */".encode() for name in module.CSS_SHA256} - payload = io.BytesIO() - with ZipFile(payload, "w") as wheel: - for name, content in stylesheets.items(): - wheel.writestr(f"{module.WHEEL_TEMPLATES}/{name}", content) - wheel.writestr("nbconvert/__init__.py", "raise RuntimeError('must not install wheel code')") - wheel_bytes = payload.getvalue() - monkeypatch.setattr(module, "WHEEL_SHA256", hashlib.sha256(wheel_bytes).hexdigest()) - monkeypatch.setattr( - module, "CSS_SHA256", {name: hashlib.sha256(data).hexdigest() for name, data in stylesheets.items()} - ) - monkeypatch.setattr(module, "urlopen", lambda *args, **kwargs: io.BytesIO(wheel_bytes)) - return module, prefix, record - - -def test_restores_only_css_and_tracks_assets_for_uninstall(css_environment: tuple[ModuleType, Path, Path]) -> None: - module, prefix, record = css_environment - - module.prepare_nbconvert_css() - - templates = prefix / "share" / "jupyter" / "nbconvert" / "templates" - assert {str(path.relative_to(templates)) for path in templates.rglob("*.css")} == module.CSS_SHA256.keys() - assert not (record.parent.parent / "nbconvert").exists() - with record.open(newline="") as stream: - records = list(csv.reader(stream)) - assert len(records) == 5 - for name, digest, size in records[1:]: - restored = record.parent.parent / name - assert restored.is_file() - assert digest.startswith("sha256=") - assert len(restored.read_bytes()) == int(size) - - -def test_complete_installation_needs_no_network( - css_environment: tuple[ModuleType, Path, Path], monkeypatch: pytest.MonkeyPatch -) -> None: - module, _, record = css_environment - module.prepare_nbconvert_css() - previous = record.read_bytes() - - def offline(*args: object, **kwargs: object) -> None: - raise AssertionError("must not download existing assets") - - monkeypatch.setattr(module, "urlopen", offline) - module.prepare_nbconvert_css() - - assert record.read_bytes() == previous - - -@pytest.mark.parametrize("corruption", ["wheel", "stylesheet", "missing-member"]) -def test_rejects_invalid_assets_before_writing( - css_environment: tuple[ModuleType, Path, Path], monkeypatch: pytest.MonkeyPatch, corruption: str -) -> None: - module, prefix, record = css_environment - previous = record.read_bytes() - if corruption == "wheel": - monkeypatch.setattr(module, "WHEEL_SHA256", "0" * 64) - elif corruption == "stylesheet": - monkeypatch.setitem(module.CSS_SHA256, "classic/static/style.css", "0" * 64) - else: - monkeypatch.setitem(module.CSS_SHA256, "classic/static/missing.css", "0" * 64) - - with pytest.raises((ValueError, KeyError), match="checksum mismatch|missing.css"): - module.prepare_nbconvert_css() - - assert not (prefix / "share").exists() - assert record.read_bytes() == previous - - -@pytest.mark.parametrize("corruption", ["missing", "modified"]) -def test_repairs_incomplete_installation_without_duplicate_records( - css_environment: tuple[ModuleType, Path, Path], corruption: str -) -> None: - module, prefix, record = css_environment - module.prepare_nbconvert_css() - stylesheet = prefix / "share" / "jupyter" / "nbconvert" / "templates" / "classic" / "static" / "style.css" - expected = stylesheet.read_bytes() - if corruption == "missing": - stylesheet.unlink() - else: - stylesheet.write_bytes(b"modified") - - module.prepare_nbconvert_css() - - assert stylesheet.read_bytes() == expected - with record.open(newline="") as stream: - assert len(list(csv.reader(stream))) == 5 diff --git a/pyproject.toml b/pyproject.toml index aa5f3a3db..8932a5dc8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,6 @@ required-version = ">=0.13.4" # Minimum versions for transitive dependencies with known security vulnerabilities. constraint-dependencies = [ "anyio>=4.14.2", - "bleach>=6.4.0", "cryptography>=50.0.0", "filelock>=4.2.1", "idna>=3.15", @@ -65,14 +64,9 @@ notebooks = [ "aiohttp>=3.14.4,<4", # Keep aligned with the security constraint above "datasets>=5.0.1,<6", # 5.0.1 fixes CVE-2026-66007 "ipykernel>=6.29.0,<7", - "jupyter>=1.0.0,<2", - "jupyter-server>=2.21.0,<3", # Keep aligned with the security constraint above - "jupyterlab>=4.6.4,<5", # 4.6.4 fixes CVE-2026-102831 - "mistune>=3.3.3,<4", # 3.3.3 fixes security advisory pulled in by nbconvert - "nbconvert>=7.17.2,<8", # 7.17.2 fixes export filename path traversal - "notebook>=7.6.3,<8", # 7.6.3 fixes CVE-2026-102831 + "ipywidgets>=8.1.8,<9", + "nbclient>=0.10.4,<1", "setuptools>=84.1.0,<85", # 84.1.0 fixes the namespace_packages.txt path escape - "soupsieve>=2.9.1,<3", # 2.9.1 fixes soupsieve security advisories pulled in by nbconvert "tornado>=6.6,<7", # 6.6 fixes redirect and HTTP parsing advisories ] recipes = [ diff --git a/uv.lock b/uv.lock index 99846d7ac..6aae489f9 100644 --- a/uv.lock +++ b/uv.lock @@ -22,7 +22,6 @@ members = [ ] constraints = [ { name = "anyio", specifier = ">=4.14.2" }, - { name = "bleach", specifier = ">=6.4.0" }, { name = "cryptography", specifier = ">=50.0.0" }, { name = "filelock", specifier = ">=4.2.1" }, { name = "idna", specifier = ">=3.15" }, @@ -266,62 +265,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, ] -[[package]] -name = "argon2-cffi" -version = "25.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "argon2-cffi-bindings" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657, upload-time = "2025-06-03T06:55:30.804Z" }, -] - -[[package]] -name = "argon2-cffi-bindings" -version = "25.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441, upload-time = "2025-07-30T10:02:05.147Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/60/97/3c0a35f46e52108d4707c44b95cfe2afcafc50800b5450c197454569b776/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:3d3f05610594151994ca9ccb3c771115bdb4daef161976a266f0dd8aa9996b8f", size = 54393, upload-time = "2025-07-30T10:01:40.97Z" }, - { url = "https://files.pythonhosted.org/packages/9d/f4/98bbd6ee89febd4f212696f13c03ca302b8552e7dbf9c8efa11ea4a388c3/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8b8efee945193e667a396cbc7b4fb7d357297d6234d30a489905d96caabde56b", size = 29328, upload-time = "2025-07-30T10:01:41.916Z" }, - { url = "https://files.pythonhosted.org/packages/43/24/90a01c0ef12ac91a6be05969f29944643bc1e5e461155ae6559befa8f00b/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3c6702abc36bf3ccba3f802b799505def420a1b7039862014a65db3205967f5a", size = 31269, upload-time = "2025-07-30T10:01:42.716Z" }, - { url = "https://files.pythonhosted.org/packages/d4/d3/942aa10782b2697eee7af5e12eeff5ebb325ccfb86dd8abda54174e377e4/argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1c70058c6ab1e352304ac7e3b52554daadacd8d453c1752e547c76e9c99ac44", size = 86558, upload-time = "2025-07-30T10:01:43.943Z" }, - { url = "https://files.pythonhosted.org/packages/0d/82/b484f702fec5536e71836fc2dbc8c5267b3f6e78d2d539b4eaa6f0db8bf8/argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2fd3bfbff3c5d74fef31a722f729bf93500910db650c925c2d6ef879a7e51cb", size = 92364, upload-time = "2025-07-30T10:01:44.887Z" }, - { url = "https://files.pythonhosted.org/packages/c9/c1/a606ff83b3f1735f3759ad0f2cd9e038a0ad11a3de3b6c673aa41c24bb7b/argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4f9665de60b1b0e99bcd6be4f17d90339698ce954cfd8d9cf4f91c995165a92", size = 85637, upload-time = "2025-07-30T10:01:46.225Z" }, - { url = "https://files.pythonhosted.org/packages/44/b4/678503f12aceb0262f84fa201f6027ed77d71c5019ae03b399b97caa2f19/argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ba92837e4a9aa6a508c8d2d7883ed5a8f6c308c89a4790e1e447a220deb79a85", size = 91934, upload-time = "2025-07-30T10:01:47.203Z" }, - { url = "https://files.pythonhosted.org/packages/f0/c7/f36bd08ef9bd9f0a9cff9428406651f5937ce27b6c5b07b92d41f91ae541/argon2_cffi_bindings-25.1.0-cp314-cp314t-win32.whl", hash = "sha256:84a461d4d84ae1295871329b346a97f68eade8c53b6ed9a7ca2d7467f3c8ff6f", size = 28158, upload-time = "2025-07-30T10:01:48.341Z" }, - { url = "https://files.pythonhosted.org/packages/b3/80/0106a7448abb24a2c467bf7d527fe5413b7fdfa4ad6d6a96a43a62ef3988/argon2_cffi_bindings-25.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b55aec3565b65f56455eebc9b9f34130440404f27fe21c3b375bf1ea4d8fbae6", size = 32597, upload-time = "2025-07-30T10:01:49.112Z" }, - { url = "https://files.pythonhosted.org/packages/05/b8/d663c9caea07e9180b2cb662772865230715cbd573ba3b5e81793d580316/argon2_cffi_bindings-25.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:87c33a52407e4c41f3b70a9c2d3f6056d88b10dad7695be708c5021673f55623", size = 28231, upload-time = "2025-07-30T10:01:49.92Z" }, - { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121, upload-time = "2025-07-30T10:01:50.815Z" }, - { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177, upload-time = "2025-07-30T10:01:51.681Z" }, - { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090, upload-time = "2025-07-30T10:01:53.184Z" }, - { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246, upload-time = "2025-07-30T10:01:54.145Z" }, - { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126, upload-time = "2025-07-30T10:01:55.074Z" }, - { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343, upload-time = "2025-07-30T10:01:56.007Z" }, - { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777, upload-time = "2025-07-30T10:01:56.943Z" }, - { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180, upload-time = "2025-07-30T10:01:57.759Z" }, - { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715, upload-time = "2025-07-30T10:01:58.56Z" }, - { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149, upload-time = "2025-07-30T10:01:59.329Z" }, -] - -[[package]] -name = "arrow" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "python-dateutil" }, - { name = "tzdata" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" }, -] - [[package]] name = "asciichartpy" version = "1.5.25" @@ -343,15 +286,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, ] -[[package]] -name = "async-lru" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8a/ca724066c32a53fa75f59e0f21aa822fdaa8a0dffa112d223634e3caabf9/async_lru-2.2.0.tar.gz", hash = "sha256:80abae2a237dbc6c60861d621619af39f0d920aea306de34cb992c879e01370c", size = 14654, upload-time = "2026-02-20T19:11:43.848Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/5c/af990f019b8dd11c5492a6371fe74a5b0276357370030b67254a87329944/async_lru-2.2.0-py3-none-any.whl", hash = "sha256:e2c1cf731eba202b59c5feedaef14ffd9d02ad0037fcda64938699f2c380eafe", size = 7890, upload-time = "2026-02-20T19:11:42.273Z" }, -] - [[package]] name = "attrs" version = "25.4.0" @@ -361,45 +295,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, ] -[[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 = "beautifulsoup4" -version = "4.14.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "soupsieve" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, -] - -[[package]] -name = "bleach" -version = "6.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "webencodings" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/48/3c/e12ac860709702bd5ebeb9b56a4fe334f1001246ee1b8f2b7ee28912df7d/bleach-6.4.0.tar.gz", hash = "sha256:4202482733d85cedd04e59fcb2f89f4e4c7c385a78d3c3c23c30446843a37452", size = 204857, upload-time = "2026-06-05T13:01:13.734Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/9d/40b6267367182187139a4000b82a3b287d84d745bccd808e75d916920e9d/bleach-6.4.0-py3-none-any.whl", hash = "sha256:4b6b6a54fff2e69a3dde9d21cc6301220bee3c3cb792187d11403fd795031081", size = 165109, upload-time = "2026-06-05T13:01:12.504Z" }, -] - -[package.optional-dependencies] -css = [ - { name = "tinycss2" }, -] - [[package]] name = "bm25s" version = "0.3.2" @@ -935,14 +830,9 @@ notebooks = [ { name = "aiohttp" }, { name = "datasets" }, { name = "ipykernel" }, - { name = "jupyter" }, - { name = "jupyter-server" }, - { name = "jupyterlab" }, - { name = "mistune" }, - { name = "nbconvert" }, - { name = "notebook" }, + { name = "ipywidgets" }, + { name = "nbclient" }, { name = "setuptools" }, - { name = "soupsieve" }, { name = "tornado" }, ] recipes = [ @@ -968,14 +858,9 @@ notebooks = [ { name = "aiohttp", specifier = ">=3.14.4,<4" }, { name = "datasets", specifier = ">=5.0.1,<6" }, { name = "ipykernel", specifier = ">=6.29.0,<7" }, - { name = "jupyter", specifier = ">=1.0.0,<2" }, - { name = "jupyter-server", specifier = ">=2.21.0,<3" }, - { name = "jupyterlab", specifier = ">=4.6.4,<5" }, - { name = "mistune", specifier = ">=3.3.3,<4" }, - { name = "nbconvert", specifier = ">=7.17.2,<8" }, - { name = "notebook", specifier = ">=7.6.3,<8" }, + { name = "ipywidgets", specifier = ">=8.1.8,<9" }, + { name = "nbclient", specifier = ">=0.10.4,<1" }, { name = "setuptools", specifier = ">=84.1.0,<85" }, - { name = "soupsieve", specifier = ">=2.9.1,<3" }, { name = "tornado", specifier = ">=6.6,<7" }, ] recipes = [ @@ -1042,15 +927,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, ] -[[package]] -name = "defusedxml" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, -] - [[package]] name = "diff-cover" version = "10.2.0" @@ -1159,15 +1035,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e0/1b/5e74289a1878e666bb4b65fe5805a04cafcac2aa5f519ef1ead67ef91c56/filelock-4.2.4-py3-none-any.whl", hash = "sha256:301241438c57936ef93f4243a94f2559022268bfcf9b375a9a72eb0f8db8358e", size = 162475, upload-time = "2026-10-19T01:57:49.419Z" }, ] -[[package]] -name = "fqdn" -version = "1.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015, upload-time = "2021-03-11T07:16:29.08Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" }, -] - [[package]] name = "frozenlist" version = "1.8.0" @@ -1534,18 +1401,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808, upload-time = "2025-11-01T21:18:10.956Z" }, ] -[[package]] -name = "isoduration" -version = "20.11.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "arrow" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" }, -] - [[package]] name = "jedi" version = "0.19.2" @@ -1579,15 +1434,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9a/79/91b83df91d03b9647ee759f286900957f0d113f49a606e28c8a43d39365b/json_repair-0.64.2-py3-none-any.whl", hash = "sha256:1dec7868c05abff0c52e91dc896e01f28fda6ba1c9f2a9ede18ab520dde637e1", size = 52688, upload-time = "2026-10-23T05:35:21.978Z" }, ] -[[package]] -name = "json5" -version = "0.13.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/77/e8/a3f261a66e4663f22700bc8a17c08cb83e91fbf086726e7a228398968981/json5-0.13.0.tar.gz", hash = "sha256:b1edf8d487721c0bf64d83c28e91280781f6e21f4a797d3261c7c828d4c165bf", size = 52441, upload-time = "2026-01-01T19:42:14.99Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl", hash = "sha256:9a08e1dd65f6a4d4c6fa82d216cf2477349ec2346a38fd70cc11d2557499fbcc", size = 36163, upload-time = "2026-01-01T19:42:13.962Z" }, -] - [[package]] name = "jsonpath-ng" version = "1.8.0" @@ -1678,15 +1524,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ba/e1/12b8a4e1ead50749bf2997f004b99a4b4458144bb31ac6be9d4fadd64103/jsonpath_rust_bindings-1.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c24aa6724dd46f79b3b1ef178eae6412aba9a2b51e0fbc283e04d89f11af1444", size = 808532, upload-time = "2025-11-16T19:03:57.096Z" }, ] -[[package]] -name = "jsonpointer" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, -] - [[package]] name = "jsonschema" version = "4.26.0" @@ -1702,19 +1539,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, ] -[package.optional-dependencies] -format-nongpl = [ - { name = "fqdn" }, - { name = "idna" }, - { name = "isoduration" }, - { name = "jsonpointer" }, - { name = "rfc3339-validator" }, - { name = "rfc3986-validator" }, - { name = "rfc3987-syntax" }, - { name = "uri-template" }, - { name = "webcolors" }, -] - [[package]] name = "jsonschema-specifications" version = "2025.9.1" @@ -1727,36 +1551,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, ] -[[package]] -name = "jupyter" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ipykernel" }, - { name = "ipywidgets" }, - { name = "jupyter-console" }, - { name = "jupyterlab" }, - { name = "nbconvert" }, - { name = "notebook" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959, upload-time = "2024-08-30T07:15:48.299Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657, upload-time = "2024-08-30T07:15:47.045Z" }, -] - -[[package]] -name = "jupyter-builder" -version = "1.2.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-core" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/75/3e/56f593e6a664cd14d441724654ce8243f3cac7d3e45867cf084749c8bc75/jupyter_builder-1.2.3.tar.gz", hash = "sha256:01aba6794eb9b19e0e29ae21137ca60ba4135c70347d4b9f664a586822b8c809", size = 1024218, upload-time = "2026-09-04T18:54:09.411Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/84/aa/be79e87c50698673f196d0633fc1664607da2289f9688d1de7a1c9db9e71/jupyter_builder-1.2.3-py3-none-any.whl", hash = "sha256:c5ea5a7190c2a7b082494abade98eece1b2b5bd5dbd7d610606cbcd10a1d08b3", size = 947541, upload-time = "2026-09-04T18:54:07.644Z" }, -] - [[package]] name = "jupyter-client" version = "8.8.0" @@ -1773,26 +1567,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2d/0b/ceb7694d864abc0a047649aec263878acb9f792e1fec3e676f22dc9015e3/jupyter_client-8.8.0-py3-none-any.whl", hash = "sha256:f93a5b99c5e23a507b773d3a1136bd6e16c67883ccdbd9a829b0bbdb98cd7d7a", size = 107371, upload-time = "2026-01-08T13:55:45.562Z" }, ] -[[package]] -name = "jupyter-console" -version = "6.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ipykernel" }, - { name = "ipython", version = "9.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "ipython", version = "9.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "prompt-toolkit" }, - { name = "pygments" }, - { name = "pyzmq" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363, upload-time = "2023-03-06T14:13:31.02Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510, upload-time = "2023-03-06T14:13:28.229Z" }, -] - [[package]] name = "jupyter-core" version = "5.9.1" @@ -1806,132 +1580,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032, upload-time = "2025-10-16T19:19:16.783Z" }, ] -[[package]] -name = "jupyter-events" -version = "0.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jsonschema", extra = ["format-nongpl"] }, - { name = "packaging" }, - { name = "python-json-logger" }, - { name = "pyyaml" }, - { name = "referencing" }, - { name = "rfc3339-validator" }, - { name = "rfc3986-validator" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196, upload-time = "2025-02-03T17:23:41.485Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430, upload-time = "2025-02-03T17:23:38.643Z" }, -] - -[[package]] -name = "jupyter-lsp" -version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-server" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823, upload-time = "2025-08-27T17:47:34.671Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687, upload-time = "2025-08-27T17:47:33.15Z" }, -] - -[[package]] -name = "jupyter-server" -version = "2.21.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "argon2-cffi" }, - { name = "jinja2" }, - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "jupyter-events" }, - { name = "jupyter-server-terminals" }, - { name = "nbconvert" }, - { name = "nbformat" }, - { name = "overrides", marker = "python_full_version < '3.12'" }, - { name = "packaging" }, - { name = "prometheus-client" }, - { name = "pywinpty", marker = "os_name == 'nt'" }, - { name = "pyzmq" }, - { name = "send2trash" }, - { name = "terminado" }, - { name = "tornado" }, - { name = "traitlets" }, - { name = "websocket-client" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/65/3d/3c9f8bce5d5448107bd285cd80185e76c9c871d076b580dfd90997e52904/jupyter_server-2.21.1.tar.gz", hash = "sha256:a8960aa29263f6041283e97d4756b099fb49b767baab6371891ecb1bd40a63df", size = 761651, upload-time = "2026-09-15T16:00:07.853Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/39/91bc08650cc8e3efeb7a83c25e20ebddcc9b70d28b4eb6f51a4fb55da7a4/jupyter_server-2.21.1-py3-none-any.whl", hash = "sha256:2a6467606af7dbae2e7e31640030025969e15db6a649eae334af90415dc71dca", size = 394641, upload-time = "2026-09-15T16:00:05.526Z" }, -] - -[[package]] -name = "jupyter-server-terminals" -version = "0.5.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pywinpty", marker = "os_name == 'nt'" }, - { name = "terminado" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/a7/bcd0a9b0cbba88986fe944aaaf91bfda603e5a50bda8ed15123f381a3b2f/jupyter_server_terminals-0.5.4.tar.gz", hash = "sha256:bbda128ed41d0be9020349f9f1f2a4ab9952a73ed5f5ac9f1419794761fb87f5", size = 31770, upload-time = "2026-01-14T16:53:20.213Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl", hash = "sha256:55be353fc74a80bc7f3b20e6be50a55a61cd525626f578dcb66a5708e2007d14", size = 13704, upload-time = "2026-01-14T16:53:18.738Z" }, -] - -[[package]] -name = "jupyterlab" -version = "4.6.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "async-lru" }, - { name = "httpx" }, - { name = "ipykernel" }, - { name = "jinja2" }, - { name = "jupyter-builder" }, - { name = "jupyter-core" }, - { name = "jupyter-lsp" }, - { name = "jupyter-server" }, - { name = "jupyterlab-server" }, - { name = "notebook-shim" }, - { name = "packaging" }, - { name = "tornado" }, - { name = "traitlets" }, - { name = "typing-extensions", marker = "python_full_version < '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/33/8d/995cc142f6083346b35e7d3eadc5a6717ee89ce64ea53577010ac493bc3c/jupyterlab-4.6.4.tar.gz", hash = "sha256:404f49b081819378524886c9db66dba57a5565981eff885830df1baba3a17df5", size = 28335647, upload-time = "2026-09-21T15:25:18.779Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/e4/072bc0d3c6d45d414062a06af7ee81c02a2c12d769c358ec9919f9995ffd/jupyterlab-4.6.4-py3-none-any.whl", hash = "sha256:15b13f991d3985129c797eb84d9949eeb8b6615e14b444868e642411f2c418b2", size = 17171596, upload-time = "2026-09-21T15:25:14.123Z" }, -] - -[[package]] -name = "jupyterlab-pygments" -version = "0.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, -] - -[[package]] -name = "jupyterlab-server" -version = "2.28.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "babel" }, - { name = "jinja2" }, - { name = "json5" }, - { name = "jsonschema" }, - { name = "jupyter-server" }, - { name = "packaging" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996, upload-time = "2025-10-22T13:59:18.37Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830, upload-time = "2025-10-22T13:59:16.767Z" }, -] - [[package]] name = "jupyterlab-widgets" version = "3.0.16" @@ -1957,15 +1605,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/5a/736dd2f4535dbf3bf26523f9158c011389ef88dd06ec2eef67fd744f1c7b/jupytext-1.19.1-py3-none-any.whl", hash = "sha256:d8975035155d034bdfde5c0c37891425314b7ea8d3a6c4b5d18c294348714cd9", size = 170478, upload-time = "2026-01-25T21:35:11.17Z" }, ] -[[package]] -name = "lark" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732, upload-time = "2025-10-27T18:25:56.653Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151, upload-time = "2025-10-27T18:25:54.882Z" }, -] - [[package]] name = "lxml" version = "6.1.3" @@ -2251,15 +1890,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] -[[package]] -name = "mistune" -version = "3.3.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/92/328a294a6de83bacb95bed01f04e0eaff4e3616ee359fc821a5dfc539b02/mistune-3.3.4.tar.gz", hash = "sha256:58b5c96d6fcb61190dfe5fae498d2b2065f99cf61e9649418fd54cf1ada86dfe", size = 121426, upload-time = "2026-07-22T05:22:30.89Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/e4/288365afae98953bc01de09f686f40d8ee84578135aa7767d5d4e60b5278/mistune-3.3.4-py3-none-any.whl", hash = "sha256:ee015381e955e370962968befe1d729ab60fafb6a715ac6751763fbce38c8d4a", size = 66862, upload-time = "2026-07-22T05:22:29.419Z" }, -] - [[package]] name = "multidict" version = "6.9.1" @@ -2449,31 +2079,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl", hash = "sha256:9162df5a7373d70d606527300a95a975a47c137776cd942e52d9c7e29ff83440", size = 25465, upload-time = "2025-12-23T07:45:44.51Z" }, ] -[[package]] -name = "nbconvert" -version = "7.17.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "beautifulsoup4" }, - { name = "bleach", extra = ["css"] }, - { name = "defusedxml" }, - { name = "jinja2" }, - { name = "jupyter-core" }, - { name = "jupyterlab-pygments" }, - { name = "markupsafe" }, - { name = "mistune" }, - { name = "nbclient" }, - { name = "nbformat" }, - { name = "packaging" }, - { name = "pandocfilters" }, - { name = "pygments" }, - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/53/6a/252c7620305a9661205aed7a2a4b3592f5207bfca56ad11b7dea2c5ec2f6/nbconvert-7.17.2.tar.gz", hash = "sha256:344a218e8595117ce37396ed025d994f146d076226ebac59255a2fa085ab24d8", size = 865989, upload-time = "2026-10-12T09:11:19.583Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/fd/a8d457af68848a8e5c12dd1d84ff35c415db471af78280e0703db4efbb12/nbconvert-7.17.2-py3-none-any.whl", hash = "sha256:6a143c11c00bf831604da4b1be4347d36ea52367057eb920135d69bc2862fed2", size = 262094, upload-time = "2026-10-12T09:11:17.215Z" }, -] - [[package]] name = "nbformat" version = "5.10.4" @@ -2516,35 +2121,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, ] -[[package]] -name = "notebook" -version = "7.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-builder" }, - { name = "jupyter-server" }, - { name = "jupyterlab" }, - { name = "jupyterlab-server" }, - { name = "notebook-shim" }, - { name = "tornado" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/42/ac/aedb759dc683dcd129f6c75271bab5eb23020b0f7969163c726343718e1e/notebook-7.6.3.tar.gz", hash = "sha256:e2c08e469c0ae20bb0b3214f0ab77e79653317a2f8e5b34c10361c66874a5b50", size = 5501618, upload-time = "2026-09-21T18:07:24.261Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/f7/907b98438cf00bdc4e296570058f29a347214bb42338a48e3b7eae58ae2a/notebook-7.6.3-py3-none-any.whl", hash = "sha256:ad7e0eb765fba836cd4a2ab0c7a3a26cde1d91665fbf6f533b6ae7b2de6d88d2", size = 5548452, upload-time = "2026-09-21T18:07:21.563Z" }, -] - -[[package]] -name = "notebook-shim" -version = "0.2.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jupyter-server" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167, upload-time = "2024-02-14T23:35:18.353Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307, upload-time = "2024-02-14T23:35:16.286Z" }, -] - [[package]] name = "numpy" version = "2.4.3" @@ -2677,15 +2253,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bc/14/67f8aa798857f8cf686f515bf93d9bb877ce952ddc8efae0fa25b45ce0d6/opentelemetry_semantic_conventions-0.66b1-py3-none-any.whl", hash = "sha256:d4cddeb4315490b35213f55e2bdc9ac54bb1e4d318927475bed62b35545e581b", size = 206279, upload-time = "2026-10-06T17:32:56.103Z" }, ] -[[package]] -name = "overrides" -version = "7.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, -] - [[package]] name = "packaging" version = "26.3" @@ -2749,15 +2316,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/cf/6a51b2c38980e04c279fd2fa908a1b0982064e860444acfca4ec2e2c8359/pandas-3.0.5-cp314-cp314t-win_arm64.whl", hash = "sha256:3c5015fd1730fbf883647e88068176c839c102cea883ba1769a6f4593bfc1f8c", size = 9509776, upload-time = "2026-07-22T22:19:26.694Z" }, ] -[[package]] -name = "pandocfilters" -version = "1.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, -] - [[package]] name = "parso" version = "0.8.6" @@ -3442,26 +3000,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, ] -[[package]] -name = "pywinpty" -version = "3.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/54/37c7370ba91f579235049dc26cd2c5e657d2a943e01820844ffc81f32176/pywinpty-3.0.3.tar.gz", hash = "sha256:523441dc34d231fb361b4b00f8c99d3f16de02f5005fd544a0183112bcc22412", size = 31309, upload-time = "2026-02-04T21:51:09.524Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/c3/3e75075c7f71735f22b66fab0481f2c98e3a4d58cba55cb50ba29114bcf6/pywinpty-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:dff25a9a6435f527d7c65608a7e62783fc12076e7d44487a4911ee91be5a8ac8", size = 2114430, upload-time = "2026-02-04T21:54:19.485Z" }, - { url = "https://files.pythonhosted.org/packages/8d/1e/8a54166a8c5e4f5cb516514bdf4090be4d51a71e8d9f6d98c0aa00fe45d4/pywinpty-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:fbc1e230e5b193eef4431cba3f39996a288f9958f9c9f092c8a961d930ee8f68", size = 236191, upload-time = "2026-02-04T21:50:36.239Z" }, - { url = "https://files.pythonhosted.org/packages/7c/d4/aeb5e1784d2c5bff6e189138a9ca91a090117459cea0c30378e1f2db3d54/pywinpty-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:c9081df0e49ffa86d15db4a6ba61530630e48707f987df42c9d3313537e81fc0", size = 2113098, upload-time = "2026-02-04T21:54:37.711Z" }, - { url = "https://files.pythonhosted.org/packages/b9/53/7278223c493ccfe4883239cf06c823c56460a8010e0fc778eef67858dc14/pywinpty-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:15e79d870e18b678fb8a5a6105fd38496b55697c66e6fc0378236026bc4d59e9", size = 234901, upload-time = "2026-02-04T21:53:31.35Z" }, - { url = "https://files.pythonhosted.org/packages/e5/cb/58d6ed3fd429c96a90ef01ac9a617af10a6d41469219c25e7dc162abbb71/pywinpty-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9c91dbb026050c77bdcef964e63a4f10f01a639113c4d3658332614544c467ab", size = 2112686, upload-time = "2026-02-04T21:52:03.035Z" }, - { url = "https://files.pythonhosted.org/packages/fd/50/724ed5c38c504d4e58a88a072776a1e880d970789deaeb2b9f7bd9a5141a/pywinpty-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:fe1f7911805127c94cf51f89ab14096c6f91ffdcacf993d2da6082b2142a2523", size = 234591, upload-time = "2026-02-04T21:52:29.821Z" }, - { url = "https://files.pythonhosted.org/packages/f7/ad/90a110538696b12b39fd8758a06d70ded899308198ad2305ac68e361126e/pywinpty-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:3f07a6cf1c1d470d284e614733c3d0f726d2c85e78508ea10a403140c3c0c18a", size = 2112360, upload-time = "2026-02-04T21:55:33.397Z" }, - { url = "https://files.pythonhosted.org/packages/44/0f/7ffa221757a220402bc79fda44044c3f2cc57338d878ab7d622add6f4581/pywinpty-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:15c7c0b6f8e9d87aabbaff76468dabf6e6121332c40fc1d83548d02a9d6a3759", size = 233107, upload-time = "2026-02-04T21:51:45.455Z" }, - { url = "https://files.pythonhosted.org/packages/28/88/2ff917caff61e55f38bcdb27de06ee30597881b2cae44fbba7627be015c4/pywinpty-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:d4b6b7b0fe0cdcd02e956bd57cfe9f4e5a06514eecf3b5ae174da4f951b58be9", size = 2113282, upload-time = "2026-02-04T21:52:08.188Z" }, - { url = "https://files.pythonhosted.org/packages/63/32/40a775343ace542cc43ece3f1d1fce454021521ecac41c4c4573081c2336/pywinpty-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:34789d685fc0d547ce0c8a65e5a70e56f77d732fa6e03c8f74fefb8cbb252019", size = 234207, upload-time = "2026-02-04T21:51:58.687Z" }, - { url = "https://files.pythonhosted.org/packages/8d/54/5d5e52f4cb75028104ca6faf36c10f9692389b1986d34471663b4ebebd6d/pywinpty-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:0c37e224a47a971d1a6e08649a1714dac4f63c11920780977829ed5c8cadead1", size = 2112910, upload-time = "2026-02-04T21:52:30.976Z" }, - { url = "https://files.pythonhosted.org/packages/0a/44/dcd184824e21d4620b06c7db9fbb15c3ad0a0f1fa2e6de79969fb82647ec/pywinpty-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:c4e9c3dff7d86ba81937438d5819f19f385a39d8f592d4e8af67148ceb4f6ab5", size = 233425, upload-time = "2026-02-04T21:51:56.754Z" }, -] - [[package]] name = "pyyaml" version = "6.0.3" @@ -3708,39 +3246,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/56/5d/c814546c2333ceea4ba42262d8c4d55763003e767fa169adc693bd524478/requests-2.33.0-py3-none-any.whl", hash = "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b", size = 65017, upload-time = "2026-03-25T15:10:40.382Z" }, ] -[[package]] -name = "rfc3339-validator" -version = "0.1.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, -] - -[[package]] -name = "rfc3986-validator" -version = "0.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760, upload-time = "2019-10-28T16:00:19.144Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242, upload-time = "2019-10-28T16:00:13.976Z" }, -] - -[[package]] -name = "rfc3987-syntax" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "lark" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239, upload-time = "2025-07-18T01:05:05.015Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046, upload-time = "2025-07-18T01:05:03.843Z" }, -] - [[package]] name = "rich" version = "14.3.3" @@ -3958,15 +3463,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/07/39/338d9219c4e87f3e708f18857ecd24d22a0c3094752393319553096b98af/scipy-1.17.1-cp314-cp314t-win_arm64.whl", hash = "sha256:200e1050faffacc162be6a486a984a0497866ec54149a01270adc8a59b7c7d21", size = 25489165, upload-time = "2026-02-23T00:22:29.563Z" }, ] -[[package]] -name = "send2trash" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c5/f0/184b4b5f8d00f2a92cf96eec8967a3d550b52cf94362dad1100df9e48d57/send2trash-2.1.0.tar.gz", hash = "sha256:1c72b39f09457db3c05ce1d19158c2cbef4c32b8bedd02c155e49282b7ea7459", size = 17255, upload-time = "2026-01-14T06:27:36.056Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1c/78/504fdd027da3b84ff1aecd9f6957e65f35134534ccc6da8628eb71e76d3f/send2trash-2.1.0-py3-none-any.whl", hash = "sha256:0da2f112e6d6bb22de6aa6daa7e144831a4febf2a87261451c4ad849fe9a873c", size = 17610, upload-time = "2026-01-14T06:27:35.218Z" }, -] - [[package]] name = "setuptools" version = "84.2.1" @@ -3994,15 +3490,6 @@ 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 = "soupsieve" -version = "2.9.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/99/a6ca3beb3ccacb41fb3321d8a60e5566f9e6467601ef8eba6a17e1b89778/soupsieve-2.9.2.tar.gz", hash = "sha256:4a55d8cf158a9c2e587fa4922f1bbb91d68ac829e2d6f25403a85747c71daf74", size = 122445, upload-time = "2026-08-07T00:57:24.801Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/dc/ad025c1ee131eba60c69f4dd5779b18fcf1e6b21a343e2162a84d5d133c7/soupsieve-2.9.2-py3-none-any.whl", hash = "sha256:8089a26fd974ca7a1f30276d3d8492ab266ab15af581642dfe8aa162e0c1c823", size = 37370, upload-time = "2026-08-07T00:57:23.524Z" }, -] - [[package]] name = "sqlfluff" version = "4.2.1" @@ -4074,20 +3561,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/be/5d2d47b1fb58943194fb59dcf222f7c4e35122ec0ffe8c36e18b5d728f0b/tblib-3.2.2-py3-none-any.whl", hash = "sha256:26bdccf339bcce6a88b2b5432c988b266ebbe63a4e593f6b578b1d2e723d2b76", size = 12893, upload-time = "2025-11-12T12:21:14.407Z" }, ] -[[package]] -name = "terminado" -version = "0.18.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ptyprocess", marker = "os_name != 'nt'" }, - { name = "pywinpty", marker = "os_name == 'nt'" }, - { name = "tornado" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701, upload-time = "2024-03-12T14:34:39.026Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, -] - [[package]] name = "tiktoken" version = "0.12.0" @@ -4142,18 +3615,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/af/df/c7891ef9d2712ad774777271d39fdef63941ffba0a9d59b7ad1fd2765e57/tiktoken-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f61c0aea5565ac82e2ec50a05e02a6c44734e91b51c10510b084ea1b8e633a71", size = 920667, upload-time = "2025-10-06T20:22:34.444Z" }, ] -[[package]] -name = "tinycss2" -version = "1.5.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "webencodings" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a3/ae/2ca4913e5c0f09781d75482874c3a95db9105462a92ddd303c7d285d3df2/tinycss2-1.5.1.tar.gz", hash = "sha256:d339d2b616ba90ccce58da8495a78f46e55d4d25f9fd71dfd526f07e7d53f957", size = 88195, upload-time = "2025-11-23T10:29:10.082Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/60/45/c7b5c3168458db837e8ceab06dc77824e18202679d0463f0e8f002143a97/tinycss2-1.5.1-py3-none-any.whl", hash = "sha256:3415ba0f5839c062696996998176c4a3751d18b7edaaeeb658c9ce21ec150661", size = 28404, upload-time = "2025-11-23T10:29:08.676Z" }, -] - [[package]] name = "tomli" version = "2.4.0" @@ -4324,15 +3785,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, ] -[[package]] -name = "uri-template" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678, upload-time = "2023-06-21T01:49:05.374Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140, upload-time = "2023-06-21T01:49:03.467Z" }, -] - [[package]] name = "urllib3" version = "2.8.0" @@ -4380,33 +3832,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad", size = 94189, upload-time = "2026-02-06T19:19:39.646Z" }, ] -[[package]] -name = "webcolors" -version = "25.10.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491, upload-time = "2025-10-31T07:51:03.977Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905, upload-time = "2025-10-31T07:51:01.778Z" }, -] - -[[package]] -name = "webencodings" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d5/a0/8fd707bcb776a7be556bad06a2ea5fb9bd519df78ef8e26f70ccf0f38bff/webencodings-0.6.1.tar.gz", hash = "sha256:565f9ad031c702dae404e27a099e3e09186a3ab1b9520f06d215502b651fd910", size = 15001, upload-time = "2026-08-15T14:22:57.549Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/c6/040cbc72480d789a5f40d63fb484d3106554c4dfa2d2b70ad5022057750f/webencodings-0.6.1-py3-none-any.whl", hash = "sha256:7fab6269c8bf237c657876b52058ccb182e861518d1c695c1a9aaa8c1c105d5b", size = 8745, upload-time = "2026-08-15T14:22:56.31Z" }, -] - -[[package]] -name = "websocket-client" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, -] - [[package]] name = "widgetsnbextension" version = "4.0.15"