From cb05c66b9e08503a59604d02204194ecf37bea2e Mon Sep 17 00:00:00 2001
From: John Major
Date: Tue, 26 May 2026 16:19:01 -0700
Subject: [PATCH 01/47] Add Bloom container runtime
---
.dockerignore | 16 +
Dockerfile | 42 +
bloom_lims/container_entry.py | 44 +
container_tests/test_container_runtime.py | 56 +
docker/entrypoint.sh | 16 +
uv.lock | 2815 +++++++++++++++++++++
6 files changed, 2989 insertions(+)
create mode 100644 .dockerignore
create mode 100644 Dockerfile
create mode 100644 bloom_lims/container_entry.py
create mode 100644 container_tests/test_container_runtime.py
create mode 100755 docker/entrypoint.sh
create mode 100644 uv.lock
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..bfaf8e3
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,16 @@
+.git
+.mypy_cache
+.pytest_cache
+.ruff_cache
+.venv
+__pycache__
+*.py[cod]
+build
+dist
+*.egg-info
+.coverage
+htmlcov
+tests
+docs/plans
+analytics
+stage_to_delete
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..046d925
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,42 @@
+# syntax=docker/dockerfile:1.7
+ARG PYTHON_VERSION=3.12
+
+FROM ghcr.io/astral-sh/uv:0.5.30-python${PYTHON_VERSION}-bookworm-slim AS builder
+
+ARG SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0
+ENV SETUPTOOLS_SCM_PRETEND_VERSION=${SETUPTOOLS_SCM_PRETEND_VERSION} \
+ UV_COMPILE_BYTECODE=1 \
+ UV_LINK_MODE=copy \
+ PYTHONDONTWRITEBYTECODE=1 \
+ PYTHONUNBUFFERED=1
+
+WORKDIR /app
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends build-essential libpq-dev \
+ && rm -rf /var/lib/apt/lists/*
+COPY pyproject.toml uv.lock README.md ./
+RUN uv sync --frozen --no-dev --no-install-project
+
+COPY bloom_lims ./bloom_lims
+COPY main.py ./main.py
+RUN uv sync --frozen --no-dev
+
+FROM python:${PYTHON_VERSION}-slim-bookworm AS runtime
+
+ENV PATH="/app/.venv/bin:${PATH}" \
+ PYTHONDONTWRITEBYTECODE=1 \
+ PYTHONUNBUFFERED=1
+
+RUN addgroup --system lsmc && adduser --system --ingroup lsmc --home /app lsmc
+WORKDIR /app
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends libpq5 \
+ && rm -rf /var/lib/apt/lists/*
+COPY --from=builder --chown=lsmc:lsmc /app /app
+COPY --chown=lsmc:lsmc docker/entrypoint.sh /entrypoint.sh
+RUN chmod 0755 /entrypoint.sh
+USER lsmc
+
+EXPOSE 8912
+ENTRYPOINT ["/entrypoint.sh"]
+CMD ["python", "-m", "bloom_lims.container_entry"]
diff --git a/bloom_lims/container_entry.py b/bloom_lims/container_entry.py
new file mode 100644
index 0000000..4011afc
--- /dev/null
+++ b/bloom_lims/container_entry.py
@@ -0,0 +1,44 @@
+"""Container foreground entrypoint for Bloom."""
+
+from __future__ import annotations
+
+import os
+from pathlib import Path
+
+def _required_env(name: str) -> str:
+ value = os.environ.get(name, "").strip()
+ if not value:
+ raise RuntimeError(f"{name} is required")
+ return value
+
+
+def _required_absolute_file(name: str) -> Path:
+ path = Path(_required_env(name))
+ if not path.is_absolute():
+ raise RuntimeError(f"{name} must be an absolute path")
+ if not path.is_file():
+ raise RuntimeError(f"{name} does not exist: {path}")
+ return path
+
+
+def _start_server(**kwargs: object) -> None:
+ from bloom_lims.cli.server import start
+
+ start(**kwargs)
+
+
+def main() -> None:
+ _required_absolute_file("BLOOM_CONFIG_PATH")
+ _start_server(
+ port=int(_required_env("PORT")),
+ host=_required_env("HOST"),
+ reload=False,
+ background=False,
+ ssl=False,
+ cert=None,
+ key=None,
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/container_tests/test_container_runtime.py b/container_tests/test_container_runtime.py
new file mode 100644
index 0000000..4f93a29
--- /dev/null
+++ b/container_tests/test_container_runtime.py
@@ -0,0 +1,56 @@
+from __future__ import annotations
+
+from pathlib import Path
+from unittest.mock import patch
+
+import pytest
+
+from bloom_lims import container_entry
+
+
+PROJECT_ROOT = Path(__file__).resolve().parents[1]
+
+
+def test_docker_runtime_files_use_foreground_uv_and_no_legacy_runtime() -> None:
+ dockerfile = (PROJECT_ROOT / "Dockerfile").read_text(encoding="utf-8")
+ entrypoint = (PROJECT_ROOT / "docker" / "entrypoint.sh").read_text(encoding="utf-8")
+
+ assert "uv sync --frozen --no-dev --no-install-project" in dockerfile
+ assert "uv sync --frozen --no-dev" in dockerfile
+ assert "USER lsmc" in dockerfile
+ assert "python\", \"-m\", \"bloom_lims.container_entry" in dockerfile
+ assert ":latest" not in dockerfile
+ assert "conda" not in dockerfile.lower()
+ assert "tmux" not in entrypoint
+ assert "background" not in entrypoint
+ assert "${BLOOM_CONFIG_PATH:?BLOOM_CONFIG_PATH is required}" in entrypoint
+
+
+def test_container_entry_requires_absolute_config_path(monkeypatch: pytest.MonkeyPatch) -> None:
+ monkeypatch.setenv("BLOOM_CONFIG_PATH", "relative.yaml")
+
+ with pytest.raises(RuntimeError, match="must be an absolute path"):
+ container_entry._required_absolute_file("BLOOM_CONFIG_PATH")
+
+
+def test_container_entry_runs_foreground_http_server(
+ tmp_path: Path, monkeypatch: pytest.MonkeyPatch
+) -> None:
+ config_path = tmp_path / "bloom.yaml"
+ config_path.write_text("auth: {}\n", encoding="utf-8")
+ monkeypatch.setenv("BLOOM_CONFIG_PATH", str(config_path))
+ monkeypatch.setenv("HOST", "127.0.0.1")
+ monkeypatch.setenv("PORT", "8912")
+
+ with patch("bloom_lims.container_entry._start_server") as start:
+ container_entry.main()
+
+ assert start.call_args.kwargs == {
+ "port": 8912,
+ "host": "127.0.0.1",
+ "reload": False,
+ "background": False,
+ "ssl": False,
+ "cert": None,
+ "key": None,
+ }
diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh
new file mode 100755
index 0000000..e44ed84
--- /dev/null
+++ b/docker/entrypoint.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env sh
+set -eu
+
+: "${LSMC_SERVICE_NAME:?LSMC_SERVICE_NAME is required}"
+: "${LSMC_ENV:?LSMC_ENV is required}"
+: "${LSMC_RUNTIME_CLASS:?LSMC_RUNTIME_CLASS is required}"
+: "${BLOOM_CONFIG_PATH:?BLOOM_CONFIG_PATH is required}"
+: "${HOST:?HOST is required}"
+: "${PORT:?PORT is required}"
+: "${OTEL_EXPORTER_OTLP_ENDPOINT:?OTEL_EXPORTER_OTLP_ENDPOINT is required}"
+
+export OTEL_SERVICE_NAME="${OTEL_SERVICE_NAME:-$LSMC_SERVICE_NAME}"
+export OTEL_RESOURCE_ATTRIBUTES="service.name=${OTEL_SERVICE_NAME},deployment.environment=${LSMC_ENV},service.version=${LSMC_RELEASE_SHA:-unknown}"
+export LOG_FORMAT="${LOG_FORMAT:-json}"
+
+exec "$@"
diff --git a/uv.lock b/uv.lock
new file mode 100644
index 0000000..6a24122
--- /dev/null
+++ b/uv.lock
@@ -0,0 +1,2815 @@
+version = 1
+revision = 3
+requires-python = ">=3.12"
+resolution-markers = [
+ "python_full_version >= '3.15' and sys_platform == 'win32'",
+ "python_full_version >= '3.15' and sys_platform == 'emscripten'",
+ "python_full_version >= '3.15' and sys_platform != 'emscripten' and sys_platform != 'win32'",
+ "python_full_version == '3.14.*' and sys_platform == 'win32'",
+ "python_full_version == '3.14.*' and sys_platform == 'emscripten'",
+ "python_full_version == '3.14.*' and sys_platform != 'emscripten' and sys_platform != 'win32'",
+ "python_full_version < '3.14' and sys_platform == 'win32'",
+ "python_full_version < '3.14' and sys_platform == 'emscripten'",
+ "python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
+]
+
+[[package]]
+name = "annotated-doc"
+version = "0.0.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" },
+]
+
+[[package]]
+name = "annotated-types"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
+]
+
+[[package]]
+name = "anyio"
+version = "4.13.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "idna" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" },
+]
+
+[[package]]
+name = "ast-serialize"
+version = "0.5.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/81/9d/09e27731bd5864a9ce04e3244074e674bb8936bf62b45e0357248717adac/ast_serialize-0.5.0.tar.gz", hash = "sha256:5880091bfe6f4f986f22866375c2e884843e7a0b6343ae41aeea659613d879b6", size = 61157, upload-time = "2026-05-17T17:48:29.429Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c0/9a/13dde51ba9e15f8b97957ab7cb0120d0e381524d651c6bd630b9c359227f/ast_serialize-0.5.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8f5c14f169eb0972c0c21bada5358b23d6047c76583b005234f865b11f1fa00a", size = 1183520, upload-time = "2026-05-17T17:47:30.831Z" },
+ { url = "https://files.pythonhosted.org/packages/37/de/5a7f0a9fe68944f536632a5af84676739c7d2582be42deb082634bf3a754/ast_serialize-0.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7d1a2de9de5be04652f0ed60738356ef94f66db37924a9499fffe98dc491aa0b", size = 1175779, upload-time = "2026-05-17T17:47:32.551Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/81/0bb853e76e4f6e9a1855d569003c59e19ffac45f7079d91505d1bb212f92/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be5173fb66f9b49026d9d5a2ff0fc7c7009077107c0eb285b2d60fdf1fe10bd1", size = 1233750, upload-time = "2026-05-17T17:47:34.731Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/d3/4cf705beeccc08754d0bbda99aefff26110e209b9a07ac8a6b60eec48531/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f8015cd071ac1339924ee2b8098c93e00e155f30a16f40ec9816fcf84f4753f6", size = 1235942, upload-time = "2026-05-17T17:47:36.287Z" },
+ { url = "https://files.pythonhosted.org/packages/26/c8/ee097e437ea27dd2b8b227865c875492b585650a5802a22d82b304c8201b/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5499e8797edff2a9186aa313ed382c6b422e798e9332d9953badcee6e69a88f2", size = 1442517, upload-time = "2026-05-17T17:47:38.17Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/bd/68063442838f1ba68ec72b5436430bc75b3bb17a1a3c3063f09b0c05ae2b/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6848f2a093fb5548751a9a09bff8fcd229e2bbeb0e3331f391b6ae6d26cd9903", size = 1254081, upload-time = "2026-05-17T17:47:39.826Z" },
+ { url = "https://files.pythonhosted.org/packages/50/e2/1e520793bc6a4e4524a6ab022391e827825eaa0c3811828bfdc6852eca26/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:832d4c998e0b091fd60a6d6bceee535483c4d490de9ba85003af835225719261", size = 1259910, upload-time = "2026-05-17T17:47:41.369Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/e1/49b60f467979979cfe6913b43948ff25bca971ad0591d181812f163a988e/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:16db7c62ec0b8efe1d7afd283a388d8f74f2605d56032e5a37747d2de8dba027", size = 1250678, upload-time = "2026-05-17T17:47:43.702Z" },
+ { url = "https://files.pythonhosted.org/packages/74/ba/66ab9555de6275677566f6574e5ef6c29cb185ea866f643bc06f8280a8ee/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:baf5eb061eb5bccade4128ad42da33787d72f6013809cd1b590376ece8b3c937", size = 1301603, upload-time = "2026-05-17T17:47:46.256Z" },
+ { url = "https://files.pythonhosted.org/packages/66/42/6aca9b9abc710014b2be9059689e5dd1679339e78f567ffb4d255a9e2050/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:104e4a35bd7c124173c41760ef9aaea17ddb3f86c65cb643671d59afbe3ee94c", size = 1410332, upload-time = "2026-05-17T17:47:47.899Z" },
+ { url = "https://files.pythonhosted.org/packages/47/68/2f76594432a22581ecf878b5e75a9b8601c24b2241cf0bbeb1e21fcf370c/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:36be371028fc1675acb38a331bde160dbab7ff907fdf00b67eb6911aa106951b", size = 1509979, upload-time = "2026-05-17T17:47:50.942Z" },
+ { url = "https://files.pythonhosted.org/packages/40/ac/a93c9b58292653f6c595752f677a08e608f903b710594909e9231a389b3b/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:061ee58bdb52341c8201a6df41182a977736bae3b7ded87ca7176ca25a8a47ab", size = 1505002, upload-time = "2026-05-17T17:47:54.093Z" },
+ { url = "https://files.pythonhosted.org/packages/14/2e/b278f68c497ee2f1d1576cbbef8db5281cd4a5f2db040537592ac9c8862e/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b15219e9cdc9f53f6f4cb51c009203507228226148c05c5e8fe451c28b435eb3", size = 1456231, upload-time = "2026-05-17T17:47:56.311Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/43/419be1c566a4c504cd8fd60ce2f84e790f295495c0f327cfaeadf3d51012/ast_serialize-0.5.0-cp314-cp314t-win32.whl", hash = "sha256:842d1c004bb466c7df036f95fabef789570541922b10976b12f5592a69cf0b38", size = 1058668, upload-time = "2026-05-17T17:47:58.305Z" },
+ { url = "https://files.pythonhosted.org/packages/03/6f/c9d4d549295ed05111aeb8853232d1afd9d0a179fddb01eeffbb3a4a6842/ast_serialize-0.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b0c06d760909b095cc466356dfccd05a1c7233a6ca191c020dca2c6a6f16c24c", size = 1101075, upload-time = "2026-05-17T17:48:00.35Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/8e/d00c5ab30c58222e07d62956fca86c59d91b9ad32997e633c38b526623a3/ast_serialize-0.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:787baedb0262cc49e8ce37cc15c00ae818e46a165a3b36f5e21ed174998104cb", size = 1075347, upload-time = "2026-05-17T17:48:01.753Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/9e/dc2530acb3a60dc6e46d65abf27d1d9f86721694757906a148d90a6860de/ast_serialize-0.5.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:0668aa9459cfa8c9c49ddd2163ebcf43088ba045ef7492af6fe22e0098303101", size = 1191380, upload-time = "2026-05-17T17:48:03.738Z" },
+ { url = "https://files.pythonhosted.org/packages/26/0a/bd3d18a582f273d6c843d16bb9e22e9e16365ff7991e92f18f798e9f1224/ast_serialize-0.5.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:bf683d6363edf2b39eed6b6d4fe22d34b6203867a67e27134d9e2a2680c4bc4a", size = 1183879, upload-time = "2026-05-17T17:48:05.463Z" },
+ { url = "https://files.pythonhosted.org/packages/40/ae/1f919100f8620887af58fcc381c61a1f218cdf89c6e155f87b213e61010a/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc22cf0c9be65e71cf88fda130af60d61eb4a79370ad4cfe7900d48a4aa2211", size = 1244529, upload-time = "2026-05-17T17:48:07.008Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/ca/6376559dcce707cdbc1d0d9a13c8d3baaaa501e949ce0ebdc4230cd881aa/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f66173891548c9f2726bf27957b41cabce12fa679dc6da505ddbde4d4b3b31cf", size = 1240560, upload-time = "2026-05-17T17:48:08.46Z" },
+ { url = "https://files.pythonhosted.org/packages/35/b2/a620e206b5aeb7efbf2710336df57d457cffbb3991076bbcc1147ef9abd4/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e42d729ef2be96a14efbad355093284739e3670ece3e534f82cc8832790911d9", size = 1451172, upload-time = "2026-05-17T17:48:09.922Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/e0/4ad5c04c24a40481b2935ce9a0ccdb6023dc8b667167d06ae530cc3512f2/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b725026bafa801dbd7310eb13a75f0a2e370e7e51b2cb225f9d21fcfadf919ee", size = 1265072, upload-time = "2026-05-17T17:48:11.469Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/71/4d1d479aa56d0101c40e17720c3d6ac2af7269ea0487a80b18e7bfd1a5b7/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b54f60c1d78767a53b67eaa663f0dfac3afe606aa07f1301572f588b73d64809", size = 1270488, upload-time = "2026-05-17T17:48:13.575Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/4f/0de1bbe06f6edef9fde4ed12ca8e7b3ec7e6e2bd4e672c5af487f7957665/ast_serialize-0.5.0-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:27d51654fc240a1e87e742d353d98eb45b75f62f129086b3596ab53df2ac2a43", size = 1260702, upload-time = "2026-05-17T17:48:15.141Z" },
+ { url = "https://files.pythonhosted.org/packages/75/61/e00872439cfdddcc3c1b6cdaa6e5d904ba8e26a18807c67c4e14409d0ca8/ast_serialize-0.5.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c36237c46dd1674542f2109740ea5ea485a169bf1431939ada0434e17934", size = 1311182, upload-time = "2026-05-17T17:48:16.779Z" },
+ { url = "https://files.pythonhosted.org/packages/76/8e/699a5b955f7926956c95e9e1d74132acad73c2fe7a426f94da89123c20aa/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1943db345233cc7194a470f13afa9c59772c0b123dea0c9414c4d4ca54369759", size = 1421410, upload-time = "2026-05-17T17:48:18.527Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/ae/d5b7626874478997adc7a29ab28accf21e596fb590c944290401dfd0b29e/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:df1c00022cbbcb064bfaa505aa9c9295362443ce5dacb459d1331d3da353f887", size = 1516587, upload-time = "2026-05-17T17:48:20.133Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/ce/b59e02a82d9c4244d64cde502e0b00e83e38816abe19155ceb5437402c7f/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:cae65289fc456fde04af979a2be09302ef5d8ab92ef23e596d6746dc267ada27", size = 1515171, upload-time = "2026-05-17T17:48:21.921Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/38/d8d90042747d05aa08d4efcf1c99035a5f670a6bf4c214d31644392afbca/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:239a4c354e8d676e9d94631d1d4a64edc6b266f86ff3a5a80aedd344f342c01d", size = 1464668, upload-time = "2026-05-17T17:48:23.544Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/51/5b840c4df7334104cecffa28f23904fe81ca89ca223d2450e288de39fd3c/ast_serialize-0.5.0-cp39-abi3-win32.whl", hash = "sha256:143a4ef63285a075871908fda3672dc21864b83a8ec3ee12304aa3e4c5387b9a", size = 1068311, upload-time = "2026-05-17T17:48:25.027Z" },
+ { url = "https://files.pythonhosted.org/packages/41/11/ca5672c7d491825bc4cd6702dea106a6b60d928707712ec257c7833ae476/ast_serialize-0.5.0-cp39-abi3-win_amd64.whl", hash = "sha256:cf25572c526add400f26a4750dc6ce0c3bb93fc1f75e7ae0cad4ce4f2cd5c590", size = 1108931, upload-time = "2026-05-17T17:48:26.591Z" },
+ { url = "https://files.pythonhosted.org/packages/45/19/cc8bd127d28a43da249aa955cfd164cf8fd534e79e42cea96c4854d72fd0/ast_serialize-0.5.0-cp39-abi3-win_arm64.whl", hash = "sha256:92a31c9c20d25a076edaeec76b128a3535d74a24f340b9a8a7e96c9b86dc9642", size = 1081181, upload-time = "2026-05-17T17:48:28.122Z" },
+]
+
+[[package]]
+name = "asttokens"
+version = "3.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" }
+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 = "attrs"
+version = "26.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" },
+]
+
+[[package]]
+name = "bandit"
+version = "1.9.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "pyyaml" },
+ { name = "rich" },
+ { name = "stevedore" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/aa/c3/0cb80dfe0f3076e5da7e4c5ad8e57bac6ac357ff4a6406205501cade4965/bandit-1.9.4.tar.gz", hash = "sha256:b589e5de2afe70bd4d53fa0c1da6199f4085af666fde00e8a034f152a52cd628", size = 4242677, upload-time = "2026-02-25T06:44:15.503Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/05/a4/a26d5b25671d27e03afb5401a0be5899d94ff8fab6a698b1ac5be3ec29ef/bandit-1.9.4-py3-none-any.whl", hash = "sha256:f89ffa663767f5a0585ea075f01020207e966a9c0f2b9ef56a57c7963a3f6f8e", size = 134741, upload-time = "2026-02-25T06:44:13.694Z" },
+]
+
+[[package]]
+name = "black"
+version = "26.5.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+ { name = "mypy-extensions" },
+ { name = "packaging" },
+ { name = "pathspec" },
+ { name = "platformdirs" },
+ { name = "pytokens" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c0/37/5628dd55bf2b34257fc7603f0fe97c40e3aaf24265f416a9c85c95ca1436/black-26.5.1.tar.gz", hash = "sha256:dd321f668053961824bcc1be1cc1df748b2d7e4fa28086b08331e577b0100a73", size = 679439, upload-time = "2026-05-18T16:53:36.107Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/24/99/7744b906703228264ef73bdd534df88ec1ef3de45c4e78f6d31b9e32d0c9/black-26.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4ad6fa01f941920f54f2bbb35f3df7673428a0ef98a0b0840c2eaef3b110efa8", size = 2012518, upload-time = "2026-05-18T17:05:20.108Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/c0/c5a3b1636dfd09c42534f2b3cf33506814f6d3e066fb0879ffa16c1ae860/black-26.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3915f256e75a2d7cf88d8953d37f780455dc586cc72dee059c528fe77f581217", size = 1816016, upload-time = "2026-05-18T17:05:21.84Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/0e/36044316b65ca471d3bb6d3703fd06fb50c6b727c3562f6a5a3153634f88/black-26.5.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d98d4137277c75dfb898ec8d846c4fd68ba1e9cf77f95e2865c203dc18f4c3d", size = 1884150, upload-time = "2026-05-18T17:05:23.546Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/33/dafc5808c2af43672912111d7c3354af1615f7e2be3bed7a878461abbe4d/black-26.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:a1dca32d9f1784af512a13410ec204c6f7f0aa9797a111c42e1c03449821c264", size = 1486825, upload-time = "2026-05-18T17:05:25.004Z" },
+ { url = "https://files.pythonhosted.org/packages/82/14/b965ee6ad2a311f28bdbf692def3ee9848d2ae289dab28b27657fcee3e78/black-26.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:1037d5ac7b7b310b2632ad867ec8d0e4c4819dcdb0b820f63135da746a24e418", size = 1288646, upload-time = "2026-05-18T17:05:26.477Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/5c/c384363980e11e25ca6b93205949bb331fbf35f4e0dbec376dfa6326cec8/black-26.5.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2b36cf2ddf5566e205f6535f782a62194a184d33e175b64ae8c40b1737522be3", size = 2009020, upload-time = "2026-05-18T17:05:28.132Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/df/9f31c5e0babbfed77d505fc5d120beb98b21b33feaeded3924ea941fe360/black-26.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f7ea64ebfa01b50f693508fc39f875e264446d3b097088f84f203b9d09618a0", size = 1813335, upload-time = "2026-05-18T17:05:31.266Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/24/8e7b9a2fa61b0afd82209efe937557d180a1fa055bd7f6161eb9defc3719/black-26.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecb3e624844c798144e9bd986954e0adc81d8911a1f30f375e1252fe26e8c294", size = 1881614, upload-time = "2026-05-18T17:05:32.718Z" },
+ { url = "https://files.pythonhosted.org/packages/49/ad/b4e0d9365ba8ac34f6bbab62a4b1b2dd5d618fac3fa1b8db968c844201b5/black-26.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:e1a26503279b6b310669fb0b219c39e4820b77e8189fe80f522bb511f247db0a", size = 1488925, upload-time = "2026-05-18T17:05:34.259Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/4b/652b859bf5df88a751c30451b09338f7fd26a77d1271c666992f836b7711/black-26.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c34b25da232ead53a6f335b76dbea124f4d152ad568b9080d6f944bc2b34b52", size = 1289883, upload-time = "2026-05-18T17:05:36.019Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/16/a8da8eb208c51c7f4ce74609a45d0dcc6d8a2141e45e81ee5289d1bb0d59/black-26.5.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e88976690a64b0af98312ca958415849cb42423423c5f2ee74af4b49a97a2168", size = 2004800, upload-time = "2026-05-18T17:05:38.182Z" },
+ { url = "https://files.pythonhosted.org/packages/11/8a/a479296a19e383b70a725882a6cf3d786540601ff03cabbaaf1cce864c5a/black-26.5.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32d5ea7f6c8bdfa6e648326ebca1f02b0764e2a029edc6f8dce2627e19d468c3", size = 1815576, upload-time = "2026-05-18T17:05:40.309Z" },
+ { url = "https://files.pythonhosted.org/packages/81/6b/cfaf3d39f25132c156a068f6b805576c9103a84086019507c70e1911ee7d/black-26.5.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ea8d16dc41655aa113cd64665e7219446cd7e4ff2248d7178eaa905190c86b18", size = 1877927, upload-time = "2026-05-18T17:05:42.463Z" },
+ { url = "https://files.pythonhosted.org/packages/66/76/302e313964bcff7e28df329d39f84f5270095730d85ff0acc260610a0d82/black-26.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:577f21094ea469ef92ec1adaf2c9441a226d2144d01a5be2fa823cecf6543e50", size = 1511860, upload-time = "2026-05-18T17:05:43.943Z" },
+ { url = "https://files.pythonhosted.org/packages/27/4e/a3827e35e0e567f9f9ee59e2a0ab979267dca98718f25547ca8c6733afd4/black-26.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:ed1a20af114c301a0269bf01163d51dbef72737fd65f850001e7cbe7f3c7abae", size = 1316632, upload-time = "2026-05-18T17:05:45.521Z" },
+ { url = "https://files.pythonhosted.org/packages/94/51/f975cae76d44274cc2868dc9040ac5d58d464784610234455b4e7b19c6ef/black-26.5.1-py3-none-any.whl", hash = "sha256:4ed7f7da04046d2e488437170797d3b4a4ad83906683bcb7dfc68b673bbce5e2", size = 213693, upload-time = "2026-05-18T16:53:33.964Z" },
+]
+
+[[package]]
+name = "bloom-lims"
+source = { editable = "." }
+dependencies = [
+ { name = "bandit" },
+ { name = "black" },
+ { name = "boto3" },
+ { name = "cli-core-yo" },
+ { name = "daylily-auth-cognito" },
+ { name = "daylily-carrier-tracking" },
+ { name = "daylily-tapdb" },
+ { name = "djlint" },
+ { name = "fastapi" },
+ { name = "httpx" },
+ { name = "ipython" },
+ { name = "itsdangerous" },
+ { name = "jinja2" },
+ { name = "matplotlib" },
+ { name = "moto" },
+ { name = "mypy" },
+ { name = "pandas" },
+ { name = "playwright" },
+ { name = "pre-commit" },
+ { name = "psutil" },
+ { name = "psycopg2" },
+ { name = "pydantic" },
+ { name = "pydantic-settings" },
+ { name = "pyjwt" },
+ { name = "pytest" },
+ { name = "pytest-asyncio" },
+ { name = "pytest-cov" },
+ { name = "pytest-playwright" },
+ { name = "python-multipart" },
+ { name = "pyyaml" },
+ { name = "requests" },
+ { name = "requests-mock" },
+ { name = "rich" },
+ { name = "ruff" },
+ { name = "sqlalchemy" },
+ { name = "starlette" },
+ { name = "uvicorn" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "bandit", extras = ["toml"], specifier = ">=1.8.0" },
+ { name = "black", specifier = ">=24.0.0" },
+ { name = "boto3", specifier = ">=1.34.0" },
+ { name = "cli-core-yo", specifier = "==2.1.1" },
+ { name = "daylily-auth-cognito", specifier = "==2.1.5" },
+ { name = "daylily-carrier-tracking", specifier = "==0.5.1" },
+ { name = "daylily-tapdb", specifier = ">=7.0.5,<8.0.0" },
+ { name = "djlint" },
+ { name = "fastapi", specifier = ">=0.110.0" },
+ { name = "httpx", specifier = ">=0.27.2" },
+ { name = "ipython", specifier = ">=8.18.1" },
+ { name = "itsdangerous", specifier = ">=2.1.2" },
+ { name = "jinja2", specifier = ">=3.0.3" },
+ { name = "matplotlib", specifier = ">=3.8.0" },
+ { name = "moto", specifier = ">=5.0.0" },
+ { name = "mypy", specifier = ">=1.0" },
+ { name = "pandas", specifier = ">=2.2.0" },
+ { name = "playwright", specifier = ">=1.42.0" },
+ { name = "pre-commit", specifier = ">=3.8.0" },
+ { name = "psutil", specifier = ">=5.9.0" },
+ { name = "psycopg2", specifier = "==2.9.9" },
+ { name = "pydantic", specifier = ">=2.6.0" },
+ { name = "pydantic-settings", specifier = ">=2.0.0" },
+ { name = "pyjwt", specifier = ">=2.8.0" },
+ { name = "pytest", specifier = ">=8.0" },
+ { name = "pytest-asyncio", specifier = ">=0.23.0" },
+ { name = "pytest-cov", specifier = ">=4.1.0" },
+ { name = "pytest-playwright", specifier = ">=0.4.4" },
+ { name = "python-multipart", specifier = ">=0.0.9" },
+ { name = "pyyaml", specifier = ">=6.0" },
+ { name = "requests", specifier = ">=2.28.2" },
+ { name = "requests-mock", specifier = ">=1.11.0" },
+ { name = "rich", specifier = ">=13.0" },
+ { name = "ruff", specifier = ">=0.1.0" },
+ { name = "sqlalchemy", specifier = ">=2.0.23" },
+ { name = "starlette", specifier = ">=0.35.1" },
+ { name = "uvicorn", specifier = ">=0.28.0" },
+]
+
+[[package]]
+name = "boto3"
+version = "1.43.15"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "botocore" },
+ { name = "jmespath" },
+ { name = "s3transfer" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4f/1f/ef8f2967570c221681056134d02e70ebd490b795c17cf44d52f898344fbd/boto3-1.43.15.tar.gz", hash = "sha256:8dbb1a129c693313218a099d4f086f3bb48f50159b74b5bd8869e1037fde4101", size = 113161, upload-time = "2026-05-26T19:45:14.203Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/af/8f/373833a5ca86f5b89c7d918c6130aece8d5e43b0c8bdbefac75145abf3f3/boto3-1.43.15-py3-none-any.whl", hash = "sha256:67510ef57a79f0d53b963b0dd1d1741d1e3de1eb2ef6cf1737b6a6bddd34b8cb", size = 140537, upload-time = "2026-05-26T19:45:11.152Z" },
+]
+
+[[package]]
+name = "botocore"
+version = "1.43.15"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "jmespath" },
+ { name = "python-dateutil" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/93/06/4eb6a40f2a5861cd48743765a80e5a6534f26ec0e9884502572cfadeca50/botocore-1.43.15.tar.gz", hash = "sha256:eed2e24962af03ec361a1dc6924f6b2cff0215a0a2f5c690eab655f43d1f700f", size = 15383526, upload-time = "2026-05-26T19:44:57.627Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/51/34/dfdd494cf22a88be269bcf648d28a65f85dcc0f914f52a02f8e740d6ccaf/botocore-1.43.15-py3-none-any.whl", hash = "sha256:bda4923998d1bf17f8eb6bc767a0923fbb9e525ecd50f839b041e469b46e1c94", size = 15063140, upload-time = "2026-05-26T19:44:54.54Z" },
+]
+
+[[package]]
+name = "certifi"
+version = "2026.5.20"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" },
+]
+
+[[package]]
+name = "cffi"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pycparser", marker = "implementation_name != 'PyPy'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" },
+ { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" },
+ { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" },
+ { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" },
+ { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" },
+ { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" },
+ { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" },
+ { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" },
+ { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" },
+ { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" },
+ { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
+ { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" },
+ { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
+ { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
+]
+
+[[package]]
+name = "cfgv"
+version = "3.5.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" }
+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/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 = "cli-core-yo"
+version = "2.1.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+ { name = "rich" },
+ { name = "typer" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/40/6e/2d5b690639e684483b55633f88a68280b96a87cc00a87e860f784701e31c/cli_core_yo-2.1.1.tar.gz", hash = "sha256:cc73bc220e48051843294f4d4d97067492ce01b41b961a1da23ad6af39153c86", size = 63822, upload-time = "2026-04-27T14:49:18.808Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3b/15/d7b7e1de008ba81968c56ad6a7e609c72cba38dca284638c720262ce807c/cli_core_yo-2.1.1-py3-none-any.whl", hash = "sha256:c23685086fa2f96ebdcf6fbf64f3a6d7fb96ce8a8a7c262a7f52cadbc2b139e1", size = 36913, upload-time = "2026-04-27T14:49:17.506Z" },
+]
+
+[[package]]
+name = "click"
+version = "8.4.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9b/98/518d8e5081007684232226f475082b30087d0f585e8457db087298259f49/click-8.4.1.tar.gz", hash = "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96", size = 353007, upload-time = "2026-05-22T04:08:37.769Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" },
+]
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
+]
+
+[[package]]
+name = "contourpy"
+version = "1.3.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" },
+ { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" },
+ { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" },
+ { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" },
+ { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" },
+ { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" },
+ { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" },
+ { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" },
+ { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" },
+ { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" },
+ { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" },
+ { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" },
+ { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" },
+ { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" },
+ { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" },
+ { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" },
+ { url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" },
+ { url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871, upload-time = "2025-07-26T12:02:20.418Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264, upload-time = "2025-07-26T12:02:21.916Z" },
+ { url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819, upload-time = "2025-07-26T12:02:23.759Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650, upload-time = "2025-07-26T12:02:26.181Z" },
+ { url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833, upload-time = "2025-07-26T12:02:28.782Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692, upload-time = "2025-07-26T12:02:30.128Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424, upload-time = "2025-07-26T12:02:31.395Z" },
+ { url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300, upload-time = "2025-07-26T12:02:32.956Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769, upload-time = "2025-07-26T12:02:34.2Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892, upload-time = "2025-07-26T12:02:35.807Z" },
+ { url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748, upload-time = "2025-07-26T12:02:37.193Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554, upload-time = "2025-07-26T12:02:38.894Z" },
+ { url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118, upload-time = "2025-07-26T12:02:40.642Z" },
+ { url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555, upload-time = "2025-07-26T12:02:42.25Z" },
+ { url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295, upload-time = "2025-07-26T12:02:44.668Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027, upload-time = "2025-07-26T12:02:47.09Z" },
+ { url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428, upload-time = "2025-07-26T12:02:48.691Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331, upload-time = "2025-07-26T12:02:50.137Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831, upload-time = "2025-07-26T12:02:51.449Z" },
+]
+
+[[package]]
+name = "coverage"
+version = "7.14.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/54/fd/0ab2772530e946e1be1abd0bc09e647ec9b02e88f0867857601fefca8953/coverage-7.14.1.tar.gz", hash = "sha256:30c08f7d90415aa98b3c990385dea2939b0da55f38515e5b369b83655f8523be", size = 920132, upload-time = "2026-05-26T20:41:36.783Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3d/b7/bdbb725ba02c5b42825b200c940f38b7a54fcad24627b7192f78f8110d76/coverage-7.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a06c76364a9360e33d6d23769aefdf7f66f38e2ffb60ceb1baaa4989d83b695c", size = 220022, upload-time = "2026-05-26T20:39:03.702Z" },
+ { url = "https://files.pythonhosted.org/packages/72/81/fdc0898a55c6219223291ec1a1fe89966ef212ce82276aa0899df84b5de0/coverage-7.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fad54e871165f6ec2f536063ac74c3104508a12963e64072ba44bd822de52b0c", size = 220379, upload-time = "2026-05-26T20:39:05.381Z" },
+ { url = "https://files.pythonhosted.org/packages/de/72/de048c4a25e13bce59ac6a339351c10bdf2515e07459afcdaf04dc3143a2/coverage-7.14.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:84b535f00655ecafe1d929d1fb00ed5d6fa3051ea643ab2c161a3887b86f294b", size = 251888, upload-time = "2026-05-26T20:39:07.367Z" },
+ { url = "https://files.pythonhosted.org/packages/28/30/300c343f68beb9d4cbb64ec81e58c5b6b80b56927f72d2b38654ac26e013/coverage-7.14.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6b6b0853b895fe0e98cbfc580d1ec3393d9302b4b1e96a77b3f5c91fdab899e6", size = 254624, upload-time = "2026-05-26T20:39:09.037Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/ed/7b25642496e8170b6bac14adce00537c6e5fa2d586159401a4de3e8b49e6/coverage-7.14.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:442cc9c952b2df400cda54bb04ab87330cf2cd08a8692cbbea36773531eb6f37", size = 255739, upload-time = "2026-05-26T20:39:10.889Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/a2/abd210b8c4e29c24e4624916db97bb519097a91034aaeb767f937e7da794/coverage-7.14.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8270544c361ed405a27a060dbc9ed2c124b084d96dfdc2d9a2510482aef981ad", size = 257998, upload-time = "2026-05-26T20:39:12.722Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/24/7c50beed3792fe62f6ce0545c6686ce83379719e2c0276179333d97eae92/coverage-7.14.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:48b283b1dd6372e8de2a7a9a4c4d5dc06f4d4fd209b876f3c88a7a205a0c8f84", size = 252296, upload-time = "2026-05-26T20:39:14.259Z" },
+ { url = "https://files.pythonhosted.org/packages/15/05/0f874628ebcbfc77ead559ff210281ef06a97db08481832e7dd39274a135/coverage-7.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5b0c99ba93a07d56f6df340bb79be53202a082b2fdb81bfe6190b741a3470d54", size = 253658, upload-time = "2026-05-26T20:39:15.923Z" },
+ { url = "https://files.pythonhosted.org/packages/99/6f/ca6ad067364b337ef997802115e7ecad2abd2248b05471464b0dea02b4d4/coverage-7.14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e471bc5769ff073b058cfadb0d736b56ce067c8560eabeb0da88462df98c23e7", size = 251803, upload-time = "2026-05-26T20:39:17.537Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/30/b9b4d377cd9f40baf228068f5a81faf8450c6228503011bd499708483a50/coverage-7.14.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f497a1ea81d4cd7c10ddcaa685135b9aabd291af3d55775a9ddf3cb7a364cdd9", size = 255873, upload-time = "2026-05-26T20:39:19.414Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/21/7c721a9e5e6bb88547d30a787aefb97512d3f54c1324c7488d9b3743f7f9/coverage-7.14.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2222be86d0b54f5dd5a38f45f17f315f737245e857bf0bdedc70734f84a13c02", size = 251372, upload-time = "2026-05-26T20:39:21.169Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/8c/f8ae5a2200130e1503cd7661a6cd3b2b7bacef98277fbf3571fb13f8b766/coverage-7.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:85e85586565842f6932abebd4c18bcb1074223dc0b3576e7d173ca710622813a", size = 253245, upload-time = "2026-05-26T20:39:23.097Z" },
+ { url = "https://files.pythonhosted.org/packages/34/62/70a9024672a5f6910517d9628c52c9afbdd3cf8f46426af52bb148a56fff/coverage-7.14.1-cp312-cp312-win32.whl", hash = "sha256:4a28fd227808366b196a75476dced2eb35b351d6766ba9c858dc93319e87f4f1", size = 222567, upload-time = "2026-05-26T20:39:24.868Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/81/8b7cd386839b039ebe1855733b9f9449a8dec5d79564018234f185a7fa70/coverage-7.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:54acdb6674a4661768d7bf7db32dfb9f46ab1d764f8aba6df75ce1a6a088724e", size = 223372, upload-time = "2026-05-26T20:39:26.603Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/ba/b44d472022f620d289d95fa830143235c0c36461c6f2437ea8d51e5481ed/coverage-7.14.1-cp312-cp312-win_arm64.whl", hash = "sha256:99cd41ff91afd94896fea3bc002706b6ae4ce95727d06e4a0f39c0a8d8bd8b1a", size = 221989, upload-time = "2026-05-26T20:39:28.242Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/9e/5f6d56327c62b185225d145191c607e07515294a0aa6338e58805cd4a5ac/coverage-7.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:be9f2c802dcfce3f71298303aa5dad0dce440a76c52f2f60dacd8656dab78793", size = 220044, upload-time = "2026-05-26T20:39:29.902Z" },
+ { url = "https://files.pythonhosted.org/packages/75/92/e82aca356744cbbc0f77a0b623e38918c1872361963413a3bab5d0340393/coverage-7.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6223a72fd0e4c7156353ec0f08a5f93623e1d3034d0e2683b9bb8ea674131b1d", size = 220412, upload-time = "2026-05-26T20:39:31.561Z" },
+ { url = "https://files.pythonhosted.org/packages/27/c9/385bde0bf7ed0f4bf3a7ee5367060a86b5d218718cfd6fb943c0f836b34f/coverage-7.14.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7279d2110a28cebc738b6459ecda2771735a4c18465fbbd36b3288fe5ed92247", size = 251412, upload-time = "2026-05-26T20:39:33.337Z" },
+ { url = "https://files.pythonhosted.org/packages/51/8c/23faf6a2343a0d17f960a4bd56c43bc7eb4cf312f774dd6ceebd82c7d8fc/coverage-7.14.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9eeb3fcbc13ba40dfbdb22d01d196a28e9cef9ed4c29b60061a1e0e823a9929d", size = 254008, upload-time = "2026-05-26T20:39:35.009Z" },
+ { url = "https://files.pythonhosted.org/packages/42/06/36f4aa9ca8a815e6036156e80706a67828bb97bd826948244f6996dda957/coverage-7.14.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f0cfc27c539f07cf5c0a4cfe211d0b6cae039f8f40526dbaa71944e64b50a7b", size = 255241, upload-time = "2026-05-26T20:39:36.71Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/79/95266316352f90f6b1c6736bb413302edfde2453fb32422d3911642691b3/coverage-7.14.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:221c70f316241a78e77e607c227cefc8808d4e08f28d99c04f35694690e940be", size = 257373, upload-time = "2026-05-26T20:39:38.412Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/9c/58316d1f66c488b5fca8a0eb3e98348807813efa8a0d0833b9021be27488/coverage-7.14.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:da028256b04ec30e5e0114b6f76172938c313991f0a2d3d894271315cf5d5e43", size = 251635, upload-time = "2026-05-26T20:39:40.268Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/5a/ca2398a568e16fed7bb713e84ba3603a7164fb65779abe645c565ec890d5/coverage-7.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76a085d7005236a767e3426148b2c407e53ad61695c562f8a81da2d373324901", size = 253373, upload-time = "2026-05-26T20:39:42.145Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/2c/0396562c32deaebe7be51d865b3a41e9a87d7561acafe1a28f53b07e019a/coverage-7.14.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b553d04b5e778a8e56d57eb134aff42a92718ecba45e79c4764ecfa40efd92ff", size = 251341, upload-time = "2026-05-26T20:39:43.907Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/8f/a94f9221184c9cae1ee115820e3798e48b6b17777a9f19e46fb9a0c8dc74/coverage-7.14.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:46f714d2fb8ae2f4f29f23ada7f1e79b759fff5a70f94a1dac23af204c3ec9e4", size = 255497, upload-time = "2026-05-26T20:39:46.166Z" },
+ { url = "https://files.pythonhosted.org/packages/71/69/505d70e47db1eaebcd002c39759707621ef184cd6b1ae084d9f41293f323/coverage-7.14.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:1896f5e19ff3f0431c7ce2172adc54890fd97f86b59ced8ca1649145d9ffe35d", size = 251159, upload-time = "2026-05-26T20:39:48.03Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/aa/58681c383aa33a9d2ed40a02d7a22fbf780d1fa4d575396365777828198c/coverage-7.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:62fd185ef9df3c33d1c8178c5af105f762afbad96038de9a4ae100aa6297ca33", size = 252934, upload-time = "2026-05-26T20:39:49.872Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/fd/11c928cd6bdffc7074bb5965c173d9ebf517fb00205e1da524b98d29ef92/coverage-7.14.1-cp313-cp313-win32.whl", hash = "sha256:ab4af6352741a604c431c6072fce5bee33bf0f20dc7a56618d6bf6bb89e9810c", size = 222584, upload-time = "2026-05-26T20:39:51.68Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/92/fb416fc26d340dcba19518c418d6048e913186e17243982c5e435e41fa7a/coverage-7.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:7af486dabe8954d03b087f0021540897afe084f04e16ff5579e08cc46f871416", size = 223394, upload-time = "2026-05-26T20:39:53.472Z" },
+ { url = "https://files.pythonhosted.org/packages/73/c6/02d56e3867972f77d5036de924643f26c056e848f00452cafb4dbc3c29b4/coverage-7.14.1-cp313-cp313-win_arm64.whl", hash = "sha256:2224f89ffd0c5605ccce1ed7a584da162bc7c55f601ab1c946bc9de31a486b42", size = 222015, upload-time = "2026-05-26T20:39:55.374Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/9e/fcc77914050df73f7662fa1f00902774c79c075a8388ab334074574bf77e/coverage-7.14.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:de286598cc65d2b489411174b1faec2f5a7775fb3201fd925db2a76b4030f37d", size = 220733, upload-time = "2026-05-26T20:39:57.189Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/67/2963cbdaf5cbadec44efa3a1e39eaa1f02df4079585f05387607a221e126/coverage-7.14.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:042c46ded7c288aeb07cf14a28b6c1e10b78fcba40171c3fa1e939377eeef0b5", size = 221086, upload-time = "2026-05-26T20:39:59.019Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/c5/8701645574e11881f2f47d8930f98bc48b5d43b25eb5b4430dfc4a2f9f48/coverage-7.14.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f4ddbe407477f04c45115d1a4e5bc480f753553b534d338d4c3358b1cdd0ea52", size = 262381, upload-time = "2026-05-26T20:40:00.822Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/28/7a64d73598263e0c5abd5084211a8474488d31b3c552ff531c719dfcff62/coverage-7.14.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d13e6725992e2d2fd7d81d4f5241952d13740121dfd501da09201be39b2c003a", size = 264458, upload-time = "2026-05-26T20:40:02.506Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/d8/4969179db9f7eb4df218e69540adf829d1c835f59452513d065d15446802/coverage-7.14.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f747dc8edcfe740130f28f32f3995e955494285717e86ee25af51db2219df08a", size = 266884, upload-time = "2026-05-26T20:40:04.421Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/78/a45d5794dbc9bafd97afc96a4377c86c7820d78b6cf51b89bc1d4e919275/coverage-7.14.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ced2f09ef276fd58611a1ef502164ad266d2b75174e5a40cabbdb4033f9f6cf2", size = 268022, upload-time = "2026-05-26T20:40:06.298Z" },
+ { url = "https://files.pythonhosted.org/packages/21/cb/4f5e354e9e3e67af96bd4e57113e6db6b22298c7168b13eec408a549903d/coverage-7.14.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b84800013769a78ccb9ef4659402e26d06867e337b61ec365f77ad008adea80e", size = 261631, upload-time = "2026-05-26T20:40:08.226Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/49/eced49af4cb996d5d8b7e94e736175c513e4facd3398507b89892b4326d8/coverage-7.14.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ea8cd6ca0ee9f616aaef3afc6882e32c2cbf18b00d96313ffd76af650574034d", size = 264443, upload-time = "2026-05-26T20:40:10.137Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/d8/5603a88a7c5913a6b54f6cb1a8c46f7b39cbb30f27cd3f492908da09b2d7/coverage-7.14.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:aa5e304a873fabddc11e484e9b6b738bd38bd7bed17b09aa84eecf5332e8b8bb", size = 262069, upload-time = "2026-05-26T20:40:11.999Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/59/2ae3cb79da554a06c8619d6c88ea19dd1e4aed4b834b6a83bb1fa243bdc5/coverage-7.14.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5a1c5215be81035e629d5bc756650634d0bf31991038db7a0eccb90f025ce16d", size = 265780, upload-time = "2026-05-26T20:40:13.858Z" },
+ { url = "https://files.pythonhosted.org/packages/af/5f/b130c1dc999031f2648bd25317fbce505ad8d5562079b4ed81e736a84967/coverage-7.14.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:79058c47dae6788504b5effb319961bcd72d7240551464b91d474bc0ed186d69", size = 260970, upload-time = "2026-05-26T20:40:16.142Z" },
+ { url = "https://files.pythonhosted.org/packages/87/d1/ec13ccddeb48ec963bdfa72a11224bac2584bd045ba13beca82f8113e9c7/coverage-7.14.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:370c5afae3fa0658e11694a32b24c2778f6bc2d17718121f94ee185e69f26b54", size = 263157, upload-time = "2026-05-26T20:40:18.382Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/c2/cd91ead503045161092d3845f7bb95ea2f25131ce96d3e314dd835d91b9c/coverage-7.14.1-cp313-cp313t-win32.whl", hash = "sha256:3758dd0a7f1fa57365ef2e781df0f0731d38b6e3772259d13dae4bd8a958d4b1", size = 223259, upload-time = "2026-05-26T20:40:20.381Z" },
+ { url = "https://files.pythonhosted.org/packages/71/9f/1e28d97e6bd2c76b07f38b7c02870f1371255ff6717f54eca578fcbbdd0e/coverage-7.14.1-cp313-cp313t-win_amd64.whl", hash = "sha256:6ff665fb023a77386fe11685190cee1f60a7d635994a30d9b0a061533d470fce", size = 224320, upload-time = "2026-05-26T20:40:22.316Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/e0/d936e908f0e1efa55e52b91e01b52f1055cef5e1ab2718493390ed8e2fb8/coverage-7.14.1-cp313-cp313t-win_arm64.whl", hash = "sha256:17a5a241e5997621a956a7f402a7433ef4221e5152809b785bec79e2323799f1", size = 222577, upload-time = "2026-05-26T20:40:24.894Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/34/fc2f101b151af3799a101f0550b0454aa008afdc0add677394ec4aa8ea10/coverage-7.14.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d5ed429d0b8edaac649e889b4ffcedb6c80b06629a3f93050e3dddfb99235bee", size = 220091, upload-time = "2026-05-26T20:40:27.249Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/a7/1ebae2ab5b961b5c79bb09fe7b3ac99edb190d8be4a8c510b2cf66f46468/coverage-7.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8011224a62280e50dab346960c03cf47aca1a1e09e608c0fb33fd6e0cc8e9500", size = 220421, upload-time = "2026-05-26T20:40:30.084Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/90/92aca9cf0acc95123c96cd1eb1f08917897a7f5dee01e15738922971ec31/coverage-7.14.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:12c42ec1e14f553c4f817e989365982e646e27211f10a0f717855b94a79c8906", size = 251466, upload-time = "2026-05-26T20:40:32.542Z" },
+ { url = "https://files.pythonhosted.org/packages/26/2b/78048cbe3b999f6cbf9cc0d90abba6a88a3e0863a8c1c6cbc762f3f8802f/coverage-7.14.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:06144cd511cf2624873a035c5069cf297144f6e77a73ee3d7a55b605ec5efb42", size = 253973, upload-time = "2026-05-26T20:40:34.473Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/21/c2e33b29d1cfde484a19d437afc343c6cd30b08d78cbbf9f5aff14e57b2b/coverage-7.14.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a311d8e1da24be5c1ccf85cbfb06315dbaa1703d5a1eab3f6432c72b837917c8", size = 255318, upload-time = "2026-05-26T20:40:38.154Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/ee/aad2f108d63b769121005302f16bf66db8625c88ceaba466942e09a2607e/coverage-7.14.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c79cead5b5bc584d9c71451cb984d0e3a84e0c0937379c8efcbf27c8d661b851", size = 257633, upload-time = "2026-05-26T20:40:40.164Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/f8/11a2c29b4fd76d9849f81d0bb812ec0017a9396df3217214e38934a8c837/coverage-7.14.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dcbf65f1f66a26cdd88c35cf68fb4729c5d1cd2e88added72420541dfb212034", size = 251488, upload-time = "2026-05-26T20:40:42.631Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/b8/9a5820de4b8ac2b71d85e3b5fb49108d7469c665f0e2ad0dd7569023e305/coverage-7.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fd86572566fb40189a8260446158235159bc7a82dfbc87a3b39cf4fb57fcec1c", size = 253329, upload-time = "2026-05-26T20:40:45.208Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/ff/f33e4823667e27548e8fd8df44217515303f9808d0ff29817db56f87d990/coverage-7.14.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7771b601718fdde84832c3a434ca9bbf4ae9adbc49d84198b4110700c3c77c36", size = 251291, upload-time = "2026-05-26T20:40:47.502Z" },
+ { url = "https://files.pythonhosted.org/packages/68/9b/489db0ebb209054766b90a9014a45f6d26eb724c02ec21311c3733b5a644/coverage-7.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:39b21e212c55af06fa375e3dbf90a8a8e38792f3a910c580066d23563830ddd5", size = 255564, upload-time = "2026-05-26T20:40:49.372Z" },
+ { url = "https://files.pythonhosted.org/packages/27/b5/16bc2d4c2409b23c7737edb68c83bc89e345f378050549fe1d75ac7d34d5/coverage-7.14.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f2302660e32562a532b442480121aef8aa61a5bdb20b30bf0adab29f10a5a4b4", size = 251107, upload-time = "2026-05-26T20:40:51.677Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/0c/2629997469a00cd069d588a41c9dc887610f2775ae89d250c4791e65272a/coverage-7.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:03a6f93c1ec3b7f2e77b5dbcc5573a2c21f12529a5c6bbe0f16f72303cc2fa4d", size = 252764, upload-time = "2026-05-26T20:40:54.267Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/ee/f78d63c8f079e0d7211c7e2401fa17e311514534ba61bae03e4b287ce4ab/coverage-7.14.1-cp314-cp314-win32.whl", hash = "sha256:8a3ce026d73290f42f08dafecbd82c193a74df280461fbf97300fec51fd133ee", size = 222837, upload-time = "2026-05-26T20:40:56.496Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/b9/be539854f93a70dfbeec69117f33ec70dc42ff0b65b5b07ab8d40d04228e/coverage-7.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:114c95ef29302423b87d159075805f4ab973254a2638a5d7d046c94887cc87d7", size = 223650, upload-time = "2026-05-26T20:40:58.351Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/9e/24e2842fef40f35ac82ba3a7719c8023d011bf3bf652d0675316a9d088a1/coverage-7.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:a07891c3f4805442b31b71e84ba3cf29ed1aa9a428284e06deeb4b23e5b46343", size = 222218, upload-time = "2026-05-26T20:41:00.321Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/1d/ac0a9df5fe31c1e8bdd658074905fc12844a05c1a7e3fdb8417e97c31e23/coverage-7.14.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1101a5ebb083aecb625ebb6209d4105b58f647b093cb2dc8122d7b33f743cfe1", size = 220822, upload-time = "2026-05-26T20:41:02.281Z" },
+ { url = "https://files.pythonhosted.org/packages/32/cf/f964fd9aff20323f9f1a726c97135f8a76bcd87b92dad141a456a43f3c64/coverage-7.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:851b9e1e4e8a4608e77c79714b2e77c0970d2ed7202a05e92ae407817481887b", size = 221084, upload-time = "2026-05-26T20:41:04.593Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/5e/7e5ef2aba844de2b80d678619fcf0841b42e3f37f16411226f3fe4c1016f/coverage-7.14.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d5b89cdfb2ee051b71e8c3c70bd81a9eff81100f736a269136fe1a68efe00474", size = 262454, upload-time = "2026-05-26T20:41:06.641Z" },
+ { url = "https://files.pythonhosted.org/packages/64/62/75809bded87015cc4935524218a2a8ed8dd1a8498bfed30a2f4f7a4b4d34/coverage-7.14.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0177614a0370f227888b4e436a7c55686d6a9f90eb1ade2b624ba685a1686e86", size = 264578, upload-time = "2026-05-26T20:41:08.556Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/42/d33392dc14633525012d2d504fa1a33b05538bf535f5c1d64675e5754b78/coverage-7.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d69af5dea2de76fc485a83032a630523f985198b7e25be901ec60181587b01e", size = 266981, upload-time = "2026-05-26T20:41:10.824Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/49/0157c4428c2aca7f1e09d5565930586fd5ae36f1655f08b0daa7cf1fcae1/coverage-7.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:35ab22d91de736e8966b980dc355cbcdd2c6dbbcfe275f9a2991bc8a91b3df65", size = 268112, upload-time = "2026-05-26T20:41:12.966Z" },
+ { url = "https://files.pythonhosted.org/packages/96/26/86b9ce71f4092b1ed325ce1421698081df1286b833400b6836912834d6e0/coverage-7.14.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:357d4e32935c36588aaba057d734fa32428c360c9fc2e4442afbf1b646beee6e", size = 261558, upload-time = "2026-05-26T20:41:15Z" },
+ { url = "https://files.pythonhosted.org/packages/20/4c/c311210c5472cf5401d8422b0d7812cdd520f24417673afabda6c323faca/coverage-7.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:51bd64741cc6fa065abd300ede1afe5a5291ece9c31da8b24884deda48bcc3f8", size = 264447, upload-time = "2026-05-26T20:41:17.369Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/71/59513f8710ed3e6b0ac0a050a5b7e977bb9c9e880354863b5d00d8809256/coverage-7.14.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:9132cd363a68a4c3daa7c8704a654b1e39d3360f6f5b8ddd470608a945236c07", size = 262048, upload-time = "2026-05-26T20:41:19.309Z" },
+ { url = "https://files.pythonhosted.org/packages/84/8d/bceed32dc494f5bbf50f775cd2e78ca814953942b5ea28d3c1c3ac316f14/coverage-7.14.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:07c6290b1697b862c0478eab545eec949a0d0e4d6d03497f446d706da3b4f2de", size = 265781, upload-time = "2026-05-26T20:41:21.559Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/c5/9348fe40dbfd4991aaf78df2c6c3098bfb2cc834d1fd362a64b4efef855a/coverage-7.14.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5ea0c297e27133853b4d8a3eb799bff5a2dbd9f2f41537a240d337ac9b4df890", size = 260896, upload-time = "2026-05-26T20:41:23.428Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/92/1ea0f03929da7cf87206b1fa24f4c8e9c158be0455481af29ec0a1f3503f/coverage-7.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:01b7733daad0237daa01ef80fe2dfceffc911e6a17fa7b55d14aa8214eaaaecd", size = 263214, upload-time = "2026-05-26T20:41:25.419Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/a9/b2493c054c0e01a643266742ab45e15744e60743f9260cd930c7142b1124/coverage-7.14.1-cp314-cp314t-win32.whl", hash = "sha256:6adc5a36984624a70bf11d7184e20fa0a49aa7c47ffab43804106a1a695ea22e", size = 223624, upload-time = "2026-05-26T20:41:27.795Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/bd/3e1e6a57fccd2d7c83fcdf338e93ba98eb85c6e877dd34731ac585375490/coverage-7.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:ddf799247318f34dbcd2efa8c95a8d0642674e926bb1774cf9b63dfd2a389d1c", size = 224728, upload-time = "2026-05-26T20:41:30.098Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/d7/31066cf1d2f0c6c797fce911bcfa01dd35642dc6da992a950256097c5860/coverage-7.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:145986fe66647eb489f18d9a997567a3fd358584c4b5a808769113abc07466af", size = 222752, upload-time = "2026-05-26T20:41:32.123Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/3c/1a983b9a745d7f83d53f057bcc5bf79ba6a2bbc08266b3f0c7d6fe630c9b/coverage-7.14.1-py3-none-any.whl", hash = "sha256:a252f21c27e38347e60111a3266b03827422a7d5525951aceee313aa68bab1d2", size = 211815, upload-time = "2026-05-26T20:41:34.078Z" },
+]
+
+[[package]]
+name = "cryptography"
+version = "48.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9f/a9/db8f313fdcd85d767d4973515e1db101f9c71f95fced83233de224673757/cryptography-48.0.0.tar.gz", hash = "sha256:5c3932f4436d1cccb036cb0eaef46e6e2db91035166f1ad6505c3c9d5a635920", size = 832984, upload-time = "2026-05-04T22:59:38.133Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/df/3d/01f6dd9190170a5a241e0e98c2d04be3664a9e6f5b9b872cde63aff1c3dd/cryptography-48.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:0c558d2cdffd8f4bbb30fc7134c74d2ca9a476f830bb053074498fbc86f41ed6", size = 8001587, upload-time = "2026-05-04T22:57:36.803Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/6e/e90527eef33f309beb811cf7c982c3aeffcce8e3edb178baa4ca3ae4a6fa/cryptography-48.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f5333311663ea94f75dd408665686aaf426563556bb5283554a3539177e03b8c", size = 4690433, upload-time = "2026-05-04T22:57:40.373Z" },
+ { url = "https://files.pythonhosted.org/packages/90/04/673510ed51ddff56575f306cf1617d80411ee76831ccd3097599140efdfe/cryptography-48.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7995ef305d7165c3f11ae07f2517e5a4f1d5c18da1376a0a9ed496336b69e5f3", size = 4710620, upload-time = "2026-05-04T22:57:42.935Z" },
+ { url = "https://files.pythonhosted.org/packages/14/d5/e9c4ef932c8d800490c34d8bd589d64a31d5890e27ec9e9ad532be893294/cryptography-48.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:40ba1f85eaa6959837b1d51c9767e230e14612eea4ef110ee8854ada22da1bf5", size = 4696283, upload-time = "2026-05-04T22:57:45.294Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/29/174b9dfb60b12d59ecfc6cfa04bc88c21b42a54f01b8aae09bb6e51e4c7f/cryptography-48.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:369a6348999f94bbd53435c894377b20ab95f25a9065c283570e70150d8abc3c", size = 5296573, upload-time = "2026-05-04T22:57:47.933Z" },
+ { url = "https://files.pythonhosted.org/packages/95/38/0d29a6fd7d0d1373f0c0c88a04ba20e359b257753ac497564cd660fc1d55/cryptography-48.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a0e692c683f4df67815a2d258b324e66f4738bd7a96a218c826dce4f4bd05d8f", size = 4743677, upload-time = "2026-05-04T22:57:50.067Z" },
+ { url = "https://files.pythonhosted.org/packages/30/be/eef653013d5c63b6a490529e0316f9ac14a37602965d4903efed1399f32b/cryptography-48.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:18349bbc56f4743c8b12dc32e2bccb2cf83ee8b69a3bba74ef8ae857e26b3d25", size = 4330808, upload-time = "2026-05-04T22:57:52.301Z" },
+ { url = "https://files.pythonhosted.org/packages/84/9e/500463e87abb7a0a0f9f256ec21123ecde0a7b5541a15e840ea54551fd81/cryptography-48.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:7e8eac43dfca5c4cccc6dad9a80504436fca53bb9bc3100a2386d730fbe6b602", size = 4695941, upload-time = "2026-05-04T22:57:54.603Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/dc/7303087450c2ec9e7fbb750e17c2abfbc658f23cbd0e54009509b7cc4091/cryptography-48.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9ccdac7d40688ecb5a3b4a604b8a88c8002e3442d6c60aead1db2a89a041560c", size = 5252579, upload-time = "2026-05-04T22:57:57.207Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/c0/7101d3b7215edcdc90c45da544961fd8ed2d6448f77577460fa75a8443f7/cryptography-48.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:bd72e68b06bb1e96913f97dd4901119bc17f39d4586a5adf2d3e47bc2b9d58b5", size = 4743326, upload-time = "2026-05-04T22:57:59.535Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/d8/5b833bad13016f562ab9d063d68199a4bd121d18458e439515601d3357ec/cryptography-48.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:59baa2cb386c4f0b9905bd6eb4c2a79a69a128408fd31d32ca4d7102d4156321", size = 4826672, upload-time = "2026-05-04T22:58:01.996Z" },
+ { url = "https://files.pythonhosted.org/packages/98/e1/7074eb8bf3c135558c73fc2bcf0f5633f912e6fb87e868a55c454080ef09/cryptography-48.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9249e3cd978541d665967ac2cb2787fd6a62bddf1e75b3e347a594d7dacf4f74", size = 4972574, upload-time = "2026-05-04T22:58:03.968Z" },
+ { url = "https://files.pythonhosted.org/packages/04/70/e5a1b41d325f797f39427aa44ef8baf0be500065ab6d8e10369d850d4a4f/cryptography-48.0.0-cp311-abi3-win32.whl", hash = "sha256:9c459db21422be75e2809370b829a87eb37f74cd785fc4aa9ea1e5f43b47cda4", size = 3294868, upload-time = "2026-05-04T22:58:06.467Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/ac/8ac51b4a5fc5932eb7ee5c517ba7dc8cd834f0048962b6b352f00f41ebf9/cryptography-48.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:5b012212e08b8dd5edc78ef54da83dd9892fd9105323b3993eff6bea65dc21d7", size = 3817107, upload-time = "2026-05-04T22:58:08.845Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/84/70e3feea9feea87fd7cbe77efb2712ae1e3e6edf10749dc6e95f4e60e455/cryptography-48.0.0-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:3cb07a3ed6431663cd321ea8a000a1314c74211f823e4177fefa2255e057d1ec", size = 7986556, upload-time = "2026-05-04T22:58:11.172Z" },
+ { url = "https://files.pythonhosted.org/packages/89/6e/18e07a618bb5442ba10cf4df16e99c071365528aa570dfcb8c02e25a303b/cryptography-48.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8c7378637d7d88016fa6791c159f698b3d3eed28ebf844ac36b9dc04a14dae18", size = 4684776, upload-time = "2026-05-04T22:58:13.712Z" },
+ { url = "https://files.pythonhosted.org/packages/be/6a/4ea3b4c6c6759794d5ee2103c304a5076dc4b19ae1f9fe47dba439e159e9/cryptography-48.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc90c0b39b2e3c65ef52c804b72e3c58f8a04ab2a1871272798e5f9572c17d20", size = 4698121, upload-time = "2026-05-04T22:58:16.448Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/59/6ff6ad6cae03bb887da2a5860b2c9805f8dac969ef01ce563336c49bd1d1/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:76341972e1eff8b4bea859f09c0d3e64b96ce931b084f9b9b7db8ef364c30eff", size = 4690042, upload-time = "2026-05-04T22:58:18.544Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/b4/fc334ed8cfd705aca282fe4d8f5ae64a8e0f74932e9feecb344610cf6e4d/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:55b7718303bf06a5753dcdccf2f3945cf18ad7bffde41b61226e4db31ab89a9c", size = 5282526, upload-time = "2026-05-04T22:58:20.75Z" },
+ { url = "https://files.pythonhosted.org/packages/11/08/9f8c5386cc4cd90d8255c7cdd0f5baf459a08502a09de30dc51f553d38dc/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:a64697c641c7b1b2178e573cbc31c7c6684cd56883a478d75143dbb7118036db", size = 4733116, upload-time = "2026-05-04T22:58:23.627Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/77/99307d7574045699f8805aa500fa0fb83422d115b5400a064ddd306d7750/cryptography-48.0.0-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:561215ea3879cb1cbbf272867e2efda62476f240fb58c64de6b393ae19246741", size = 4316030, upload-time = "2026-05-04T22:58:25.581Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/36/a608b98337af3cb2aff4818e406649d30572b7031918b04c87d979495348/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:ad64688338ed4bc1a6618076ba75fd7194a5f1797ac60b47afe926285adb3166", size = 4689640, upload-time = "2026-05-04T22:58:27.747Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/a6/825010a291b4438aecc1f568bc428189fc1175515223632477c07dc0a6df/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:906cbf0670286c6e0044156bc7d4af9cbb0ef6db9f73e52c3ec56ba6bdde5336", size = 5237657, upload-time = "2026-05-04T22:58:29.848Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/09/4e76a09b4caa29aad535ddc806f5d4c5d01885bd978bd984fbc6ca032cae/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:ea8990436d914540a40ab24b6a77c0969695ed52f4a4874c5137ccf7045a7057", size = 4732362, upload-time = "2026-05-04T22:58:32.009Z" },
+ { url = "https://files.pythonhosted.org/packages/18/78/444fa04a77d0cb95f417dda20d450e13c56ba8e5220fc892a1658f44f882/cryptography-48.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c18684a7f0cc9a3cb60328f496b8e3372def7c5d2df39ac267878b05565aaaae", size = 4819580, upload-time = "2026-05-04T22:58:34.254Z" },
+ { url = "https://files.pythonhosted.org/packages/38/85/ea67067c70a1fd4be2c63d35eeed82658023021affccc7b17705f8527dd2/cryptography-48.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9be5aafa5736574f8f15f262adc81b2a9869e2cfe9014d52a44633905b40d52c", size = 4963283, upload-time = "2026-05-04T22:58:36.376Z" },
+ { url = "https://files.pythonhosted.org/packages/75/54/cc6d0f3deac3e81c7f847e8a189a12b6cdd65059b43dad25d4316abd849a/cryptography-48.0.0-cp314-cp314t-win32.whl", hash = "sha256:c17dfe85494deaeddc5ce251aebd1d60bbe6afc8b62071bb0b469431a000124f", size = 3270954, upload-time = "2026-05-04T22:58:38.791Z" },
+ { url = "https://files.pythonhosted.org/packages/49/67/cc947e288c0758a4e5473d1dcb743037ab7785541265a969240b8885441a/cryptography-48.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27241b1dc9962e056062a8eef1991d02c3a24569c95975bd2322a8a52c6e5e12", size = 3797313, upload-time = "2026-05-04T22:58:40.746Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/63/61d4a4e1c6b6bab6ce1e213cd36a24c415d90e76d78c5eb8577c5541d2e8/cryptography-48.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:58d00498e8933e4a194f3076aee1b4a97dfec1a6da444535755822fe5d8b0b86", size = 7983482, upload-time = "2026-05-04T22:58:43.769Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/ac/f5b5995b87770c693e2596559ffafe195b4033a57f14a82268a2842953f3/cryptography-48.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:614d0949f4790582d2cc25553abd09dd723025f0c0e7c67376a1d77196743d6e", size = 4683266, upload-time = "2026-05-04T22:58:46.064Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/c6/8b14f67e18338fbc4adb76f66c001f5c3610b3e2d1837f268f47a347dbbb/cryptography-48.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7ce4bfae76319a532a2dc68f82cc32f5676ee792a983187dac07183690e5c66f", size = 4696228, upload-time = "2026-05-04T22:58:48.22Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/73/f808fbae9514bd91b47875b003f13e284c8c6bdfd904b7944e803937eec1/cryptography-48.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:2eb992bbd4661238c5a397594c83f5b4dc2bc5b848c365c8f991b6780efcc5c7", size = 4689097, upload-time = "2026-05-04T22:58:50.9Z" },
+ { url = "https://files.pythonhosted.org/packages/93/01/d86632d7d28db8ae83221995752eeb6639ffb374c2d22955648cf8d52797/cryptography-48.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:22a5cb272895dce158b2cacdfdc3debd299019659f42947dbdac6f32d68fe832", size = 5283582, upload-time = "2026-05-04T22:58:53.017Z" },
+ { url = "https://files.pythonhosted.org/packages/02/e1/50edc7a50334807cc4791fc4a0ce7468b4a1416d9138eab358bfc9a3d70b/cryptography-48.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2b4d59804e8408e2fea7d1fbaf218e5ec984325221db76e6a241a9abd6cdd95c", size = 4730479, upload-time = "2026-05-04T22:58:55.611Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/af/99a582b1b1641ff5911ac559beb45097cf79efd4ead4657f578ef1af2d47/cryptography-48.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:984a20b0f62a26f48a3396c72e4bc34c66e356d356bf370053066b3b6d54634a", size = 4326481, upload-time = "2026-05-04T22:58:57.607Z" },
+ { url = "https://files.pythonhosted.org/packages/90/ee/89aa26a06ef0a7d7611788ffd571a7c50e368cc6a4d5eef8b4884e866edb/cryptography-48.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5a5ed8fde7a1d09376ca0b40e68cd59c69fe23b1f9768bd5824f54681626032a", size = 4688713, upload-time = "2026-05-04T22:59:00.077Z" },
+ { url = "https://files.pythonhosted.org/packages/70/ba/bcb1b0bb7a33d4c7c0c4d4c7874b4a62ae4f56113a5f4baefa362dfb1f0f/cryptography-48.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:8cd666227ef7af430aa5914a9910e0ddd703e75f039cef0825cd0da71b6b711a", size = 5238165, upload-time = "2026-05-04T22:59:02.317Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/70/ca4003b1ce5ca3dc3186ada51908c8a9b9ff7d5cab83cc0d43ee14ec144f/cryptography-48.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9071196d81abc88b3516ac8cdfad32e2b66dd4a5393a8e68a961e9161ddc6239", size = 4729947, upload-time = "2026-05-04T22:59:05.255Z" },
+ { url = "https://files.pythonhosted.org/packages/44/a0/4ec7cf774207905aef1a8d11c3750d5a1db805eb380ee4e16df317870128/cryptography-48.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1e2d54c8be6152856a36f0882ab231e70f8ec7f14e93cf87db8a2ed056bf160c", size = 4822059, upload-time = "2026-05-04T22:59:07.802Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/75/a2e55f99c16fcac7b5d6c1eb19ad8e00799854d6be5ca845f9259eae1681/cryptography-48.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a5da777e32ffed6f85a7b2b3f7c5cbc88c146bfcd0a1d7baf5fcc6c52ee35dd4", size = 4960575, upload-time = "2026-05-04T22:59:09.851Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/23/6e6f32143ab5d8b36ca848a502c4bcd477ae75b9e1677e3530d669062578/cryptography-48.0.0-cp39-abi3-win32.whl", hash = "sha256:77a2ccbbe917f6710e05ba9adaa25fb5075620bf3ea6fb751997875aff4ae4bd", size = 3279117, upload-time = "2026-05-04T22:59:12.019Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/9a/0fea98a70cf1749d41d738836f6349d97945f7c89433a259a6c2642eefeb/cryptography-48.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:16cd65b9330583e4619939b3a3843eec1e6e789744bb01e7c7e2e62e33c239c8", size = 3792100, upload-time = "2026-05-04T22:59:14.884Z" },
+]
+
+[[package]]
+name = "cssbeautifier"
+version = "1.15.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "editorconfig" },
+ { name = "jsbeautifier" },
+ { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f7/01/fdf41c1e5f93d359681976ba10410a04b299d248e28ecce1d4e88588dde4/cssbeautifier-1.15.4.tar.gz", hash = "sha256:9bb08dc3f64c101a01677f128acf01905914cf406baf87434dcde05b74c0acf5", size = 25376, upload-time = "2025-02-27T17:53:51.341Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/63/51/ef6c5628e46092f0a54c7cee69acc827adc6b6aab57b55d344fefbdf28f1/cssbeautifier-1.15.4-py3-none-any.whl", hash = "sha256:78c84d5e5378df7d08622bbd0477a1abdbd209680e95480bf22f12d5701efc98", size = 123667, upload-time = "2025-02-27T17:53:43.594Z" },
+]
+
+[[package]]
+name = "cycler"
+version = "0.12.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" },
+]
+
+[[package]]
+name = "daylily-auth-cognito"
+version = "2.1.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "boto3" },
+ { name = "cli-core-yo" },
+ { name = "fastapi" },
+ { name = "itsdangerous" },
+ { name = "python-jose", extra = ["cryptography"] },
+ { name = "pyyaml" },
+ { name = "rich" },
+ { name = "typer" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/af/02/af8947a387570c09bc4b32c93935619a3bb742ff2505b0b44ccf8ffa9337/daylily_auth_cognito-2.1.5.tar.gz", hash = "sha256:407b73e22c72935652471c10a35481a7f415cc4c16aa3430632152cb2d3bf44a", size = 77340, upload-time = "2026-04-27T18:04:22.37Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7e/8d/bac93d358a84a2c288a82dfb9480781597721992942063d51bfdacb564d4/daylily_auth_cognito-2.1.5-py3-none-any.whl", hash = "sha256:77499606791b90bfbe3a85a32f0dd0b70c70c085cd26fe33a15771baf1485081", size = 49918, upload-time = "2026-04-27T18:04:21.345Z" },
+]
+
+[[package]]
+name = "daylily-carrier-tracking"
+version = "0.5.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "requests" },
+ { name = "yaml-config-day" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2d/10/0fbba9a39ab00c7d39456d145abe612b939aa4931d9aab4d54c782f9b1a2/daylily_carrier_tracking-0.5.1.tar.gz", hash = "sha256:86f8085b44db8bb85c879b93e9be7fdb65c610e37e6eb2c9dc2aedeea572350f", size = 34456, upload-time = "2026-03-10T18:08:04.178Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b0/72/b028cc143146bfb091053fa8ab2402eca35d498f7be5dcd5dfdcbc44ada2/daylily_carrier_tracking-0.5.1-py3-none-any.whl", hash = "sha256:004884fdf7295a1f37a06f76c3a26503d4c000d3fdcdb9a2aea08d13113c3f07", size = 22032, upload-time = "2026-03-10T18:08:02.438Z" },
+]
+
+[[package]]
+name = "daylily-tapdb"
+version = "7.0.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cli-core-yo" },
+ { name = "jsonschema" },
+ { name = "meridian-euid" },
+ { name = "psycopg2-binary" },
+ { name = "pydantic" },
+ { name = "pyyaml" },
+ { name = "rich" },
+ { name = "sqlalchemy" },
+ { name = "typer" },
+ { name = "uuid6" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/02/f0/e43d08ff8dd476e7b162408b58680fbc3d3c82e3b89119d5457f303d6bac/daylily_tapdb-7.0.5.tar.gz", hash = "sha256:51fa260efc3c57a67496d0c7cdebca72a51ca28ee4156fe14744d62d5f6ea2ae", size = 375380, upload-time = "2026-05-18T14:02:42.708Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/56/6c/f5b3f2143076144fa8315acd839205bcd29790980136ac232abe5f1bd5da/daylily_tapdb-7.0.5-py3-none-any.whl", hash = "sha256:6cad6a5ec40337c4fa9fb05e7e871c082d47ad06ee78eb1a7005da30aeef7f07", size = 254541, upload-time = "2026-05-18T14:02:40.958Z" },
+]
+
+[[package]]
+name = "decorator"
+version = "5.3.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/60/8b/32f9823da46cde7df2087faa08cd98d01b908f8dcab982cdba9c84e85355/decorator-5.3.1.tar.gz", hash = "sha256:4cbcdd55a6efadb9dbea26b858f4fb3264567b52d69ca0d25b721b553f60ea82", size = 58084, upload-time = "2026-05-18T06:03:28.057Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/05/7f/798705f5296a58ca505d600456748d1be48078eac8a7050d8a98bc9edb89/decorator-5.3.1-py3-none-any.whl", hash = "sha256:f47fe6fdbd2edd623ecfe36875d37aba411624e2670dd395dddae1358689bb3c", size = 10365, upload-time = "2026-05-18T06:03:26.517Z" },
+]
+
+[[package]]
+name = "distlib"
+version = "0.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" },
+]
+
+[[package]]
+name = "djlint"
+version = "1.36.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+ { name = "colorama" },
+ { name = "cssbeautifier" },
+ { name = "jsbeautifier" },
+ { name = "json5" },
+ { name = "pathspec" },
+ { name = "pyyaml" },
+ { name = "regex" },
+ { name = "tqdm" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/74/89/ecf5be9f5c59a0c53bcaa29671742c5e269cc7d0e2622e3f65f41df251bf/djlint-1.36.4.tar.gz", hash = "sha256:17254f218b46fe5a714b224c85074c099bcb74e3b2e1f15c2ddc2cf415a408a1", size = 47849, upload-time = "2024-12-24T13:06:36.36Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/53/f5/9ae02b875604755d4d00cebf96b218b0faa3198edc630f56a139581aed87/djlint-1.36.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff9faffd7d43ac20467493fa71d5355b5b330a00ade1c4d1e859022f4195223b", size = 354886, upload-time = "2024-12-24T13:06:11.571Z" },
+ { url = "https://files.pythonhosted.org/packages/97/51/284443ff2f2a278f61d4ae6ae55eaf820ad9f0fd386d781cdfe91f4de495/djlint-1.36.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:79489e262b5ac23a8dfb7ca37f1eea979674cfc2d2644f7061d95bea12c38f7e", size = 323237, upload-time = "2024-12-24T13:06:13.057Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/5e/791f4c5571f3f168ad26fa3757af8f7a05c623fde1134a9c4de814ee33b7/djlint-1.36.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e58c5fa8c6477144a0be0a87273706a059e6dd0d6efae01146ae8c29cdfca675", size = 411719, upload-time = "2024-12-24T13:06:15.672Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/11/894425add6f84deffcc6e373f2ce250f2f7b01aa58c7f230016ebe7a0085/djlint-1.36.4-cp312-cp312-win_amd64.whl", hash = "sha256:bb6903777bf3124f5efedcddf1f4716aef097a7ec4223fc0fa54b865829a6e08", size = 362076, upload-time = "2024-12-24T13:06:17.517Z" },
+ { url = "https://files.pythonhosted.org/packages/da/83/88b4c885812921739f5529a29085c3762705154d41caf7eb9a8886a3380c/djlint-1.36.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ead475013bcac46095b1bbc8cf97ed2f06e83422335734363f8a76b4ba7e47c2", size = 354384, upload-time = "2024-12-24T13:06:20.809Z" },
+ { url = "https://files.pythonhosted.org/packages/32/38/67695f7a150b3d9d62fadb65242213d96024151570c3cf5d966effa68b0e/djlint-1.36.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6c601dfa68ea253311deb4a29a7362b7a64933bdfcfb5a06618f3e70ad1fa835", size = 322971, upload-time = "2024-12-24T13:06:22.185Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/7a/cd851393291b12e7fe17cf5d4d8874b8ea133aebbe9235f5314aabc96a52/djlint-1.36.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bda5014f295002363381969864addeb2db13955f1b26e772657c3b273ed7809f", size = 410972, upload-time = "2024-12-24T13:06:24.077Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/31/56469120394b970d4f079a552fde21ed27702ca729595ab0ed459eb6d240/djlint-1.36.4-cp313-cp313-win_amd64.whl", hash = "sha256:16ce37e085afe5a30953b2bd87cbe34c37843d94c701fc68a2dda06c1e428ff4", size = 362053, upload-time = "2024-12-24T13:06:25.432Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/67/f7aeea9be6fb3bd984487af8d0d80225a0b1e5f6f7126e3332d349fb13fe/djlint-1.36.4-py3-none-any.whl", hash = "sha256:e9699b8ac3057a6ed04fb90835b89bee954ed1959c01541ce4f8f729c938afdd", size = 52290, upload-time = "2024-12-24T13:06:33.76Z" },
+]
+
+[[package]]
+name = "ecdsa"
+version = "0.19.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/25/ca/8de7744cb3bc966c85430ca2d0fcaeea872507c6a4cf6e007f7fe269ed9d/ecdsa-0.19.2.tar.gz", hash = "sha256:62635b0ac1ca2e027f82122b5b81cb706edc38cd91c63dda28e4f3455a2bf930", size = 202432, upload-time = "2026-03-26T09:58:17.675Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/51/79/119091c98e2bf49e24ed9f3ae69f816d715d2904aefa6a2baa039a2ba0b0/ecdsa-0.19.2-py2.py3-none-any.whl", hash = "sha256:840f5dc5e375c68f36c1a7a5b9caad28f95daa65185c9253c0c08dd952bb7399", size = 150818, upload-time = "2026-03-26T09:58:15.808Z" },
+]
+
+[[package]]
+name = "editorconfig"
+version = "0.17.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/88/3a/a61d9a1f319a186b05d14df17daea42fcddea63c213bcd61a929fb3a6796/editorconfig-0.17.1.tar.gz", hash = "sha256:23c08b00e8e08cc3adcddb825251c497478df1dada6aefeb01e626ad37303745", size = 14695, upload-time = "2025-06-09T08:21:37.097Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/96/fd/a40c621ff207f3ce8e484aa0fc8ba4eb6e3ecf52e15b42ba764b457a9550/editorconfig-0.17.1-py3-none-any.whl", hash = "sha256:1eda9c2c0db8c16dbd50111b710572a5e6de934e39772de1959d41f64fc17c82", size = 16360, upload-time = "2025-06-09T08:21:35.654Z" },
+]
+
+[[package]]
+name = "executing"
+version = "2.2.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" },
+]
+
+[[package]]
+name = "fastapi"
+version = "0.136.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-doc" },
+ { name = "pydantic" },
+ { name = "starlette" },
+ { name = "typing-extensions" },
+ { name = "typing-inspection" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/81/2d/ff8d91d7b564d464629a0fd50a4489c97fcb836ac230bf3a7269232a9b1f/fastapi-0.136.3.tar.gz", hash = "sha256:e487fae93ad408e6f47641ee4dfe389864fd7bec92e547ea8498fc13f43e83ab", size = 396410, upload-time = "2026-05-23T18:53:15.192Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e0/82/45359b62a067409bd929ae8a56b8ed13e5a8c8a61194b3c236920999ab83/fastapi-0.136.3-py3-none-any.whl", hash = "sha256:3d2a69bdf04b7e9f3afa292c3bc7a98816bbfafa10bc9b45f3f3700d2f761620", size = 117481, upload-time = "2026-05-23T18:53:16.924Z" },
+]
+
+[[package]]
+name = "filelock"
+version = "3.29.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", size = 57571, upload-time = "2026-04-19T15:39:10.068Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812, upload-time = "2026-04-19T15:39:08.752Z" },
+]
+
+[[package]]
+name = "fonttools"
+version = "4.63.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/84/69/c97f2c18e0db87d2c7b15da1974dace76ae938f1cfa22e2727a648b7ed43/fonttools-4.63.0.tar.gz", hash = "sha256:caeb583deeb5168e694b65cda8b4ee62abedfa66cf88488734466f2366b9c4e0", size = 3597189, upload-time = "2026-05-14T12:04:30.958Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/08/ef/b3c6b9b5be2f82416d73fe2ed2e96e2793cd80e7510bd6a17ca79cdd88ec/fonttools-4.63.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:37dd23e621e3b0aef1baa70a303b80aaf38449632cfc8fd2a55fb285bbccfc02", size = 2881131, upload-time = "2026-05-14T12:03:13.386Z" },
+ { url = "https://files.pythonhosted.org/packages/44/a0/c815bea63117fa63e4e1c01f8a1110d2112fa003f838e6467094ec2432ce/fonttools-4.63.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a9faff9e0c1f76f9fd55899d2ce785832efebab37eb8ae13995853aef178bef0", size = 2426704, upload-time = "2026-05-14T12:03:15.801Z" },
+ { url = "https://files.pythonhosted.org/packages/44/04/0b91d8e916e92ad1fac9e4624760baf0fd5ff2ead614c2f68fb21373f03f/fonttools-4.63.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef3048ef05dbb552b89817713d9cac912e00d0fde4a3105c00d29e52e10c89af", size = 5044298, upload-time = "2026-05-14T12:03:18.085Z" },
+ { url = "https://files.pythonhosted.org/packages/77/c7/2342da9830e3e9d4870305ca5d2091d2a83284f2953079b7bdd3b5e029d8/fonttools-4.63.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58dc6bb86a78d782f00f9190ca02c119cf5bbe2807536e361e18d42019f877d8", size = 4999800, upload-time = "2026-05-14T12:03:20.161Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/6d/67fe16c48d7ce050979b33f47e0d28a318f02da030602e944c34f7a16ef3/fonttools-4.63.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee08ebfa58f6e1aeff5697ab9582105bb620008c1caafb681e4c557e7483027b", size = 4982666, upload-time = "2026-05-14T12:03:22.87Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/00/3bbab338c07c71fa56269953845e92c951a61457bbbb0f1022551ea266d9/fonttools-4.63.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:27fdc65af8da6f88b9c6121c47a464cbe359fcfff7ff6fc2d37a1f395d755b78", size = 5133598, upload-time = "2026-05-14T12:03:25.168Z" },
+ { url = "https://files.pythonhosted.org/packages/62/f2/aa27c7f98db5b064883dadcc5283947e81e034de42e22a33675878d98b54/fonttools-4.63.0-cp312-cp312-win32.whl", hash = "sha256:af2fd1664d00a397d75f806985ddb36282091c2131a73a6485c23b4a34722263", size = 2292575, upload-time = "2026-05-14T12:03:27.496Z" },
+ { url = "https://files.pythonhosted.org/packages/87/36/cccb9bc2a6ab63d1b2980374f0dca72ce95ae267c9b4cfe77455bb70d0d4/fonttools-4.63.0-cp312-cp312-win_amd64.whl", hash = "sha256:59ac449f8cca9b4ffa08d2e7bbadad87ce710d69d1eda5c3c1ce579baa987272", size = 2343211, upload-time = "2026-05-14T12:03:30.057Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/8d/d8fec3dcde2963f8c908fb315e5ff2cd0ac34f82394bbbf73a2aa5145ce3/fonttools-4.63.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cd7e9857e5e63738b9d9fd707bc1f59c8b09e5177726d23664db393c59bb08bd", size = 2876062, upload-time = "2026-05-14T12:03:32.554Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/71/d935dc54e4ff121bfdd11e08702db63a7e6f25af21d8a3d7b7212df53641/fonttools-4.63.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c2a2a42198b696a6f48fad91709afb55176e66a5e566131219dba372fb7f8c59", size = 2424594, upload-time = "2026-05-14T12:03:34.86Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/40/e76320afa1df918e146155ef239b1719ee266092e96f5423bfd075affba1/fonttools-4.63.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e874792a8212b44583ea02189d9e693906b2f78b261f372f95d6c563210ac1d", size = 5024840, upload-time = "2026-05-14T12:03:36.745Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/36/0b805d8c485f872f65a509cbe3b58a5d0d17bee855333b54a150c79d3061/fonttools-4.63.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22135da48a348785c5e2d5d2d9d6bec5ed44adacbaeb9db12d9493bf6c6bfa68", size = 4975801, upload-time = "2026-05-14T12:03:38.833Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/26/2cee03d0aa083ab022da5c07aff9ed3f689da1defb81ad6917c9627896da/fonttools-4.63.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ccf41f2efdf56994d22d73bef4ced1052161958169428d06ba9724ea9e9a64be", size = 4965009, upload-time = "2026-05-14T12:03:41.494Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/48/cc4b66d9058c0d0982c833fad10127c4b0e9324606aafa41382295ca4102/fonttools-4.63.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9ced0bd02ac751dd6319b0da88aaef24414e3b0dbc32bb4f24944821a3741a27", size = 5105892, upload-time = "2026-05-14T12:03:43.525Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/1f/a98a30a814b9ddef3a2e706025f90b9e0bc94890e6cb15254bc86547d11a/fonttools-4.63.0-cp313-cp313-win32.whl", hash = "sha256:85be818f5506e8a7753153def2c9550178f0ecae6a47b5e0e8dbb23f7cc90380", size = 2291313, upload-time = "2026-05-14T12:03:45.594Z" },
+ { url = "https://files.pythonhosted.org/packages/92/46/5177b01f3b4abfdd4409f31cca4ab279c9343a26efbe9ec78c97fc612e02/fonttools-4.63.0-cp313-cp313-win_amd64.whl", hash = "sha256:ba04cb5891d4c0c21b6da95eda8d7b090021508a294fff33464fc7d241e0856b", size = 2342299, upload-time = "2026-05-14T12:03:47.414Z" },
+ { url = "https://files.pythonhosted.org/packages/27/d2/23d25e3f247b328be58d04a4c9f894178a0d1eda7d42867cfb388adaf416/fonttools-4.63.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fd1e3094f42d806d3d7c79162fc59e5910fcbe3a7360c385b8da969bc4493745", size = 2875338, upload-time = "2026-05-14T12:03:50.052Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/58/7dfa0c761cb3b2964e2a84c4dc986c926a87de0cb9fb60d5b28ded3f2914/fonttools-4.63.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6e528da43bc3791085f8cb6141b1d13e459226790240340fcbb4625649238b03", size = 2422661, upload-time = "2026-05-14T12:03:52.154Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/87/64cfa18a7a1621d17b7f4502b2b0ed8a135a90c3db51ea590ee99043e76b/fonttools-4.63.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b2248c5decb223562f7902ff6325077a073f608ee8e33e88ad88db734eb9f49", size = 5010526, upload-time = "2026-05-14T12:03:54.647Z" },
+ { url = "https://files.pythonhosted.org/packages/36/e1/a8933a72c45a87177fbde2696e0d0755c8c9062f8c077a961c6215fa27b1/fonttools-4.63.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:308f957cdeaf8abe4e5f2f124902ef405448af92c90f80e302a3b771c2e6116b", size = 4923946, upload-time = "2026-05-14T12:03:56.984Z" },
+ { url = "https://files.pythonhosted.org/packages/27/60/872e6e233b8c5e8b41413796ff18b7fe479661bd40147e071b450dfad7a1/fonttools-4.63.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bf00f21eb5fb721dbaf73d1e9da6d02a1af7768f2ebcf9798be98beab8ba90f6", size = 4962489, upload-time = "2026-05-14T12:03:59.443Z" },
+ { url = "https://files.pythonhosted.org/packages/30/c4/83c24f2ec38b90cfda84bf4b1a1f49df80e84a1db4e7ac6e0d41bf23bc39/fonttools-4.63.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c1aaa4b9c75798400ac043ce04d74e7830376c85095a5a6ed7cba2f17a266bf4", size = 5071870, upload-time = "2026-05-14T12:04:02.122Z" },
+ { url = "https://files.pythonhosted.org/packages/de/40/3ae22b60ff1d41ce0bd044b31238cdc72cef99f28b976f1e128ebd618c9b/fonttools-4.63.0-cp314-cp314-win32.whl", hash = "sha256:22693918177bd9ceabec4736d338045f357769416fc6b0b2508eefef75b08616", size = 2295026, upload-time = "2026-05-14T12:04:04.47Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/d4/98078064ccc76b45cb0f6c002452011e93c4bd26f6850344f0951cc1fe89/fonttools-4.63.0-cp314-cp314-win_amd64.whl", hash = "sha256:7d782fac32985914c351556f68ac0855391572bcd87de50e05970d3cd4c96fc5", size = 2347454, upload-time = "2026-05-14T12:04:06.752Z" },
+ { url = "https://files.pythonhosted.org/packages/49/4e/652d1580c5f4e39f7d103b0c793e4773129ad633dce4addd0cf4dfebde02/fonttools-4.63.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:6db5140a60a5d731d21ec076745b40a310607731b0a565b50776393188649001", size = 2958152, upload-time = "2026-05-14T12:04:08.706Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/55/ad864c9a9b219f552eb46b32cd7906c466e5a578ba0c3abfcc0fe7413eb6/fonttools-4.63.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7d76edbff9014094dbf03bd2d074709dfa6ec7aba13d838c937a2b33d2d6a86e", size = 2460809, upload-time = "2026-05-14T12:04:10.783Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/2b/0aa8db70f18cf52e49b4ed5ecec68547f981160bf5ded3b5aed6faa0a6f9/fonttools-4.63.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0eac00b9118c3c2f87d272e45341871c5b3066baa3c86897fa634a7c3fb59096", size = 5148649, upload-time = "2026-05-14T12:04:12.747Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/63/18e4369c25043096f1048e0c9915951adc4f842bd81c6b18155824d6fa99/fonttools-4.63.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:51394295f1a51de8b5f30bdb1e1b9a4231536c7064ef5c6e211eec19fa36036f", size = 4932147, upload-time = "2026-05-14T12:04:14.806Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/3f/67f3eac2ffd8a98446c5022f8ed3864eac878a5ff7af8df4c8286dba16cc/fonttools-4.63.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9e12f105d2b6342c559c298afb674006bb2893afc7102dcf8a1b55b0486b4e40", size = 5027237, upload-time = "2026-05-14T12:04:17.675Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/ba/4e6214cb38a7b04779e97bb7636de9a5c7f20af7018d03dee0b64c08510a/fonttools-4.63.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:796f27556dbe094c4824f75ca85267e4df776c79036c8441469a4df37038c196", size = 5053933, upload-time = "2026-05-14T12:04:20.818Z" },
+ { url = "https://files.pythonhosted.org/packages/34/3b/214dcc19ee31d3d38fb5ad2755c11ef0514e5dc300bbaf41c0b69f393799/fonttools-4.63.0-cp314-cp314t-win32.whl", hash = "sha256:948428a275741f0b64b113c955425a953314f4b9ab9997f73a72c83e68e569c8", size = 2359326, upload-time = "2026-05-14T12:04:24.22Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/1e/3ff1a9b523058c2eeb6a9d50f5574e2a738200d0d94107d5bc4105e8da3f/fonttools-4.63.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6d4741eb179121cab9eea4cb2393d24492373a260d7945006358c08cfbf45419", size = 2425829, upload-time = "2026-05-14T12:04:26.829Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/47/c99d5268f354002ce80f8d029cd9d7d872969da1de8b93d32de4dc56d6f4/fonttools-4.63.0-py3-none-any.whl", hash = "sha256:445af2eab030a16b9171ea8bdda7ebf7d96bda2df88ee182a464252f6e05e20d", size = 1164562, upload-time = "2026-05-14T12:04:29.092Z" },
+]
+
+[[package]]
+name = "greenlet"
+version = "3.5.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6d/6e/802acd792aebb2256fbbee8cacf2727faaeb6f240ac11008f09eae4414bc/greenlet-3.5.1.tar.gz", hash = "sha256:5a56aeb7d5d9cc4b3a735efb5095bd4b4f6f0e4f93e5ca876d0e2315137b7829", size = 197356, upload-time = "2026-05-20T15:05:03.917Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c4/37/4549f149c9797c21b32c2683c33522af22522099de128b2406672526d005/greenlet-3.5.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:fa4f98af3a528f0c3fd592a26df7f376f93329c8f4d987f6bb979057af8bf5e2", size = 286220, upload-time = "2026-05-20T13:07:28.463Z" },
+ { url = "https://files.pythonhosted.org/packages/38/ff/a4f436709716965eaab9f36ea7b906c8a927fbe32fb1372a2071d964f6b1/greenlet-3.5.1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffea73584b216150eab159b6d12348fb253e68757974de1e2c40d8a318ac89ed", size = 601585, upload-time = "2026-05-20T14:00:06.141Z" },
+ { url = "https://files.pythonhosted.org/packages/65/ad/54bc3fcee3ad368a61b19b67d88117f7a8c29727bf71fffdeda81fbd946e/greenlet-3.5.1-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1072b4f9edcc1e192d9283a66a3e68d6b84c561de33a83d7858beb9ba1effe10", size = 614215, upload-time = "2026-05-20T14:05:42.675Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/6c/de5b1b388cd2d9fbdfeab324863daba37d54e6e233ddbefd70b385a8c591/greenlet-3.5.1-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:89101bfd5011e069be974903cb3a4e4523845e4ece2d62dcd8d358933c0ef249", size = 620094, upload-time = "2026-05-20T14:09:09.18Z" },
+ { url = "https://files.pythonhosted.org/packages/40/69/b91cda0647df839483201545913514c2827ebea5e5ccdf931842763bc127/greenlet-3.5.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:add5217d68b31130f0beca584d7fef4878327d2e31642b66618a14eef312b63b", size = 611358, upload-time = "2026-05-20T13:14:26.37Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/43/1204baffab8a6476464795a7ccf394a3248d4f22c9f87173a15b36b6d971/greenlet-3.5.1-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:e6cd99ea59dd5d89f0c956606571d79bfe6f68c9eb7f4a4083a41a7f1587edee", size = 422782, upload-time = "2026-05-20T14:01:39.597Z" },
+ { url = "https://files.pythonhosted.org/packages/59/90/3cf77e080350cd02fa307bb2abf05df48f4482c240275bbd2c203ba8bb1c/greenlet-3.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a5ea42a752d47a145eae922b605cd1634665ac3d5ec1e72402d5048e8d60d207", size = 1570475, upload-time = "2026-05-20T14:02:25.29Z" },
+ { url = "https://files.pythonhosted.org/packages/65/2c/18cece62045e74598c3c393f70dce4a63f56222015ba29a5d4eeb04f764c/greenlet-3.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c5551170cf4f5ff5623e9af81323751979fee2c731e2287b61f73cd27257b823", size = 1635625, upload-time = "2026-05-20T13:14:34.027Z" },
+ { url = "https://files.pythonhosted.org/packages/30/f5/310d104ddf41eb5a70f4c268d22508dfb0c3c8e86fec152be34d0d2ed819/greenlet-3.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c8bb982ad117d29478ef8f5533e97df21f1e2befd17a299257b0c96d1371c0b", size = 238791, upload-time = "2026-05-20T13:10:39.018Z" },
+ { url = "https://files.pythonhosted.org/packages/62/90/ceca11f504cd23a8047a3dea31919adc48df9b626dd0c13f0d858734fdfd/greenlet-3.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:80eb4b04dadc4e67df3fae179a32c4706a3f495bc7f22fc8a81115d5f5512188", size = 235580, upload-time = "2026-05-20T13:08:45.056Z" },
+ { url = "https://files.pythonhosted.org/packages/27/69/7f7e5372d998b81001899b1c0823c957aa413ba0f2662e65821611cc31e4/greenlet-3.5.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:51518ff74664078fc51bffcc6fc529b0df5ae58da192691cee765d45ce944a2b", size = 285060, upload-time = "2026-05-20T13:08:51.899Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/bf/387f9b6b865fd2ae0d0be09e0004827295a01b71be76ed350dd1e28a91a4/greenlet-3.5.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ffdb3c0bb002c99cd8f298957e046c3dbf6006b5b7cdf11a4e19194624a0a0a", size = 604370, upload-time = "2026-05-20T14:00:07.492Z" },
+ { url = "https://files.pythonhosted.org/packages/32/f5/169ce3d4e4c67291bd18f8cbe0299c9f3e45102c7f1fb3c14780c93e4532/greenlet-3.5.1-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7715a5a2c3378ba602c3a440558261e13a820bb53a82693aacd7b7f6d964e283", size = 616987, upload-time = "2026-05-20T14:05:44.237Z" },
+ { url = "https://files.pythonhosted.org/packages/19/ba/c24110c55dffa55aa6e1d98b45310da33801aeba7686ff0190fe5d46fd32/greenlet-3.5.1-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d40a890035c0058cadbdc4af7569800fd28a0e527a0fdbb7b5f9418f176846ce", size = 622911, upload-time = "2026-05-20T14:09:10.598Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/e5/7f2e41d5273be07e77560d61ea4e56485b4d6c316d2a84518c62d1364061/greenlet-3.5.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc71ff466927a201b08305acac451ebe1aedfcea002f62f1f2f2ac2ac1e6a135", size = 613911, upload-time = "2026-05-20T13:14:27.539Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/7b/d20db2e8a5ad6c038702f3179b136f93f0a3d1a21a0c0777f3e470cdf4b2/greenlet-3.5.1-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:67821bb03e4e98664490edb787ff6af501194c29bbee0f5c1dfdcf1dc3d9d436", size = 425228, upload-time = "2026-05-20T14:01:40.837Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/a4/fbdc67579b73615a1f91615e814303cc71e06128f7baaba87be79b8fb90c/greenlet-3.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cd443683db272ebaaca03af98c0b063ab30db70ea8a31a1559f35e3f7b744ccd", size = 1570689, upload-time = "2026-05-20T14:02:27.225Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/b4/77abbe35078be39718a46cd49caf16bceb35662f97a34101dca28aa98e47/greenlet-3.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:089fff7a6ce8d9316d1f65ebc00273a56be258c1725b32b94de90a3a979557e1", size = 1635602, upload-time = "2026-05-20T13:14:36.344Z" },
+ { url = "https://files.pythonhosted.org/packages/37/f7/129f27ca700845b8ee8ca88ce7f43435a1239c2eddb7677fc938822762cf/greenlet-3.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:110a1ca7b49b014b097f6078272c3f4ed31af45b254de5228b79adba879f6af9", size = 238683, upload-time = "2026-05-20T13:11:50.57Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/5c/a485a36e87df8d8fd0632ee01511244f5156a20ed3746cc6599340326395/greenlet-3.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:f16ba1efc0715b680a18b8123d90dad887c6112ae3555b4b5c32c149540c6b4e", size = 235499, upload-time = "2026-05-20T13:12:42.028Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/cb/c62454606daf5640369c94d8a9dd540599b1bfc090e2d2180cb77f4038d2/greenlet-3.5.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:d8ab31c9de8651a2facdd5c5bb0011f2380dd1a7af78ce2adf4b56095294fc07", size = 285579, upload-time = "2026-05-20T13:08:56.396Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/71/c4270398c2eba968a6071af1dfbdcaeee6ec1c24bc8b435b8cc452700da6/greenlet-3.5.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e300185139abc337ade480c327183adf42a875ac7181bfe66d7d4efea31fbea", size = 651106, upload-time = "2026-05-20T14:00:09.448Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/ab/71e34b78a44ec271fb5f550c17bc46d301ddc5953890d935f270b0dcdb5a/greenlet-3.5.1-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7ffdb990dcaa0234cf9845aead5df2e3c3a8b6507d409274dd87e0d5ab05ffc2", size = 663478, upload-time = "2026-05-20T14:05:45.88Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/2d/2d80842910da44f78c286532d084b8a5c3717c844ae80ceb3858738ae89a/greenlet-3.5.1-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c09df69dc1712d131332054a858a3e5cca400967fa3a672e2324fbb0971448c", size = 667767, upload-time = "2026-05-20T14:09:12.15Z" },
+ { url = "https://files.pythonhosted.org/packages/77/96/4efd6fa5c62c85426a0c19077a586258ebc3a2a146ff2493e4312a697a22/greenlet-3.5.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f82b3597e9d83b63408affed0b48fd0f54935edac4302237b9a837be0dae33c", size = 660800, upload-time = "2026-05-20T13:14:29.129Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/d3/dad2eecedfbb1ed7050a20dcfae40c1442b74bc7423608be2c7e03ee7133/greenlet-3.5.1-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:a4764e0bfc6a4d114c865b32520805c16a990ef5f286a514413b05d5ecd6a23d", size = 470786, upload-time = "2026-05-20T14:01:42.064Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/e0/6c71401a25cac7000261304e866a2f2cc04dc74810d40e2f118aa4799495/greenlet-3.5.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c0141e37414c10164e702b8fb1473304221ad98f71600850c6ef7ff4880feba0", size = 1617518, upload-time = "2026-05-20T14:02:28.662Z" },
+ { url = "https://files.pythonhosted.org/packages/41/26/c5c06643e8c0af9e7bf18e16cb51d0ab7625155f0392e1c9015d66d556cd/greenlet-3.5.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:50ae25a67bea74ea41fb14b960bc532df73eb713417b2d61892dced82fe8d3bc", size = 1681593, upload-time = "2026-05-20T13:14:39.417Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/bd/e11a108317485075e68af9d23039619b86b28130c3b50d227d42edece64b/greenlet-3.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:8a17c42330e261299766b75ac1ea32caa437a9453c8f65d16a13140db378ecd3", size = 239800, upload-time = "2026-05-20T13:09:30.128Z" },
+ { url = "https://files.pythonhosted.org/packages/47/f8/8e8e8417b7bf28639a5a56356ef934d0375e1d0c70a57e04d7701e870ffe/greenlet-3.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:7b5f5fae05b8ac6d176a61b60c394a8cbdc2b5b91b81793066e68745cf165e54", size = 236862, upload-time = "2026-05-20T13:09:10.498Z" },
+ { url = "https://files.pythonhosted.org/packages/90/12/41bf27fde4d3605d3773ae57751eda182b8be2f5398011c041173b1d9534/greenlet-3.5.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:ea8da1e900d758d078810d4255d8c6aa572181896a31ec79d779eb79c3adc9ad", size = 293637, upload-time = "2026-05-20T13:12:35.529Z" },
+ { url = "https://files.pythonhosted.org/packages/44/44/ba14b23e9757707050c2f397d305bbcae62e5d7cad122f8b6baec5ae4a1f/greenlet-3.5.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a19570c52a21420dcbc94e661994bc325c0b5b11304540fed514586da5dc8f2e", size = 650840, upload-time = "2026-05-20T14:00:11.079Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/37/5ddc2b686a6844f91abecef43411842426da2e1573f60b49ecf2547f4ae1/greenlet-3.5.1-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3d955c89b75eeca4723d7cc14135f393cd47c32e2a6cb4a8e4c6e760a26b0986", size = 656416, upload-time = "2026-05-20T14:05:47.118Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/46/5987dcd1a2570ba84f3b187536b2ca3ae97613387e57f5cfa99df068fe5e/greenlet-3.5.1-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea37d5a157eb9493820d3792ac4ece28619a394391d2b9f2f78057d396ff0f0f", size = 656607, upload-time = "2026-05-20T14:09:13.949Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/f0/d17510297c35a2992712f0bf84de3779749999f7d3d63aa1f09db7c62dbe/greenlet-3.5.1-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2daaaebd1a5aa88c49045b6baf9310b3263796bd88db713edf37cf53e7bb4e", size = 654397, upload-time = "2026-05-20T13:14:30.696Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/c1/6da0a9ddcc29d7e51ef14883fa3dc1e53b3f4ffba00582106c7bf55da1d8/greenlet-3.5.1-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:8d8a23250ea3ec7b36de8fa4b541e9e2db3ee82915cc060ab0631609ad8b28de", size = 488287, upload-time = "2026-05-20T14:01:43.143Z" },
+ { url = "https://files.pythonhosted.org/packages/37/eb/147387705bb89092645b012586e7273cb5ed3c90ef7eaf3a69173eaf0209/greenlet-3.5.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bfbd69cc349e43bf3a8ae1c85548ff0718efc887615c2db16c3833d7b0b072d", size = 1614469, upload-time = "2026-05-20T14:02:30.192Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/4e/37ee0da7732b7aa9896f17e15579a9df34b9fcb9dd494f0adfa749af6623/greenlet-3.5.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4378720dd888136c27215a0214d32a4d37c3852765d45bc37aad0623423cfd78", size = 1675115, upload-time = "2026-05-20T13:14:40.972Z" },
+ { url = "https://files.pythonhosted.org/packages/57/f3/97dfcf4a6eb5077f8a672234216fb5923eb89f2cab7081cb10b2cf75b605/greenlet-3.5.1-cp314-cp314t-win_amd64.whl", hash = "sha256:45718441607f9325d948db98cbc691276059316d0358c188c246da4e1d4d23d2", size = 245246, upload-time = "2026-05-20T13:12:22.646Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/73/d7f72e34b582f694f4a9b248162db7b09cc458a259ba8f0c0bfa1a34ea7d/greenlet-3.5.1-cp315-cp315-macosx_11_0_universal2.whl", hash = "sha256:2baee5ca02031757ffe8cc3d69f0cc0aec7065ce362622da74f32d3bcab1c541", size = 285575, upload-time = "2026-05-20T13:12:07.043Z" },
+ { url = "https://files.pythonhosted.org/packages/df/59/fa9c6e87dc8ad27a95dabe2f29f372b733d05a8a67470f6c901ed9975655/greenlet-3.5.1-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b1ec3274918a81d3ea778b9e75b56b72b33f300edb6cf7f3a7fe1dae56683de", size = 656428, upload-time = "2026-05-20T14:00:12.556Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/f9/e753408871eaa61dfe35e619cfc67512b036fde99893685d50eea9e07146/greenlet-3.5.1-cp315-cp315-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:111e2390ffffc47d5840b01711dd7fac07d4c09283d0283e7f3264b14e284c64", size = 667064, upload-time = "2026-05-20T14:05:48.662Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/74/807a047255bf1e09303627c46dc043dca596b6958a354d904f32ab382005/greenlet-3.5.1-cp315-cp315-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:10a9a1c0bfbc93d41156ffcb90c75fbc05544054faf15dcc1fdf9765f8b607f0", size = 672962, upload-time = "2026-05-20T14:09:15.532Z" },
+ { url = "https://files.pythonhosted.org/packages/96/27/5565b5b40389f1c7753003a07e21892fda8660926787036d5bc0308b8113/greenlet-3.5.1-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e630136e905fe5ff43e86945ae41220b6d1470956a39220e708110ac48d01ea5", size = 665697, upload-time = "2026-05-20T13:14:32.943Z" },
+ { url = "https://files.pythonhosted.org/packages/76/32/19d4e13225193c29b13e308015223f7d75fd3d8623d49dd19040d2ce8ec1/greenlet-3.5.1-cp315-cp315-manylinux_2_39_riscv64.whl", hash = "sha256:ef08c1567c78074b22d1a200183d52d04a14df447bf70bcbb6a3507a48e776fc", size = 476047, upload-time = "2026-05-20T14:01:44.39Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/82/e7de4178c0c2d1c9a5a3be3cc0b33e46a85b3ee4a77c071bf7ad8600e079/greenlet-3.5.1-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:975eac34b44a7077ca4d421348455b94f0f518246a7f14bc6d2fdcfe5b584368", size = 1621256, upload-time = "2026-05-20T14:02:31.91Z" },
+ { url = "https://files.pythonhosted.org/packages/00/10/f2dddcf7dacac17dfc68691809589adad06135eb28930429cf58a6467a2f/greenlet-3.5.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:9ab3c3a0b2ae6198e67c898dad5215a49f9ae0d0081b3c3ec59f333e39eeca26", size = 1685956, upload-time = "2026-05-20T13:14:42.55Z" },
+ { url = "https://files.pythonhosted.org/packages/22/17/4a232b32133230ada52f70e9d7f5b65b0caef8772f01849bd8d149e7e4ca/greenlet-3.5.1-cp315-cp315-win_amd64.whl", hash = "sha256:cbfc69be86e10dcfef5b1e6269d1d6926552aa89ee39e1de3353360c1b6989ab", size = 239802, upload-time = "2026-05-20T13:13:15.481Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/ae/4e623a7e6d4d2a5f4cb8e4c82de4169fc637942caae68d6e676b8a128ac5/greenlet-3.5.1-cp315-cp315-win_arm64.whl", hash = "sha256:92fd6d44ac5e5a887c8a5dc4a8ba0ba908527c31c12f78c6bc7dcfe8aab279f6", size = 236853, upload-time = "2026-05-20T13:15:37.301Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/57/816d9cff29119da3505b3d6a5e14a8af89006ac36f47f891ff293ee05af1/greenlet-3.5.1-cp315-cp315t-macosx_11_0_universal2.whl", hash = "sha256:a6fdf2433a5441ef9a95464f7c3e674775da1c8c1177fff311cee1acad4626ed", size = 293877, upload-time = "2026-05-20T13:10:19.078Z" },
+ { url = "https://files.pythonhosted.org/packages/23/a1/59b0a7c7d140ff1a75626680b9a9899b79a9176cab298b394968fb023295/greenlet-3.5.1-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7546556f0d649f99f6a361098a55f761181bb2ea12ff150bb16d26092ad88244", size = 655333, upload-time = "2026-05-20T14:00:14.758Z" },
+ { url = "https://files.pythonhosted.org/packages/72/1b/5efe127597625042218939d01855109f352779050768b670b52edcc16a6c/greenlet-3.5.1-cp315-cp315t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d5ee3ea898009fa898f85f9982255d35278c477bebe185beca249cab42d4526c", size = 659443, upload-time = "2026-05-20T14:05:50.159Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/9d/1dcdf7b95ab3cf8c7b6d7277c18a5e167312f2b362ddfcc5d5e6d8d84b43/greenlet-3.5.1-cp315-cp315t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a57b0d05a0448eed231d59c0ceb287dde984551e54cbc51ac2d4865712838e9c", size = 659998, upload-time = "2026-05-20T14:09:16.912Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/6d/c404246ea4d22d097a7426d0efb5b781bd7eb67715f09e79001bd552ab18/greenlet-3.5.1-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5c81f74d204d3edd136ebfd50dce53acbb776995d721a0fe801626cfc93b8cd", size = 658356, upload-time = "2026-05-20T13:14:35.091Z" },
+ { url = "https://files.pythonhosted.org/packages/05/7e/c4959664fc231d587d66d8e81f2095e98056ba1954beafdcbe635e251052/greenlet-3.5.1-cp315-cp315t-manylinux_2_39_riscv64.whl", hash = "sha256:b0703c2cef53e01baec47f7a3868009913ad71ec678bbecb42a6f40895e4ce62", size = 494470, upload-time = "2026-05-20T14:01:45.611Z" },
+ { url = "https://files.pythonhosted.org/packages/51/02/f8ee37fb6d2219329f350af241c27fcf12df57e723d11f6fc6d3bacdadaa/greenlet-3.5.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:2c18ef16bf6d4dd410e4dd52996888ea1497be26892fe5bbc73580aba4287b8e", size = 1619216, upload-time = "2026-05-20T14:02:33.403Z" },
+ { url = "https://files.pythonhosted.org/packages/93/c5/3dc9475ace2c7a3680da12372cddd7f1ac874eb410a1ac48d3e9dab83782/greenlet-3.5.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:17d86354f0ae6b61bf9be5148d0dd34e06c3cb7c602c671f79f29ac3b150e659", size = 1678427, upload-time = "2026-05-20T13:14:43.71Z" },
+ { url = "https://files.pythonhosted.org/packages/df/4e/750c15c317a41ffb36f0bf40b933e3d744a7dede61889f74443ea69690cf/greenlet-3.5.1-cp315-cp315t-win_amd64.whl", hash = "sha256:e7516cf6ae6b8a582c2770a0caed47b8a48373ed732c33d69a72913ae6ac923e", size = 245225, upload-time = "2026-05-20T13:13:59.366Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/fd/d3baea2eeb7b617efd47e87ca06e2ec2c6118d303aa9e918e0ce16eadc10/greenlet-3.5.1-cp315-cp315t-win_arm64.whl", hash = "sha256:5028648bf2253ec4745add746129d3904121fa7fe871a76bed23c5720573ce0a", size = 239590, upload-time = "2026-05-20T13:13:37.382Z" },
+]
+
+[[package]]
+name = "h11"
+version = "0.16.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
+]
+
+[[package]]
+name = "httpcore"
+version = "1.0.9"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "h11" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
+]
+
+[[package]]
+name = "httpx"
+version = "0.28.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+ { name = "certifi" },
+ { name = "httpcore" },
+ { name = "idna" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
+]
+
+[[package]]
+name = "identify"
+version = "2.6.19"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", size = 99567, upload-time = "2026-04-17T18:39:50.265Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", size = 99397, upload-time = "2026-04-17T18:39:49.221Z" },
+]
+
+[[package]]
+name = "idna"
+version = "3.16"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1a/88/bcf9709822fe69d02c2a6a77956c98ce6ea8ca8767a9aadcedc7eb6a2390/idna-3.16.tar.gz", hash = "sha256:d7a6da03db833450fca25d2358ac9ff06cd624577a4aea3a596d5c0f77b8e03d", size = 203770, upload-time = "2026-05-22T00:16:18.781Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/94/16/70255075a9859a0e3adb789b68ceb0e210dec03934245fd98d248226572f/idna-3.16-py3-none-any.whl", hash = "sha256:cc246e3a3f89580c3a951b5ad298ca4638078b2cdd4f115654332b5c26daded5", size = 74165, upload-time = "2026-05-22T00:16:16.698Z" },
+]
+
+[[package]]
+name = "iniconfig"
+version = "2.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
+]
+
+[[package]]
+name = "ipython"
+version = "9.13.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "decorator" },
+ { name = "ipython-pygments-lexers" },
+ { name = "jedi" },
+ { name = "matplotlib-inline" },
+ { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
+ { name = "prompt-toolkit" },
+ { name = "psutil" },
+ { name = "pygments" },
+ { name = "stack-data" },
+ { name = "traitlets" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/cd/c4/87cda5842cf5c31837c06ddb588e11c3c35d8ece89b7a0108c06b8c9b00a/ipython-9.13.0.tar.gz", hash = "sha256:7e834b6afc99f020e3f05966ced34792f40267d64cb1ea9043886dab0dde5967", size = 4430549, upload-time = "2026-04-24T12:24:55.221Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b9/86/3060e8029b7cc505cce9a0137431dda81d0a3fde93a8f0f50ee0bf37a795/ipython-9.13.0-py3-none-any.whl", hash = "sha256:57f9d4639e20818d328d287c7b549af3d05f12486ea8f2e7f73e52a36ec4d201", size = 627274, upload-time = "2026-04-24T12:24:53.038Z" },
+]
+
+[[package]]
+name = "ipython-pygments-lexers"
+version = "1.1.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" },
+]
+
+[[package]]
+name = "itsdangerous"
+version = "2.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" },
+]
+
+[[package]]
+name = "jedi"
+version = "0.20.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "parso" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/46/b7/a3635f6a2d7cf5b5dd98064fc1d5fbbafcb25477bcea204a3a92145d158b/jedi-0.20.0.tar.gz", hash = "sha256:c3f4ccbd276696f4b19c54618d4fb18f9fc24b0aef02acf704b23f487daa1011", size = 3119416, upload-time = "2026-05-01T23:38:47.814Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9a/93/242e2eab5fe682ffcb8b0084bde703a41d51e17ee0f3a31ff0d9d813620a/jedi-0.20.0-py2.py3-none-any.whl", hash = "sha256:7bdd9c2634f56713299976f4cbd59cb3fa92165cc5e05ea811fb253480728b67", size = 4884812, upload-time = "2026-05-01T23:38:43.919Z" },
+]
+
+[[package]]
+name = "jinja2"
+version = "3.1.6"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markupsafe" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
+]
+
+[[package]]
+name = "jmespath"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377, upload-time = "2026-01-22T16:35:26.279Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" },
+]
+
+[[package]]
+name = "jsbeautifier"
+version = "1.15.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "editorconfig" },
+ { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ea/98/d6cadf4d5a1c03b2136837a435682418c29fdeb66be137128544cecc5b7a/jsbeautifier-1.15.4.tar.gz", hash = "sha256:5bb18d9efb9331d825735fbc5360ee8f1aac5e52780042803943aa7f854f7592", size = 75257, upload-time = "2025-02-27T17:53:53.252Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2d/14/1c65fccf8413d5f5c6e8425f84675169654395098000d8bddc4e9d3390e1/jsbeautifier-1.15.4-py3-none-any.whl", hash = "sha256:72f65de312a3f10900d7685557f84cb61a9733c50dcc27271a39f5b0051bf528", size = 94707, upload-time = "2025-02-27T17:53:46.152Z" },
+]
+
+[[package]]
+name = "json5"
+version = "0.14.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9c/4b/6f8906aaf67d501e259b0adab4d312945bb7211e8b8d4dcc77c92320edaa/json5-0.14.0.tar.gz", hash = "sha256:b3f492fad9f6cdbced8b7d40b28b9b1c9701c5f561bef0d33b81c2ff433fefcb", size = 52656, upload-time = "2026-03-27T22:50:48.108Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b8/42/cf027b4ac873b076189d935b135397675dac80cb29acb13e1ab86ad6c631/json5-0.14.0-py3-none-any.whl", hash = "sha256:56cf861bab076b1178eb8c92e1311d273a9b9acea2ccc82c276abf839ebaef3a", size = 36271, upload-time = "2026-03-27T22:50:47.073Z" },
+]
+
+[[package]]
+name = "jsonschema"
+version = "4.26.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "attrs" },
+ { name = "jsonschema-specifications" },
+ { name = "referencing" },
+ { name = "rpds-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" }
+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]]
+name = "jsonschema-specifications"
+version = "2025.9.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "referencing" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" }
+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 = "kiwisolver"
+version = "1.5.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4d/b2/818b74ebea34dabe6d0c51cb1c572e046730e64844da6ed646d5298c40ce/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9", size = 123158, upload-time = "2026-03-09T13:13:23.127Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/d9/405320f8077e8e1c5c4bd6adc45e1e6edf6d727b6da7f2e2533cf58bff71/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588", size = 66388, upload-time = "2026-03-09T13:13:24.765Z" },
+ { url = "https://files.pythonhosted.org/packages/99/9f/795fedf35634f746151ca8839d05681ceb6287fbed6cc1c9bf235f7887c2/kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819", size = 64068, upload-time = "2026-03-09T13:13:25.878Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f", size = 1477934, upload-time = "2026-03-09T13:13:27.166Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/2f/cebfcdb60fd6a9b0f6b47a9337198bcbad6fbe15e68189b7011fd914911f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf", size = 1278537, upload-time = "2026-03-09T13:13:28.707Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/0d/9b782923aada3fafb1d6b84e13121954515c669b18af0c26e7d21f579855/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d", size = 1296685, upload-time = "2026-03-09T13:13:30.528Z" },
+ { url = "https://files.pythonhosted.org/packages/27/70/83241b6634b04fe44e892688d5208332bde130f38e610c0418f9ede47ded/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083", size = 1346024, upload-time = "2026-03-09T13:13:32.818Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/db/30ed226fb271ae1a6431fc0fe0edffb2efe23cadb01e798caeb9f2ceae8f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6", size = 987241, upload-time = "2026-03-09T13:13:34.435Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/bd/c314595208e4c9587652d50959ead9e461995389664e490f4dce7ff0f782/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1", size = 2227742, upload-time = "2026-03-09T13:13:36.4Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/43/0499cec932d935229b5543d073c2b87c9c22846aab48881e9d8d6e742a2d/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0", size = 2323966, upload-time = "2026-03-09T13:13:38.204Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/6f/79b0d760907965acfd9d61826a3d41f8f093c538f55cd2633d3f0db269f6/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15", size = 1977417, upload-time = "2026-03-09T13:13:39.966Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/31/01d0537c41cb75a551a438c3c7a80d0c60d60b81f694dac83dd436aec0d0/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314", size = 2491238, upload-time = "2026-03-09T13:13:41.698Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/34/8aefdd0be9cfd00a44509251ba864f5caf2991e36772e61c408007e7f417/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9", size = 2294947, upload-time = "2026-03-09T13:13:43.343Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384", size = 73569, upload-time = "2026-03-09T13:13:45.792Z" },
+ { url = "https://files.pythonhosted.org/packages/28/26/192b26196e2316e2bd29deef67e37cdf9870d9af8e085e521afff0fed526/kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7", size = 64997, upload-time = "2026-03-09T13:13:46.878Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/69/024d6711d5ba575aa65d5538042e99964104e97fa153a9f10bc369182bc2/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:fd40bb9cd0891c4c3cb1ddf83f8bbfa15731a248fdc8162669405451e2724b09", size = 123166, upload-time = "2026-03-09T13:13:48.032Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/48/adbb40df306f587054a348831220812b9b1d787aff714cfbc8556e38fccd/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0e1403fd7c26d77c1f03e096dc58a5c726503fa0db0456678b8668f76f521e3", size = 66395, upload-time = "2026-03-09T13:13:49.365Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/3a/d0a972b34e1c63e2409413104216cd1caa02c5a37cb668d1687d466c1c45/kiwisolver-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dda366d548e89a90d88a86c692377d18d8bd64b39c1fb2b92cb31370e2896bbd", size = 64065, upload-time = "2026-03-09T13:13:50.562Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/0a/7b98e1e119878a27ba8618ca1e18b14f992ff1eda40f47bccccf4de44121/kiwisolver-1.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:332b4f0145c30b5f5ad9374881133e5aa64320428a57c2c2b61e9d891a51c2f3", size = 1477903, upload-time = "2026-03-09T13:13:52.084Z" },
+ { url = "https://files.pythonhosted.org/packages/18/d8/55638d89ffd27799d5cc3d8aa28e12f4ce7a64d67b285114dbedc8ea4136/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c50b89ffd3e1a911c69a1dd3de7173c0cd10b130f56222e57898683841e4f96", size = 1278751, upload-time = "2026-03-09T13:13:54.673Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/97/b4c8d0d18421ecceba20ad8701358453b88e32414e6f6950b5a4bad54e65/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4db576bb8c3ef9365f8b40fe0f671644de6736ae2c27a2c62d7d8a1b4329f099", size = 1296793, upload-time = "2026-03-09T13:13:56.287Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/10/f862f94b6389d8957448ec9df59450b81bec4abb318805375c401a1e6892/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0b85aad90cea8ac6797a53b5d5f2e967334fa4d1149f031c4537569972596cb8", size = 1346041, upload-time = "2026-03-09T13:13:58.269Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/6a/f1650af35821eaf09de398ec0bc2aefc8f211f0cda50204c9f1673741ba9/kiwisolver-1.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:d36ca54cb4c6c4686f7cbb7b817f66f5911c12ddb519450bbe86707155028f87", size = 987292, upload-time = "2026-03-09T13:13:59.871Z" },
+ { url = "https://files.pythonhosted.org/packages/de/19/d7fb82984b9238115fe629c915007be608ebd23dc8629703d917dbfaffd4/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:38f4a703656f493b0ad185211ccfca7f0386120f022066b018eb5296d8613e23", size = 2227865, upload-time = "2026-03-09T13:14:01.401Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/b9/46b7f386589fd222dac9e9de9c956ce5bcefe2ee73b4e79891381dda8654/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ac2360e93cb41be81121755c6462cff3beaa9967188c866e5fce5cf13170859", size = 2324369, upload-time = "2026-03-09T13:14:02.972Z" },
+ { url = "https://files.pythonhosted.org/packages/92/8b/95e237cf3d9c642960153c769ddcbe278f182c8affb20cecc1cc983e7cc5/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c95cab08d1965db3d84a121f1c7ce7479bdd4072c9b3dafd8fecce48a2e6b902", size = 1977989, upload-time = "2026-03-09T13:14:04.503Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/95/980c9df53501892784997820136c01f62bc1865e31b82b9560f980c0e649/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc20894c3d21194d8041a28b65622d5b86db786da6e3cfe73f0c762951a61167", size = 2491645, upload-time = "2026-03-09T13:14:06.106Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/32/900647fd0840abebe1561792c6b31e6a7c0e278fc3973d30572a965ca14c/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a32f72973f0f950c1920475d5c5ea3d971b81b6f0ec53b8d0a956cc965f22e0", size = 2295237, upload-time = "2026-03-09T13:14:08.891Z" },
+ { url = "https://files.pythonhosted.org/packages/be/8a/be60e3bbcf513cc5a50f4a3e88e1dcecebb79c1ad607a7222877becaa101/kiwisolver-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bf3acf1419fa93064a4c2189ac0b58e3be7872bf6ee6177b0d4c63dc4cea276", size = 73573, upload-time = "2026-03-09T13:14:12.327Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/d2/64be2e429eb4fca7f7e1c52a91b12663aeaf25de3895e5cca0f47ef2a8d0/kiwisolver-1.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa8eb9ecdb7efb0b226acec134e0d709e87a909fa4971a54c0c4f6e88635484c", size = 64998, upload-time = "2026-03-09T13:14:13.469Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/69/ce68dd0c85755ae2de490bf015b62f2cea5f6b14ff00a463f9d0774449ff/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db485b3847d182b908b483b2ed133c66d88d49cacf98fd278fadafe11b4478d1", size = 125700, upload-time = "2026-03-09T13:14:14.636Z" },
+ { url = "https://files.pythonhosted.org/packages/74/aa/937aac021cf9d4349990d47eb319309a51355ed1dbdc9c077cdc9224cb11/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:be12f931839a3bdfe28b584db0e640a65a8bcbc24560ae3fdb025a449b3d754e", size = 67537, upload-time = "2026-03-09T13:14:15.808Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/20/3a87fbece2c40ad0f6f0aefa93542559159c5f99831d596050e8afae7a9f/kiwisolver-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:16b85d37c2cbb3253226d26e64663f755d88a03439a9c47df6246b35defbdfb7", size = 65514, upload-time = "2026-03-09T13:14:18.035Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/7f/f943879cda9007c45e1f7dba216d705c3a18d6b35830e488b6c6a4e7cdf0/kiwisolver-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4432b835675f0ea7414aab3d37d119f7226d24869b7a829caeab49ebda407b0c", size = 1584848, upload-time = "2026-03-09T13:14:19.745Z" },
+ { url = "https://files.pythonhosted.org/packages/37/f8/4d4f85cc1870c127c88d950913370dd76138482161cd07eabbc450deff01/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b0feb50971481a2cc44d94e88bdb02cdd497618252ae226b8eb1201b957e368", size = 1391542, upload-time = "2026-03-09T13:14:21.54Z" },
+ { url = "https://files.pythonhosted.org/packages/04/0b/65dd2916c84d252b244bd405303220f729e7c17c9d7d33dca6feeff9ffc4/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56fa888f10d0f367155e76ce849fa1166fc9730d13bd2d65a2aa13b6f5424489", size = 1404447, upload-time = "2026-03-09T13:14:23.205Z" },
+ { url = "https://files.pythonhosted.org/packages/39/5c/2606a373247babce9b1d056c03a04b65f3cf5290a8eac5d7bdead0a17e21/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:940dda65d5e764406b9fb92761cbf462e4e63f712ab60ed98f70552e496f3bf1", size = 1455918, upload-time = "2026-03-09T13:14:24.74Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/d1/c6078b5756670658e9192a2ef11e939c92918833d2745f85cd14a6004bdf/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:89fc958c702ee9a745e4700378f5d23fddbc46ff89e8fdbf5395c24d5c1452a3", size = 1072856, upload-time = "2026-03-09T13:14:26.597Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/c8/7def6ddf16eb2b3741d8b172bdaa9af882b03c78e9b0772975408801fa63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9027d773c4ff81487181a925945743413f6069634d0b122d0b37684ccf4f1e18", size = 2333580, upload-time = "2026-03-09T13:14:28.237Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/87/2ac1fce0eb1e616fcd3c35caa23e665e9b1948bb984f4764790924594128/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5b233ea3e165e43e35dba1d2b8ecc21cf070b45b65ae17dd2747d2713d942021", size = 2423018, upload-time = "2026-03-09T13:14:30.018Z" },
+ { url = "https://files.pythonhosted.org/packages/67/13/c6700ccc6cc218716bfcda4935e4b2997039869b4ad8a94f364c5a3b8e63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ce9bf03dad3b46408c08649c6fbd6ca28a9fce0eb32fdfffa6775a13103b5310", size = 2062804, upload-time = "2026-03-09T13:14:32.888Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/bd/877056304626943ff0f1f44c08f584300c199b887cb3176cd7e34f1515f1/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:fc4d3f1fb9ca0ae9f97b095963bc6326f1dbfd3779d6679a1e016b9baaa153d3", size = 2597482, upload-time = "2026-03-09T13:14:34.971Z" },
+ { url = "https://files.pythonhosted.org/packages/75/19/c60626c47bf0f8ac5dcf72c6c98e266d714f2fbbfd50cf6dab5ede3aaa50/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f443b4825c50a51ee68585522ab4a1d1257fac65896f282b4c6763337ac9f5d2", size = 2394328, upload-time = "2026-03-09T13:14:36.816Z" },
+ { url = "https://files.pythonhosted.org/packages/47/84/6a6d5e5bb8273756c27b7d810d47f7ef2f1f9b9fd23c9ee9a3f8c75c9cef/kiwisolver-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:893ff3a711d1b515ba9da14ee090519bad4610ed1962fbe298a434e8c5f8db53", size = 68410, upload-time = "2026-03-09T13:14:38.695Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/d7/060f45052f2a01ad5762c8fdecd6d7a752b43400dc29ff75cd47225a40fd/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8df31fe574b8b3993cc61764f40941111b25c2d9fea13d3ce24a49907cd2d615", size = 123231, upload-time = "2026-03-09T13:14:41.323Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/a7/78da680eadd06ff35edef6ef68a1ad273bad3e2a0936c9a885103230aece/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1d49a49ac4cbfb7c1375301cd1ec90169dfeae55ff84710d782260ce77a75a02", size = 66489, upload-time = "2026-03-09T13:14:42.534Z" },
+ { url = "https://files.pythonhosted.org/packages/49/b2/97980f3ad4fae37dd7fe31626e2bf75fbf8bdf5d303950ec1fab39a12da8/kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0cbe94b69b819209a62cb27bdfa5dc2a8977d8de2f89dfd97ba4f53ed3af754e", size = 64063, upload-time = "2026-03-09T13:14:44.759Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/f9/b06c934a6aa8bc91f566bd2a214fd04c30506c2d9e2b6b171953216a65b6/kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:80aa065ffd378ff784822a6d7c3212f2d5f5e9c3589614b5c228b311fd3063ac", size = 1475913, upload-time = "2026-03-09T13:14:46.247Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/f0/f768ae564a710135630672981231320bc403cf9152b5596ec5289de0f106/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e7f886f47ab881692f278ae901039a234e4025a68e6dfab514263a0b1c4ae05", size = 1282782, upload-time = "2026-03-09T13:14:48.458Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/9f/1de7aad00697325f05238a5f2eafbd487fb637cc27a558b5367a5f37fb7f/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5060731cc3ed12ca3a8b57acd4aeca5bbc2f49216dd0bec1650a1acd89486bcd", size = 1300815, upload-time = "2026-03-09T13:14:50.721Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/c2/297f25141d2e468e0ce7f7a7b92e0cf8918143a0cbd3422c1ad627e85a06/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a4aa69609f40fce3cbc3f87b2061f042eee32f94b8f11db707b66a26461591a", size = 1347925, upload-time = "2026-03-09T13:14:52.304Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/d3/f4c73a02eb41520c47610207b21afa8cdd18fdbf64ffd94674ae21c4812d/kiwisolver-1.5.0-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:d168fda2dbff7b9b5f38e693182d792a938c31db4dac3a80a4888de603c99554", size = 991322, upload-time = "2026-03-09T13:14:54.637Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/46/d3f2efef7732fcda98d22bf4ad5d3d71d545167a852ca710a494f4c15343/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:413b820229730d358efd838ecbab79902fe97094565fdc80ddb6b0a18c18a581", size = 2232857, upload-time = "2026-03-09T13:14:56.471Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/ec/2d9756bf2b6d26ae4349b8d3662fb3993f16d80c1f971c179ce862b9dbae/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5124d1ea754509b09e53738ec185584cc609aae4a3b510aaf4ed6aa047ef9303", size = 2329376, upload-time = "2026-03-09T13:14:58.072Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/9f/876a0a0f2260f1bde92e002b3019a5fabc35e0939c7d945e0fa66185eb20/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e4415a8db000bf49a6dd1c478bf70062eaacff0f462b92b0ba68791a905861f9", size = 1982549, upload-time = "2026-03-09T13:14:59.668Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/4f/ba3624dfac23a64d54ac4179832860cb537c1b0af06024936e82ca4154a0/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d618fd27420381a4f6044faa71f46d8bfd911bd077c555f7138ed88729bfbe79", size = 2494680, upload-time = "2026-03-09T13:15:01.364Z" },
+ { url = "https://files.pythonhosted.org/packages/39/b7/97716b190ab98911b20d10bf92eca469121ec483b8ce0edd314f51bc85af/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5092eb5b1172947f57d6ea7d89b2f29650414e4293c47707eb499ec07a0ac796", size = 2297905, upload-time = "2026-03-09T13:15:03.925Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/36/4e551e8aa55c9188bca9abb5096805edbf7431072b76e2298e34fd3a3008/kiwisolver-1.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:d76e2d8c75051d58177e762164d2e9ab92886534e3a12e795f103524f221dd8e", size = 75086, upload-time = "2026-03-09T13:15:07.775Z" },
+ { url = "https://files.pythonhosted.org/packages/70/15/9b90f7df0e31a003c71649cf66ef61c3c1b862f48c81007fa2383c8bd8d7/kiwisolver-1.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:fa6248cd194edff41d7ea9425ced8ca3a6f838bfb295f6f1d6e6bb694a8518df", size = 66577, upload-time = "2026-03-09T13:15:09.139Z" },
+ { url = "https://files.pythonhosted.org/packages/17/01/7dc8c5443ff42b38e72731643ed7cf1ed9bf01691ae5cdca98501999ed83/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d1ffeb80b5676463d7a7d56acbe8e37a20ce725570e09549fe738e02ca6b7e1e", size = 125794, upload-time = "2026-03-09T13:15:10.525Z" },
+ { url = "https://files.pythonhosted.org/packages/46/8a/b4ebe46ebaac6a303417fab10c2e165c557ddaff558f9699d302b256bc53/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc4d8e252f532ab46a1de9349e2d27b91fce46736a9eedaa37beaca66f574ed4", size = 67646, upload-time = "2026-03-09T13:15:12.016Z" },
+ { url = "https://files.pythonhosted.org/packages/60/35/10a844afc5f19d6f567359bf4789e26661755a2f36200d5d1ed8ad0126e5/kiwisolver-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6783e069732715ad0c3ce96dbf21dbc2235ab0593f2baf6338101f70371f4028", size = 65511, upload-time = "2026-03-09T13:15:13.311Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/8a/685b297052dd041dcebce8e8787b58923b6e78acc6115a0dc9189011c44b/kiwisolver-1.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e7c4c09a490dc4d4a7f8cbee56c606a320f9dc28cf92a7157a39d1ce7676a657", size = 1584858, upload-time = "2026-03-09T13:15:15.103Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/80/04865e3d4638ac5bddec28908916df4a3075b8c6cc101786a96803188b96/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a075bd7bd19c70cf67c8badfa36cf7c5d8de3c9ddb8420c51e10d9c50e94920", size = 1392539, upload-time = "2026-03-09T13:15:16.661Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/01/77a19cacc0893fa13fafa46d1bba06fb4dc2360b3292baf4b56d8e067b24/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bdd3e53429ff02aa319ba59dfe4ceeec345bf46cf180ec2cf6fd5b942e7975e9", size = 1405310, upload-time = "2026-03-09T13:15:18.229Z" },
+ { url = "https://files.pythonhosted.org/packages/53/39/bcaf5d0cca50e604cfa9b4e3ae1d64b50ca1ae5b754122396084599ef903/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cdcb35dc9d807259c981a85531048ede628eabcffb3239adf3d17463518992d", size = 1456244, upload-time = "2026-03-09T13:15:20.444Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/7a/72c187abc6975f6978c3e39b7cf67aeb8b3c0a8f9790aa7fd412855e9e1f/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:70d593af6a6ca332d1df73d519fddb5148edb15cd90d5f0155e3746a6d4fcc65", size = 1073154, upload-time = "2026-03-09T13:15:22.039Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/ca/cf5b25783ebbd59143b4371ed0c8428a278abe68d6d0104b01865b1bbd0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:377815a8616074cabbf3f53354e1d040c35815a134e01d7614b7692e4bf8acfa", size = 2334377, upload-time = "2026-03-09T13:15:23.741Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/e5/b1f492adc516796e88751282276745340e2a72dcd0d36cf7173e0daf3210/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0255a027391d52944eae1dbb5d4cc5903f57092f3674e8e544cdd2622826b3f0", size = 2425288, upload-time = "2026-03-09T13:15:25.789Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/e5/9b21fbe91a61b8f409d74a26498706e97a48008bfcd1864373d32a6ba31c/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:012b1eb16e28718fa782b5e61dc6f2da1f0792ca73bd05d54de6cb9561665fc9", size = 2063158, upload-time = "2026-03-09T13:15:27.63Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/02/83f47986138310f95ea95531f851b2a62227c11cbc3e690ae1374fe49f0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e3aafb33aed7479377e5e9a82e9d4bf87063741fc99fc7ae48b0f16e32bdd6f", size = 2597260, upload-time = "2026-03-09T13:15:29.421Z" },
+ { url = "https://files.pythonhosted.org/packages/07/18/43a5f24608d8c313dd189cf838c8e68d75b115567c6279de7796197cfb6a/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7a116ae737f0000343218c4edf5bd45893bfeaff0993c0b215d7124c9f77646", size = 2394403, upload-time = "2026-03-09T13:15:31.517Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/b5/98222136d839b8afabcaa943b09bd05888c2d36355b7e448550211d1fca4/kiwisolver-1.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1dd9b0b119a350976a6d781e7278ec7aca0b201e1a9e2d23d9804afecb6ca681", size = 79687, upload-time = "2026-03-09T13:15:33.204Z" },
+ { url = "https://files.pythonhosted.org/packages/99/a2/ca7dc962848040befed12732dff6acae7fb3c4f6fc4272b3f6c9a30b8713/kiwisolver-1.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:58f812017cd2985c21fbffb4864d59174d4903dd66fa23815e74bbc7a0e2dd57", size = 70032, upload-time = "2026-03-09T13:15:34.411Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/fa/2910df836372d8761bb6eff7d8bdcb1613b5c2e03f260efe7abe34d388a7/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797", size = 130262, upload-time = "2026-03-09T13:15:35.629Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/41/c5f71f9f00aabcc71fee8b7475e3f64747282580c2fe748961ba29b18385/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203", size = 138036, upload-time = "2026-03-09T13:15:36.894Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/06/7399a607f434119c6e1fdc8ec89a8d51ccccadf3341dee4ead6bd14caaf5/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7", size = 194295, upload-time = "2026-03-09T13:15:38.22Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/91/53255615acd2a1eaca307ede3c90eb550bae9c94581f8c00081b6b1c8f44/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57", size = 75987, upload-time = "2026-03-09T13:15:39.65Z" },
+]
+
+[[package]]
+name = "librt"
+version = "0.11.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/40/08/9e7f6b5d2b5bed6ad055cdd5925f192bb403a51280f86b56554d9d0699a2/librt-0.11.0.tar.gz", hash = "sha256:075dc3ef4458a278e0195cbf6ac9d38808d9b906c5a6c7f7f79c3888276a3fb1", size = 200139, upload-time = "2026-05-10T18:17:25.138Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8b/d0/07c77e067f0838949b43bd89232c29d72efebb9d2801a9750184eb706b71/librt-0.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b87504f1690a23b9a2cca841191a04f83895d4fc2dd04df91d82b1a04ca2ad46", size = 144147, upload-time = "2026-05-10T18:15:53.227Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/24/8493538fa4f62f982686398a5b8f68008138a75086abdea19ade64bf4255/librt-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40071fc5fe0ce8daa6de616702314a01e1250711682b0523d6ab8d4525910cb3", size = 143614, upload-time = "2026-05-10T18:15:54.657Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/1e/f8bad050810d9171f34a1648ed910e56814c2ba61639f2bd53c6377ae24b/librt-0.11.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:137e79445c896a0ea7b265f52d23954e05b64222ee1af69e2cb34219067cbb67", size = 485538, upload-time = "2026-05-10T18:15:56.117Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/fe/3594ebfbaf03084ba4b120c9ba5c3183fd938a48725e9bbe6ff0a5159ad8/librt-0.11.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:cca6644054e78746d8d4ef238681f9c34ff8b584fe6b988ecebb8db3b15e622a", size = 479623, upload-time = "2026-05-10T18:15:57.544Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/da/5d1876984b3746c85dbd219dbfcb73c85f54ee263fd32e5b2a632ec14571/librt-0.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5b0eea49f5562861ee8d757a32ef7d559c1d35be2aaaa1ec28941d74c9ffc8a", size = 513082, upload-time = "2026-05-10T18:15:58.805Z" },
+ { url = "https://files.pythonhosted.org/packages/19/6e/55bdf5d5ca00c3e18430690bf2c953d8d3ffd3c337418173d33dec985dc9/librt-0.11.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0d1029d7e1ae1a7e647ed6fb5df8c4ce2dffefb7a9f5fd1376a4554d96dac09f", size = 508105, upload-time = "2026-05-10T18:16:00.2Z" },
+ { url = "https://files.pythonhosted.org/packages/07/10/f1f23a7c595ee90ece4d35c851e5d104b1311a887ed1b4ac4c35bbd13da8/librt-0.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bc3ce6b33c5828d9e80592011a5c584cb2ce86edbc4088405f70da47dc1d1b3b", size = 522268, upload-time = "2026-05-10T18:16:01.708Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/02/5720f5697a7f54b78b3aefbe20df3a48cedcff1276618c4aa481177942ed/librt-0.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:936c5995f3514a42111f20099397d8177c79b4d7e70961e396c6f5a0a3566766", size = 527348, upload-time = "2026-05-10T18:16:03.496Z" },
+ { url = "https://files.pythonhosted.org/packages/50/db/b4a47c6f91db4ff76348a0b3dd0cc65e090a078b765a810a62ff9434c3d3/librt-0.11.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9bc0ca6ad9381cbe8e4aa6e5726e4c80c78115a6e9723c599ed1d73e092bc49d", size = 516294, upload-time = "2026-05-10T18:16:05.173Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/58/9384b2f4eb1ed1d273d40948a7c5c4b2360213b402ef3be4641c06299f9c/librt-0.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:070aa8c26c0a74774317a72df8851facc7f0f012a5b406557ac56992d92e1ec8", size = 553608, upload-time = "2026-05-10T18:16:06.839Z" },
+ { url = "https://files.pythonhosted.org/packages/21/7b/5aa8848a7c6a9278c79375146da1812e695754ceec5f005e6043461a7315/librt-0.11.0-cp312-cp312-win32.whl", hash = "sha256:6bf14feb84b05ae945277395451998c89c54d0def4070eb5c08de544930b245a", size = 101879, upload-time = "2026-05-10T18:16:08.103Z" },
+ { url = "https://files.pythonhosted.org/packages/37/33/8a745436944947575b584231750a41417de1a38cf6a2e9251d1065651c09/librt-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:75672f0bc524ede266287d532d7923dbce94c7514ad07627bac3d0c6d92cc4d9", size = 119831, upload-time = "2026-05-10T18:16:09.174Z" },
+ { url = "https://files.pythonhosted.org/packages/59/67/a6739ac96e28b7855808bdb0370e250606104a859750d209e5a0716fe7ab/librt-0.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:2f10cf143e4a9bb0f4f5af568a00df94a2d69ef41c2579584454bb0fe5cc642c", size = 103470, upload-time = "2026-05-10T18:16:10.369Z" },
+ { url = "https://files.pythonhosted.org/packages/82/61/e59168d4d0bf2bf90f4f0caf7a001bfc60254c3af4586013b04dc3ef517b/librt-0.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:78dc31f7fdfe9c9d0eb0e8f42d139db230e826415bbcabd9f0e9faaaee909894", size = 144119, upload-time = "2026-05-10T18:16:11.771Z" },
+ { url = "https://files.pythonhosted.org/packages/61/fd/caa1d60b12f7dd79ccea23054e06eeaebe266a5f52c40a6b651069200ce5/librt-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fa475675db22290c3158e1d42326d0f5a65f04f44a0e68c3630a25b53560fb9c", size = 143565, upload-time = "2026-05-10T18:16:13.334Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/a9/dc744f5c2b4978d48db970be29f22716d3413d28b14ad99740817315cf2c/librt-0.11.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:621db29691044bdeda22e789e482e1b0f3a985d90e3426c9c6d17606416205ea", size = 485395, upload-time = "2026-05-10T18:16:14.729Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/21/7f8e97a1e4dae952a5a95948f6f8507a173bc1e669f54340bba6ca1ca31b/librt-0.11.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:a9010e2ed5b3a9e158c5fd966b3ab7e834bb3d3aacc8f66c91dd4b57a3799230", size = 479383, upload-time = "2026-05-10T18:16:16.321Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/6d/d8ee9c114bebf2c50e29ec2aa940826fccb62a645c3e4c18760987d0e16d/librt-0.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c39513d8b7477a2e1ed8c43fc21c524e8d5a0f8d4e8b7b074dbdbe7820a08e2", size = 513010, upload-time = "2026-05-10T18:16:17.647Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/43/0b5708af2bd30a46400e72ba6bdaa8f066f15fb9a688527e34220e8d6c06/librt-0.11.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7aef3cf1d5af86e770ab04bfd993dfc4ae8b8c17f66fb77dd4a7d50de7bbb1a3", size = 508433, upload-time = "2026-05-10T18:16:19.309Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/50/356187247d09013490481033183b3532b58acf8028bcb34b2b56a375c9b2/librt-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:557183ddc36babe46b27dd60facbd5adb4492181a5be887587d57cda6e092f21", size = 522595, upload-time = "2026-05-10T18:16:20.642Z" },
+ { url = "https://files.pythonhosted.org/packages/40/e7/c6ac4240899c7f3248079d5a9900debe0dadb3fdeaf856684c987105ba47/librt-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:83d3e1f72bd42f6c5c0b7daec530c3f829bd02db42c70b8ddf0c2d90a2459930", size = 527255, upload-time = "2026-05-10T18:16:22.352Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/b5/a81322dbeedeeaf9c1ee6f001734d28a09d8383ac9e6779bc24bbd0743c6/librt-0.11.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4ce1f21fbe589bc1afd7872dece84fb0e1144f794a288e58a10d2c54a55c43be", size = 516847, upload-time = "2026-05-10T18:16:23.627Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/66/6e6323787d592b55204a42595ff1102da5115601b53a7e9ddebc889a6da5/librt-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b09f7044ea2b64c9da42fd3d335666518cfd1c6e8a182c95da73d0214b41e", size = 553920, upload-time = "2026-05-10T18:16:25.025Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/21/623f8ca230857102066d9ca8c6c1734995908c4d0d1bee7bb2ef0021cb33/librt-0.11.0-cp313-cp313-win32.whl", hash = "sha256:78fddc31cd4d3caa897ad5d31f856b1faadc9474021ad6cb182b9018793e254e", size = 101898, upload-time = "2026-05-10T18:16:26.649Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/1d/b4ebd44dd723f768469007515cb92251e0ae286c94c140f374801140fa74/librt-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ca8aa88751a775870b764e93bad5135385f563cb8dcee399abf034ea4d3cb47", size = 119812, upload-time = "2026-05-10T18:16:27.859Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/e4/b2f4ca7965ca373b491cdb4bc25cdb30c1649ca81a8782056a83850292a9/librt-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:96f044bb325fd9cf1a723015638c219e9143f0dfbc0ca54c565df2b7fc748b44", size = 103448, upload-time = "2026-05-10T18:16:29.066Z" },
+ { url = "https://files.pythonhosted.org/packages/29/eb/dbce197da4e227779e56b5735f2decc3eb36e55a1cdbf1bd65d6639d76c1/librt-0.11.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4a017a95e5837dc15a8c5661d60e05daa96b90908b1aa6b7acdf443cd25c8ebd", size = 143345, upload-time = "2026-05-10T18:16:30.674Z" },
+ { url = "https://files.pythonhosted.org/packages/76/a3/254bebd0c11c8ba684018efb8006ff22e466abce445215cca6c778e7d9de/librt-0.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b1ecbd9819deccc39b7542bf4d2a740d8a620694d39989e58661d3763458f8d4", size = 143131, upload-time = "2026-05-10T18:16:32.037Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/3f/f77d6122d21ac7bf6ae8a7dfced1bd2a7ac545d3273ebdcaf8042f6d619f/librt-0.11.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7da327dacd7be8f8ec36547373550744a3cc0e536d54665cd83f8bcd961200e8", size = 477024, upload-time = "2026-05-10T18:16:33.493Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/0a/2c996dadebaa7d9bbbd43ef2d4f3e66b6da545f838a41694ef6172cebec8/librt-0.11.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:0dc56b1f8d06e60db362cc3fdae206681817f86ce4725d34511473487f12a34b", size = 474221, upload-time = "2026-05-10T18:16:34.864Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/7e/f5d92af8486b8272c23b3e686b46ff72d89c8169585eb61eef01a2ac7147/librt-0.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05fb8fb2ab90e21c8d12ea240d744ad514da9baf381ebfa70d91d20d21713175", size = 505174, upload-time = "2026-05-10T18:16:36.705Z" },
+ { url = "https://files.pythonhosted.org/packages/af/1a/cb0734fe86398eb33193ab753b7326255c74cac5eb09e76b9b16536e7adb/librt-0.11.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cae74872be221df4374d10fec61f93ed1513b9546ea84f2c0bf73ab3e9bd0b03", size = 497216, upload-time = "2026-05-10T18:16:38.418Z" },
+ { url = "https://files.pythonhosted.org/packages/18/06/094820f91558b66e29943c0ec41c9914f460f48dd51fc503c3101e10842d/librt-0.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:32bcc918c0148eb7e3d57385125bac7e5f9e4359d05f07448b09f6f778c2f31c", size = 513921, upload-time = "2026-05-10T18:16:39.848Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/c2/00de9018871a282f530cacb457d5ec0428f6ac7e6fedde9aff7468d9fb04/librt-0.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f9743fc99135d5f78d2454435615f6dec0473ca507c26ce9d92b10b562a280d3", size = 520850, upload-time = "2026-05-10T18:16:41.471Z" },
+ { url = "https://files.pythonhosted.org/packages/51/9d/64631832348fd1834fb3a61b996434edddaaf25a31d03b0a76273159d2cf/librt-0.11.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:5ba067f4aadae8fda802d91d2124c90c42195ff32d9161d3549e6d05cfe26f96", size = 504237, upload-time = "2026-05-10T18:16:43.15Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/ec/ae5525eb16edc827a044e7bb8777a455ff95d4bca9379e7e6bddd7383647/librt-0.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:de3bf945454d032f9e390b85c4072e0a0570bf825421c8be0e71209fa65e1abe", size = 546261, upload-time = "2026-05-10T18:16:44.408Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/09/adce371f27ca039411da9659f7430fcc2ba6cd0c7b3e4467a0f091be7fa9/librt-0.11.0-cp314-cp314-win32.whl", hash = "sha256:d2277a05f6dcb9fd13db9566aac4fabd68c3ea1ea46ee5567d4eef8efa495a2f", size = 96965, upload-time = "2026-05-10T18:16:46.039Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/ee/8ac720d98548f173c7ce2e632a7ca94673f74cacd5c8162a84af5b35958a/librt-0.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:ab73e8db5e3f564d812c1f5c3a175930a5f9bc96ccb5e3b22a34d7858b401cf7", size = 115151, upload-time = "2026-05-10T18:16:47.133Z" },
+ { url = "https://files.pythonhosted.org/packages/94/20/c900cf14efeb09b6bef2b2dff20779f73464b97fd58d1c6bccc379588ae3/librt-0.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:aea3caa317752e3a466fa8af45d91ee0ea8c7fdd96e42b0a8dd9b76a7931eba1", size = 98850, upload-time = "2026-05-10T18:16:48.597Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/71/944bfe4b64e12abffcd3c15e1cce07f72f3d55655083786285f4dedeb532/librt-0.11.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d1b36540d7aaf9b9101b3a6f376c8d8e9f7a9aec93ed05918f2c69d493ffef72", size = 151138, upload-time = "2026-05-10T18:16:49.839Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/10/99e64a5c86989357fda078c8143c533389585f6473b7439172dd8f3b3b2d/librt-0.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:efbb343ab2ce3540f4ecbe6315d677ed70f37cd9a72b1e58066c918ca83acbaa", size = 151976, upload-time = "2026-05-10T18:16:51.062Z" },
+ { url = "https://files.pythonhosted.org/packages/21/31/5072ad880946d83e5ea4147d6d018c78eefce85b77819b19bdd0ee229435/librt-0.11.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0dd688aab3f7914d3e6e5e3554978e0383312fb8e771d84be008a35b9ee548", size = 557927, upload-time = "2026-05-10T18:16:52.632Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/8d/70b5fb7cfbab60edbe7381614ab985da58e144fbf465c86d44c95f43cdca/librt-0.11.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f5fb36b8c6c63fdcbb1d526d94c0d1331610d43f4118cc1beb4efef4f3faacb2", size = 539698, upload-time = "2026-05-10T18:16:53.934Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/a3/ba3495a0b3edbd24a4cae0d1d3c64f39a9fc45d06e812101289b50c1a619/librt-0.11.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4a9a237d13addb93715b6fee74023d5ee3469b53fce527626c0e088aa585805f", size = 577162, upload-time = "2026-05-10T18:16:55.589Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/db/36e25fb81f99937ff1b96612a1dc9fd66f039cb9cc3aee12c01fac31aab9/librt-0.11.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5ddd17bd87b2c56ddd60e546a7984a2e64c4e8eab92fb4cf3830a48ad5469d51", size = 566494, upload-time = "2026-05-10T18:16:56.975Z" },
+ { url = "https://files.pythonhosted.org/packages/33/0d/3f622b47f0b013eeb9cf4cc07ae9bfe378d832a4eec998b2b209fe84244d/librt-0.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd43992b4473d42f12ff9e68326079f0696d9d4e6000e8f39a0238d482ba6ee2", size = 596858, upload-time = "2026-05-10T18:16:58.374Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/02/71b90bc93039c46a2000651f6ad60122b114c8f54c4ad306e0e96f5b75ad/librt-0.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:f8e3e8056dd674e279741485e2e512d6e9a751c7455809d0114e6ebf8d781085", size = 590318, upload-time = "2026-05-10T18:16:59.676Z" },
+ { url = "https://files.pythonhosted.org/packages/04/04/418cb3f75621e2b761fb1ab0f017f4d70a1a72a6e7c74ee4f7e8d198c2f3/librt-0.11.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c1f708d8ae9c56cf38a903c44297243d2ec83fd82b396b977e0144a3e76217e3", size = 575115, upload-time = "2026-05-10T18:17:01.007Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/2c/5a2183ac58dd911f26b5d7e7d7d8f1d87fcecdddd99d6c12169a258ff62c/librt-0.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0add982e0e7b9fc14cf4b33789d5f13f66581889b88c2f58099f6ce8f92617bd", size = 617918, upload-time = "2026-05-10T18:17:02.682Z" },
+ { url = "https://files.pythonhosted.org/packages/15/1f/dc6771a52592a4451be6effa200cbfc9cec61e4393d3033d81a9d307961d/librt-0.11.0-cp314-cp314t-win32.whl", hash = "sha256:2b481d846ac894c4e8403c5fd0e87c5d11d6499e404b474602508a224ff531c8", size = 103562, upload-time = "2026-05-10T18:17:03.99Z" },
+ { url = "https://files.pythonhosted.org/packages/62/4a/7d1415567027286a75ba1093ec4aca11f073e0f559c530cf3e0a757ad55c/librt-0.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:28edb433edde181112a908c78907af28f964eabc15f4dd16c9d66c834302677c", size = 124327, upload-time = "2026-05-10T18:17:05.465Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/62/b40b382fa0c66fee1478073eb8db352a4a6beda4a1adccf1df911d8c289c/librt-0.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dee008f20b542e3cd162ba338a7f9ec0f6d23d395f66fe8aeeec3c9d067ea253", size = 102572, upload-time = "2026-05-10T18:17:06.809Z" },
+]
+
+[[package]]
+name = "markdown-it-py"
+version = "4.2.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mdurl" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" },
+]
+
+[[package]]
+name = "markupsafe"
+version = "3.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" },
+ { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" },
+ { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" },
+ { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" },
+ { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" },
+ { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" },
+ { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" },
+ { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" },
+ { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" },
+ { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" },
+ { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" },
+ { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" },
+ { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" },
+ { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" },
+ { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" },
+ { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" },
+ { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" },
+ { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" },
+ { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" },
+ { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" },
+ { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" },
+ { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" },
+ { 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 = "matplotlib"
+version = "3.10.9"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "contourpy" },
+ { name = "cycler" },
+ { name = "fonttools" },
+ { name = "kiwisolver" },
+ { name = "numpy" },
+ { name = "packaging" },
+ { name = "pillow" },
+ { name = "pyparsing" },
+ { name = "python-dateutil" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/63/1b/4be5be87d43d327a0cf4de1a56e86f7f84c89312452406cf122efe2839e6/matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358", size = 34811233, upload-time = "2026-04-24T00:14:13.539Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/35/c6/5581e26c72233ebb2a2a6fed2d24fb7c66b4700120b813f51b0555acf0b6/matplotlib-3.10.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f0c3c28d9fbcc1fe7a03be236d73430cf6409c41fb2383a7ac52fe932b072cb1", size = 8319908, upload-time = "2026-04-24T00:12:21.323Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/18/4880dd762e40cd360c1bf06e890c5a97b997e91cb324602b1a19950ad5ce/matplotlib-3.10.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cb28c2bd769aa3e98322c6ab09854cbcc52ab69d2759d681bba3e327b2b320", size = 8216016, upload-time = "2026-04-24T00:12:23.4Z" },
+ { url = "https://files.pythonhosted.org/packages/32/91/d024616abdba99e83120e07a20658976f6a343646710760c4a51df126029/matplotlib-3.10.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ae20801130378b82d647ff5047c07316295b68dc054ca6b3c13519d0ea624285", size = 8789336, upload-time = "2026-04-24T00:12:26.096Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/04/030a2f61ef2158f5e4c259487a92ac877732499fb33d871585d89e03c42d/matplotlib-3.10.9-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c63ebcd8b4b169eb2f5c200552ae6b8be8999a005b6b507ed76fb8d7d674fe2", size = 9604602, upload-time = "2026-04-24T00:12:29.052Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/c2/541e4d09d87bb6b5830fc28b4c887a9a8cf4e1c6cee698a8c05552ae2003/matplotlib-3.10.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d75d11c949914165976c621b2324f9ef162af7ebf4b057ddf95dd1dba7e5edcf", size = 9670966, upload-time = "2026-04-24T00:12:32.131Z" },
+ { url = "https://files.pythonhosted.org/packages/04/a1/4571fc46e7702de8d0c2dc54ad1b2f8e29328dea3ee90831181f7353d93c/matplotlib-3.10.9-cp312-cp312-win_amd64.whl", hash = "sha256:d091f9d758b34aaaaa6331d13574bf01891d903b3dec59bfff458ef7551de5d6", size = 8217462, upload-time = "2026-04-24T00:12:35.226Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/d0/2269edb12aa30c13c8bcc9382892e39943ce1d28aab4ec296e0381798e81/matplotlib-3.10.9-cp312-cp312-win_arm64.whl", hash = "sha256:10cc5ce06d10231c36f40e875f3c7e8050362a4ee8f0ee5d29a6b3277d57bb42", size = 8136688, upload-time = "2026-04-24T00:12:37.442Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/d3/8d4f6afbecb49fc04e060a57c0fce39ea51cc163a6bd87303ccd698e4fa6/matplotlib-3.10.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b580440f1ff81a0e34122051a3dfabb7e4b7f9e380629929bde0eff9af72165f", size = 8320331, upload-time = "2026-04-24T00:12:39.688Z" },
+ { url = "https://files.pythonhosted.org/packages/63/d9/9e14bc7564bf92d5ffa801ae5fac819ce74b925dfb55e3ebde61a3bbad3e/matplotlib-3.10.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b1b745c489cd1a77a0dc1120a05dc87af9798faebc913601feb8c73d89bf2d1e", size = 8216461, upload-time = "2026-04-24T00:12:42.494Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/17/4402d0d14ccf1dfc70932600b68097fbbf9c898a4871d2cbbe79c7801a32/matplotlib-3.10.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8f3bcac1ca5ed000a6f4337d47ba67dfddf37ed6a46c15fd7f014997f7bf865f", size = 8790091, upload-time = "2026-04-24T00:12:44.789Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/0b/322aeec06dd9b91411f92028b37d447342770a24392aa4813e317064dad5/matplotlib-3.10.9-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a8d66a55def891c33147ba3ba9bfcabf0b526a43764c818acbb4525e5ed0838", size = 9605027, upload-time = "2026-04-24T00:12:47.583Z" },
+ { url = "https://files.pythonhosted.org/packages/74/88/5f13482f55e7b00bcfc09838b093c2456e1379978d2a146844aae05350ad/matplotlib-3.10.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d843374407c4017a6403b59c6c81606773d136f3259d5b6da3131bc814542cc2", size = 9671269, upload-time = "2026-04-24T00:12:50.878Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/e0/0840fd2f93da988ec660b8ad1984abe9f25d2aed22a5e394ff1c68c88307/matplotlib-3.10.9-cp313-cp313-win_amd64.whl", hash = "sha256:f4399f64b3e94cd500195490972ae1ee81170df1636fa15364d157d5bdd7b921", size = 8217588, upload-time = "2026-04-24T00:12:53.784Z" },
+ { url = "https://files.pythonhosted.org/packages/47/b9/d706d06dd605c49b9f83a2aed8c13e3e5db70697d7a80b7e3d7915de6b17/matplotlib-3.10.9-cp313-cp313-win_arm64.whl", hash = "sha256:ba7b3b8ef09eab7df0e86e9ae086faa433efbfbdb46afcb3aa16aabf779469a8", size = 8136913, upload-time = "2026-04-24T00:12:56.501Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/45/6e32d96978264c8ca8c4b1010adb955a1a49cfaf314e212bbc8908f04a61/matplotlib-3.10.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:09218df8a93712bd6ea133e83a153c755448cf7868316c531cffcc43f69d1cc9", size = 8368019, upload-time = "2026-04-24T00:12:58.896Z" },
+ { url = "https://files.pythonhosted.org/packages/86/0a/c8e3d3bba245f0f7fc424937f8ff7ef77291a36af3edb97ccd78aa93d84f/matplotlib-3.10.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:82368699727bfb7b0182e1aa13082e3c08e092fa1a25d3e1fd92405bff96f6d4", size = 8264645, upload-time = "2026-04-24T00:13:01.406Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/aa/5bf5a14fe4fed73a4209a155606f8096ff797aad89c6c35179026571133e/matplotlib-3.10.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3225f4e1edcb8c86c884ddf79ebe20ecd0a67d30188f279897554ccd8fded4dc", size = 8802194, upload-time = "2026-04-24T00:13:03.702Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/5e/b4be852d6bba6fd15893fadf91ff26ae49cb91aac789e95dde9d342e664f/matplotlib-3.10.9-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de2445a0c6690d21b7eb6ce071cebad6d40a2e9bdf10d039074a96ba19797b99", size = 9622684, upload-time = "2026-04-24T00:13:06.647Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/3d/ed428c971139112ef730f62770654d609467346d09d4b62617e1afd68a5a/matplotlib-3.10.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:b2b9516251cb89ff618d757daec0e2ed1bf21248013844a853d87ef85ab3081d", size = 9680790, upload-time = "2026-04-24T00:13:10.009Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/09/052e884aaf2b985c63cb79f715f1d5b6a3eaa7de78f6a52b9dbc077d5b53/matplotlib-3.10.9-cp313-cp313t-win_amd64.whl", hash = "sha256:e9fae004b941b23ff2edcf1567a857ed77bafc8086ffa258190462328434faf8", size = 8287571, upload-time = "2026-04-24T00:13:13.087Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/38/ae27288e788c35a4250491422f3db7750366fc8c97d6f36fbdecfc1f5518/matplotlib-3.10.9-cp313-cp313t-win_arm64.whl", hash = "sha256:6b63d9c7c769b88ab81e10dc86e4e0607cf56817b9f9e6cf24b2a5f1693b8e38", size = 8188292, upload-time = "2026-04-24T00:13:15.546Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/e6/3bd8afd04949f02eabc1c17115ea5255e19cacd4d06fc5abdde4eeb0052c/matplotlib-3.10.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:172db52c9e683f5d12eaf57f0f54834190e12581fe1cc2a19595a8f5acb4e77d", size = 8321276, upload-time = "2026-04-24T00:13:18.318Z" },
+ { url = "https://files.pythonhosted.org/packages/41/86/86231232fff41c9f8e4a1a7d7a597d349a02527109c3af7d618366122139/matplotlib-3.10.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97e35e8d39ccc85859095e01a53847432ba9a53ddf7986f7a54a11b73d0e143f", size = 8218218, upload-time = "2026-04-24T00:13:20.974Z" },
+ { url = "https://files.pythonhosted.org/packages/85/8f/becc9722cafc64f5d2eb0b7c1bf5f585271c618a45dbd8fabeb021f898b6/matplotlib-3.10.9-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aba1615dabe83188e19d4f75a253c6a08423e04c1425e64039f800050a69de6b", size = 9608145, upload-time = "2026-04-24T00:13:23.228Z" },
+ { url = "https://files.pythonhosted.org/packages/32/5d/f7e914f7d9325abff4057cee62c0fa70263683189f774473cbfb534cd13b/matplotlib-3.10.9-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34cf8167e023ad956c15f36302911d5406bd99a9862c1a8499ea6f7c0e015dc2", size = 9885085, upload-time = "2026-04-24T00:13:25.849Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/fd/fa69f2221534e80cc5772ac2b7d222011a2acafc2ec7216d5dd174c864ae/matplotlib-3.10.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:59476c6d29d612b8e9bb6ce8c5b631be6ba8f9e3a2421f22a02b192c7dd28716", size = 9672358, upload-time = "2026-04-24T00:13:28.906Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/1a/5a4f747a8b271cbb024946d2dd3c913ab5032ba430626f8c3528ada96b4b/matplotlib-3.10.9-cp314-cp314-win_amd64.whl", hash = "sha256:336b9acc64d309063126edcdaca00db9373af3c476bb94388fe9c5a53ad13e6f", size = 8349970, upload-time = "2026-04-24T00:13:31.904Z" },
+ { url = "https://files.pythonhosted.org/packages/64/dc/95d60ecaefe30680a154b52ea96ab4b0dab547f1fd6aa12f5fb655e89cae/matplotlib-3.10.9-cp314-cp314-win_arm64.whl", hash = "sha256:2dc9477819ffd78ad12a20df1d9d6a6bd4fec6aaa9072681465fddca052f1456", size = 8272785, upload-time = "2026-04-24T00:13:34.511Z" },
+ { url = "https://files.pythonhosted.org/packages/70/a0/005d68bc8b8418300ce6591f18586910a8526806e2ab663933d9f20a41e9/matplotlib-3.10.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:da4e09638420548f31c354032a6250e473c68e5a4e96899b4844cf39ddea23fe", size = 8367999, upload-time = "2026-04-24T00:13:36.962Z" },
+ { url = "https://files.pythonhosted.org/packages/22/05/1236cc9290be70b2498af20ca348add76e3fffe7f67b477db5133a84f3ea/matplotlib-3.10.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:345f6f68ecc8da0ca56fad2ea08fde1a115eda530079eca185d50a7bc3e146c6", size = 8264543, upload-time = "2026-04-24T00:13:39.851Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/c2/071f5a5ff6c5bd63aaaf2f45c811d9bf2ced94bde188d9e1a519e21d0cba/matplotlib-3.10.9-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4edcfbd8565339aa62f1cd4012f7180926fdbe71850f7b0d3c379c175cd6b66c", size = 9622800, upload-time = "2026-04-24T00:13:42.296Z" },
+ { url = "https://files.pythonhosted.org/packages/95/57/da7d1f10a85624b9e7db68e069dd94e58dc41dbf9463c5921632ecbe3661/matplotlib-3.10.9-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6be157fe17fc37cb95ac1d7374cf717ce9259616edec911a78d9d26dae8522d4", size = 9888561, upload-time = "2026-04-24T00:13:45.026Z" },
+ { url = "https://files.pythonhosted.org/packages/67/b2/ef8d6bb59b0edb6c16c968b70f548aa13b54348972def5aa6ac85df67145/matplotlib-3.10.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4e42042d54db34fda4e95a7bd3e5789c2a995d2dad3eb8850232ee534092fbbf", size = 9680884, upload-time = "2026-04-24T00:13:48.066Z" },
+ { url = "https://files.pythonhosted.org/packages/61/1c/d21bfeb9931881ebe96bcfcff27c7ae4b160ae0ec291a714c42641a56d75/matplotlib-3.10.9-cp314-cp314t-win_amd64.whl", hash = "sha256:c27df8b3848f32a83d1767566595e43cfaa4460380974da06f4279a7ec143c39", size = 8432333, upload-time = "2026-04-24T00:13:51.008Z" },
+ { url = "https://files.pythonhosted.org/packages/78/23/92493c3e6e1b635ccfff146f7b99e674808787915420373ac399283764c2/matplotlib-3.10.9-cp314-cp314t-win_arm64.whl", hash = "sha256:a49f1eadc84ca85fd72fa4e89e70e61bf86452df6f971af04b12c60761a0772c", size = 8324785, upload-time = "2026-04-24T00:13:53.633Z" },
+]
+
+[[package]]
+name = "matplotlib-inline"
+version = "0.2.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "traitlets" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/bd/c0/9f7c9a46090390368a4d7bcb76bb87a4a36c421e4c0792cdb53486ffac7a/matplotlib_inline-0.2.2.tar.gz", hash = "sha256:72f3fe8fce36b70d4a5b612f899090cd0401deddc4ea90e1572b9f4bfb058c79", size = 8150, upload-time = "2026-05-08T17:33:33.49Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/41/09/5b161152e2d90f7b87f781c2e1267494aef9c32498df793f73ad0a0a494a/matplotlib_inline-0.2.2-py3-none-any.whl", hash = "sha256:3c821cf1c209f59fb2d2d64abbf5b23b67bcb2210d663f9918dd851c6da1fcf6", size = 9534, upload-time = "2026-05-08T17:33:32.055Z" },
+]
+
+[[package]]
+name = "mdurl"
+version = "0.1.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
+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 = "meridian-euid"
+version = "0.4.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9e/ae/2e51a25fd422f39d0b8cc7b65ad9f32309efad6cadaaa15ab16f29585a98/meridian_euid-0.4.5.tar.gz", hash = "sha256:5423d40c4a200d86dc1e0b5df47d3d1aecdf5a30f9668849e4f857deb956e218", size = 15247, upload-time = "2026-05-16T11:47:36.548Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0e/8d/02dc20a37f126beca0ca197796be8ee44db463c9417efa350715046915d0/meridian_euid-0.4.5-py3-none-any.whl", hash = "sha256:c07d760f26d47a7cee489b71fe11a4df69a9ba094cde57aad2fca8415a05bee8", size = 12073, upload-time = "2026-05-16T11:47:35.645Z" },
+]
+
+[[package]]
+name = "moto"
+version = "5.2.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "boto3" },
+ { name = "botocore" },
+ { name = "cryptography" },
+ { name = "requests" },
+ { name = "responses" },
+ { name = "werkzeug" },
+ { name = "xmltodict" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f6/e9/c38202162db2e76623176be9f1dbc9aa41228ffa91ee8da2d3986082c3e3/moto-5.2.1.tar.gz", hash = "sha256:ccb2f3e1dfa82e50e054bda98b0be708d244d2668364dcc1d45e8d3de6091bde", size = 8634437, upload-time = "2026-05-10T19:11:57.286Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/15/79/8085b7c1ecd48d0535c3c8444a1d8df2926e457dce8e55fabc332a382c9c/moto-5.2.1-py3-none-any.whl", hash = "sha256:19d2fbd6e613aa5b4e364c52cd5d3cea371643a0f4210689a703227bd2924c5c", size = 6671379, upload-time = "2026-05-10T19:11:53.543Z" },
+]
+
+[[package]]
+name = "mypy"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "ast-serialize" },
+ { name = "librt", marker = "platform_python_implementation != 'PyPy'" },
+ { name = "mypy-extensions" },
+ { name = "pathspec" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/82/15/cca9d88503549ed6fedeaa1d448cdddd542ee8a490232d732e278036fbf2/mypy-2.1.0.tar.gz", hash = "sha256:81e76ad12c2d804512e9b13240d1588316531bfba07558286078bfbce9613633", size = 3898359, upload-time = "2026-05-11T18:37:36.237Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/95/b1/55861beb5c339b44f9a2ba92df9e2cb1eeb4ae1eee674cdf7772c797778b/mypy-2.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:244358bf1c0da7722230bce60683d52e8e9fd030554926f15b747a84efb5b3af", size = 14874381, upload-time = "2026-05-11T18:37:31.784Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/b3/b7f770114b7d0ac92d0f76e8d93c2780844a70488a90e91821927850da86/mypy-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4ec7c57657493c7a75534df2751c8ae2cda383c16ecc55d2106c54476b1b16f6", size = 13665501, upload-time = "2026-05-11T18:34:23.063Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/f3/8ae2037967e2126689a0c11d99e2b707134a565191e92c60ca2572aec60a/mypy-2.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8161b6ff4392410023224f0969d17db93e1e154bc3e4ba62598e720723ae211", size = 14045750, upload-time = "2026-05-11T18:31:48.151Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/32/615eb5911859e43d054941b0d0a7d06cfa2870eba86529cf385b052b111c/mypy-2.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf03e12003084a67395184d3eb8cbd6a489dc3655b5664b28c210a9e2403ab0b", size = 15061630, upload-time = "2026-05-11T18:37:06.898Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/03/4eafbfff8bfab1b87082741eae6e6a624028c984e6708b73bce2a8570c9d/mypy-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:20509760fd791c51579d573153407d226385ec1f8bcce55d730b354f3336bc22", size = 15288831, upload-time = "2026-05-11T18:31:18.07Z" },
+ { url = "https://files.pythonhosted.org/packages/99/ee/919661478e5891a3c96e549c036e467e64563ab85995b10c53c8358e16a3/mypy-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:6753d0c1fdd6b1a23b9e4f283ce80b2153b724adcb2653b20b85a8a28ac6436b", size = 11135228, upload-time = "2026-05-11T18:34:31.23Z" },
+ { url = "https://files.pythonhosted.org/packages/24/0a/6a12b9782ca0831a553192f351679f4548abc9d19a7cc93bb7feb02084c7/mypy-2.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:98ebb6589bb3b6d0c6f0c459d53ca55b8091fbc13d277c4041c885392e8195e8", size = 10040684, upload-time = "2026-05-11T18:36:48.199Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/dd/c7191469c777f07689c032a8f7326e393ea34c92d6d76eb7ce5ba57ea66d/mypy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35aac3bb114e03888f535d5eb51b8bafbb3266586b599da1940f9b1be3ec5bd5", size = 14852174, upload-time = "2026-05-11T18:31:38.929Z" },
+ { url = "https://files.pythonhosted.org/packages/55/8c/aed55408879043d72bb9135f4d0d19a02b886dd569631e113e3d2706cb8d/mypy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8de55a8c861f2a49331f807be98d90caeceeef520bde13d43a160207f8af613e", size = 13651542, upload-time = "2026-05-11T18:36:04.636Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/8e/f371a824b1f1fa8ea6e3dbb8703d232977d572be2329554a3bc4d960302f/mypy-2.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5fdf2941a07434af755837d9880f7d7d25f1dacb1af9dcd4b9b66f2220a3024e", size = 14033929, upload-time = "2026-05-11T18:35:55.742Z" },
+ { url = "https://files.pythonhosted.org/packages/94/21/f54be870d6dd53a82c674407e0f8eed7174b05ec78d42e5abd7b42e84fd5/mypy-2.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e195b817c13f02352a9c124301f9f30f078405444679b6753c1b96b6eed37285", size = 15039200, upload-time = "2026-05-11T18:33:10.281Z" },
+ { url = "https://files.pythonhosted.org/packages/17/99/bf21748626a40ce59fd29a39386ab46afec88b7bd2f0fa6c3a97c995523f/mypy-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5431d42af987ebd92ba2f71d45c85ed41d8e6ca9f5fd209a69f68f707d2469e5", size = 15272690, upload-time = "2026-05-11T18:32:07.205Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/d7/9e90d2cf47100bea550ed2bc7b0d4de3a62181d84d5e37da0003e8462637/mypy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:767fe8c66dc3e01e19e1737d4c38ebefead16125e1b8e58ad421903b376f5c65", size = 11147435, upload-time = "2026-05-11T18:33:56.477Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/46/e5c449e858798e35ffc90946282a27c62a77be743fe17480e4977374eb91/mypy-2.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:ecfe70d43775ab99562ab128ce49854a362044c9f894961f68f898c23cb7429d", size = 10035052, upload-time = "2026-05-11T18:32:30.049Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/ca/b279a672e874aedd5498ae25f722dacc8aa86bbffb939b3f97cbb1cf6686/mypy-2.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:7354c5a7f69d9345c3d6e69921d57088eea3ddeeb6b20d34c1b3855b02c36ec2", size = 14848422, upload-time = "2026-05-11T18:35:45.984Z" },
+ { url = "https://files.pythonhosted.org/packages/27/e6/3efe56c631d959b9b4454e208b0ac4b7f4f58b404c89f8bec7b49efdfc21/mypy-2.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:49890d4f76ac9e06ec117f9e09f3174da70a620a0c300953d8595c926e80947f", size = 13677374, upload-time = "2026-05-11T18:36:57.188Z" },
+ { url = "https://files.pythonhosted.org/packages/84/7f/8107ea87a44fd1f1b59882442f033c9c3488c127201b1d1d15f1cbd6022e/mypy-2.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:761be68e023ef5d94678772396a8af1220030f80837a3afd8d0aef3b419666f4", size = 14055743, upload-time = "2026-05-11T18:35:18.361Z" },
+ { url = "https://files.pythonhosted.org/packages/51/4d/b6d34db183133b83761b9199a82d31557cdbb70a380d8c3b3438e11882a3/mypy-2.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c90345fc182dc363b891350457ec69c35140858538f38b4540845afcc32b1aef", size = 15020937, upload-time = "2026-05-11T18:34:59.618Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/d7/f08360c691d758acb02f45022c34d98b92892f4ea756644e1000d4b9f3d8/mypy-2.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b84802e7b5a6daf1f5e15bc9fcd7ddae77be13981ffab037f1c67bb84d67d135", size = 15253371, upload-time = "2026-05-11T18:36:41.081Z" },
+ { url = "https://files.pythonhosted.org/packages/67/1b/09460a13719530a19bce27bd3bc8449e83569dd2ba7faf51c9c3c30c0b61/mypy-2.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:022c771234936ceac541ebaf836fe9e2abeb3f5e09aff21588fe543ff006fe21", size = 11326429, upload-time = "2026-05-11T18:34:13.526Z" },
+ { url = "https://files.pythonhosted.org/packages/40/62/75dbf0f82f7b6680340efc614af29dd0b3c17b8a4f1cd09b8bd2fd6bc814/mypy-2.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:498207db725cec88829a6a5c2fc771205fd043719ef98bc49aba8fb9fc4e6d57", size = 10218799, upload-time = "2026-05-11T18:32:23.491Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/66/caca04ed7d972fb6eb6dd1ccd6df1de5c38fae8c5b3dc1c4e8e0d85ee6b9/mypy-2.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7d5e5cad0efeba72b93cd17490cc0d69c5ac9ca132994fe3fb0314808aeeb83e", size = 15923458, upload-time = "2026-05-11T18:35:28.64Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/52/2d90cbe49d014b13ed7ff337930c30bad35893fe38a1e4641e756bb62191/mypy-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ff715050c127d724fd260a2e666e7747fdd83511c0c47d449d98238970aef780", size = 14757697, upload-time = "2026-05-11T18:36:14.208Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/37/d98f4a14e081b238992d0ed96b6d39c7cc0148c9699eb71eaa68629665ea/mypy-2.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:82208da9e09414d520e912d3e462d454854bed0810b71540bb016dcbca7308fd", size = 15405638, upload-time = "2026-05-11T18:33:48.249Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/c2/15c46613b24a84fad2aea1248bf9619b99c2767ae9071fe224c179a0b7d4/mypy-2.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e79ebc1b904b84f0310dff7469655a9c36c7a68bddb37bdd42b67a332df61d08", size = 16215852, upload-time = "2026-05-11T18:32:50.296Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/90/9c16a57f482c76d25f6379762b56bbf65c711d8158cf271fb2802cfb0640/mypy-2.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e583edc957cfb0deb142079162ae826f58449b116c1d442f2d91c69d9fced081", size = 16452695, upload-time = "2026-05-11T18:33:38.182Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/4c/215a4eeb63cacc5f17f516691ea7285d11e249802b942476bff15922a314/mypy-2.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b33b6cd332695bba180d55e717a79d3038e479a2c49cc5eb3d53603409b9a5d7", size = 12866622, upload-time = "2026-05-11T18:34:39.945Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/50/1043e1db5f455ffe4c9ab22747cd8ca2bc492b1e4f4e21b130a44ee2b217/mypy-2.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:4f910fe825376a7b66ef7ca8c98e5a149e8cd64c19ae71d84047a74ee060d4e6", size = 10610798, upload-time = "2026-05-11T18:36:31.444Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/2a/13ca1f292f6db1b98ff495ef3467736b331621c5917cad984b7043e7348d/mypy-2.1.0-py3-none-any.whl", hash = "sha256:a663814603a5c563fb87a4f96fb473eeb30d1f5a4885afcf44f9db000a366289", size = 2693302, upload-time = "2026-05-11T18:31:29.246Z" },
+]
+
+[[package]]
+name = "mypy-extensions"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
+]
+
+[[package]]
+name = "nodeenv"
+version = "1.10.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" }
+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 = "numpy"
+version = "2.4.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/95/2a/3d7b5ac8aac24feaf9ad7ed58f45b0bbc06d37e4338ae84c9f2298b570f9/numpy-2.4.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:001fbb8e08d942dd57599e781f2472269ee7f2755fae407b4f67b2f0b17da3f1", size = 16689119, upload-time = "2026-05-18T23:33:54.065Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/12/92c4c131527599e8288d6918e888d88726f84d805d784b771f32408aeaef/numpy-2.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ebfb099f8dcf083deef3ac1ca4c1503f387cf76296fcb3816b66f5ecb5f54fdb", size = 14699246, upload-time = "2026-05-18T23:33:57.621Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/fe/c0a6b7b2ca128a8fb228575147073b660656734b8ebe4d76c8fd748dcc79/numpy-2.4.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3213d622a0283a39a93d188f3cf72b26862df52fbb4ca3697f51705016523d41", size = 5204410, upload-time = "2026-05-18T23:34:00.302Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/d4/9770d14ba719432bb90a421bfd443872ed0f70f7264b64bec12ea363d5fd/numpy-2.4.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:357cc07a6d7b0b182ff02249616a03742827ebb1277546b5c7cd7f7620a45698", size = 6551240, upload-time = "2026-05-18T23:34:02.852Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/c6/50a46a6205feba2343f1d6d17438107c5dc491ed1c736e6ea68689fd906b/numpy-2.4.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f9fb9157b4ce2971008323afe46053787b526ef624fea915b261468a8421a0f", size = 15671012, upload-time = "2026-05-18T23:34:05.485Z" },
+ { url = "https://files.pythonhosted.org/packages/99/60/14115e6364fa676c5397c2ad3004e527e9aa487abf5d0706ec81bbd08529/numpy-2.4.6-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90f9849678c75fe7afa2d348ac842c168b0a4d3d61919687216dfc547976d853", size = 16645538, upload-time = "2026-05-18T23:34:09.265Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/c5/693cbe59e57db94d2231fa519ca3978dc9e19da5a8f088588f5c6e947ff2/numpy-2.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1a2af6c6ef86344a6b0db6b97834208bf598db514f2b155042439b62605601a", size = 17020706, upload-time = "2026-05-18T23:34:13.053Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/fc/85b7c4eff9b4966ade25c2273cf7e7012e92366c032058653934b37de044/numpy-2.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5805d5a22fd19c8ccff10a9561f9df94436b0545619ea579db2d3c35294bce2", size = 18368541, upload-time = "2026-05-18T23:34:17.024Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/81/e1b27545deedce7f4a0b348618c6b62d74e36a4dc9ccd42f3eb2f85eee32/numpy-2.4.6-cp312-cp312-win32.whl", hash = "sha256:e3eeb0aabd6bd5ce64faae67e9935203a6991b4bc2a485a767fbafb2c5125f45", size = 5962825, upload-time = "2026-05-18T23:34:20.3Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/ca/feab00bd44aa5fe1ad2c18f08b4d3bb92e26484b0b1d1443897809ed528c/numpy-2.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:d8e8286dd7cea7895157318d1b91cdacac64c479f3cbc8dce548331728484751", size = 12321687, upload-time = "2026-05-18T23:34:23.095Z" },
+ { url = "https://files.pythonhosted.org/packages/63/cf/5a6d34850a39d1093558564f77ee8e8e0bee5061151b8f05a55711001ec7/numpy-2.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:4081eb135ac24158bd51cdfbef16f1c64df7063b1143f24731387137c092bec8", size = 10221482, upload-time = "2026-05-18T23:34:25.876Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/82/bdab26d7438c6791ca31b7c024ca37c1eab8b726ba236129005cd4a06e45/numpy-2.4.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:511dbaf848decaaaf4b4ca48032619fb3138710c4bf7da7617765edad1ef96b0", size = 16684648, upload-time = "2026-05-18T23:34:29.41Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/30/a80189bcc7f5e4258b3fbc3968d909d1756f54d023299ecc39ad6fdb9ef8/numpy-2.4.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bf162abab1c1a736333192707cef898e735a5ca00f38f27eeedf44b39d9e85eb", size = 14693902, upload-time = "2026-05-18T23:34:33.013Z" },
+ { url = "https://files.pythonhosted.org/packages/97/12/70b5d0d7c15e1ebb8a6a84a8caa1d19e181d84fb58bb6d70aca29099dec1/numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:043191bfa8eab18c776647b62723ac9dddece59743b13f49b2016094129c2b3f", size = 5198992, upload-time = "2026-05-18T23:34:36.132Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/8c/ebd2a8f8a83541f8d38cc5667e8c2b69cecfd30da6e45693e8158857d44b/numpy-2.4.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:6180d8b35af935aed8ece3a85e0a43f87393ae0ac87c8d2c8bd2c993f7270ef3", size = 6546944, upload-time = "2026-05-18T23:34:38.484Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/c5/7b863a97a91671a0338f4253bd3b5a3d3852f0692dae91711c9f4a10e787/numpy-2.4.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72fbe16c6fac95aedf5937fa873445cec2110be35d8a4e9433d7501fd98dae6b", size = 15669392, upload-time = "2026-05-18T23:34:41.257Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/9d/3584b9984ca4c047aea75214ce1a4c4c73d849bd71b604264b7f5653f8a8/numpy-2.4.6-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7830bab239b79cda9c08c2da014761cafb48da6150e1da17ac06283f43b6089", size = 16633220, upload-time = "2026-05-18T23:34:45.075Z" },
+ { url = "https://files.pythonhosted.org/packages/05/ae/7c67fba23bd98caec7c99261f3a16072ade14813486b0282cb29846de832/numpy-2.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ef4aea96ce4d3b074422cb4f2f64e216bf9e213004bb58ecfdf50ea02ea8eb9a", size = 17020800, upload-time = "2026-05-18T23:34:49.065Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/5d/3b6725cb31d983c5e66916f5d36f6d7e5521129e4c4404d64f918292a5b6/numpy-2.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfa20cc6ca228e6b155b11da03825975ce66aea520985dbbddf0f2a5a495c605", size = 18357600, upload-time = "2026-05-18T23:34:52.709Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/da/2ccc6c2fe8898dee01d90c75c5f5f914a23daf99e3e0f59516a08760c8b5/numpy-2.4.6-cp313-cp313-win32.whl", hash = "sha256:56b39e5e0622a09a25bf5baf62f4bcf0cb8a41ae6e2819cf49bbc5a74c083f91", size = 5961134, upload-time = "2026-05-18T23:34:55.618Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/cd/9cc4dc876fb065d5c220aae4d5e14826b2715331bb7618ce1fb07a679d99/numpy-2.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:c4fc99836233ea196540b17ab0983aff60ed07941751930f5f4d05bc3b3b7359", size = 12318598, upload-time = "2026-05-18T23:34:58.928Z" },
+ { url = "https://files.pythonhosted.org/packages/39/1e/c0bcba1f8694116485fe28fd1be698c278fcda4141c5b0e53a2aed8b12a8/numpy-2.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a7c711e21628b52034bb5ab8d1bce291f752fcc5e92accc615778acee1ff4778", size = 10222272, upload-time = "2026-05-18T23:35:02.167Z" },
+ { url = "https://files.pythonhosted.org/packages/63/6d/cc5619247c8f4204e507f5883528372e4ac4bb189e579fb859a12e480b1f/numpy-2.4.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:112b06a867b235ef466ed3508ddf0238050df9c727cafb5301ac385b899189a1", size = 14821197, upload-time = "2026-05-18T23:35:05.468Z" },
+ { url = "https://files.pythonhosted.org/packages/00/58/f1c39161c87d9e9bed660f1ed4bafc0e403d5ec9650b6dd77aead07d489b/numpy-2.4.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:eaf7fa2de5c0be8ae6ff8e9bea2ccd725e980541244521d8d4b5f3354a27babe", size = 5326287, upload-time = "2026-05-18T23:35:08.693Z" },
+ { url = "https://files.pythonhosted.org/packages/af/57/3917ab0fd97f271a8694513581b8a36c655f111c446852c302f04ccdb6fc/numpy-2.4.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7265a2f3d436e54ef9f2b52b5c937e6be778781bd97a590319d7348f1c1ca997", size = 6646763, upload-time = "2026-05-18T23:35:11.459Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/0f/037e64c494b67581ae18193d770adef354c41f3f2c8ebf865602d949bf8f/numpy-2.4.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f74a575920ab21fe304421a3fc28793d82e299cae9eccb37084e9fc7f3617c20", size = 15728070, upload-time = "2026-05-18T23:35:14.79Z" },
+ { url = "https://files.pythonhosted.org/packages/21/a6/5d2bae9c9542eb4df16dc9c46dc79c186e9bad53805dfa5399a6023c6db0/numpy-2.4.6-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ede83e07a75dd06bc501566c1eca2afc0d61677c1472ac9ad93fdee6e638a48d", size = 16681752, upload-time = "2026-05-18T23:35:18.836Z" },
+ { url = "https://files.pythonhosted.org/packages/92/14/23d1dfb410ae362cd59ce53e936b1513d545eb40db3949ced632e19a459e/numpy-2.4.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:68bb27509ac1b9a3443094260f6326150663b06abe40b73a2f81160623da5b67", size = 17086024, upload-time = "2026-05-18T23:35:22.52Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/6e/23595a2c642cdf3bc567877064bdd7f91c8b0038a4453cf2daf7248eafe9/numpy-2.4.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a0df0043bdb289bde1f62da130d20df23d58b45429f752bc7a8fc5325a225ecd", size = 18403398, upload-time = "2026-05-18T23:35:26.398Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/90/0ac3bc947217e66dec77e7cbc6a1979d1af70b6461b82f620d3bccd5e4c8/numpy-2.4.6-cp313-cp313t-win32.whl", hash = "sha256:29a287e0cf63ff528da061de6b9f64a4618da591ca1046aafc54062e40ca7eab", size = 6084971, upload-time = "2026-05-18T23:35:29.387Z" },
+ { url = "https://files.pythonhosted.org/packages/77/71/5673e351671a1d2bd6063b91b44f70c0affea7d1516fa7a6572941ba4aa1/numpy-2.4.6-cp313-cp313t-win_amd64.whl", hash = "sha256:25c692919ac5a01f170a3bfcd62d745b24fd095c353d50812637d6fcab442e75", size = 12458532, upload-time = "2026-05-18T23:35:32.175Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/88/19d3503c5046e688f049274b27a3ef3d771152fa80d3ba3d01a3dff61abe/numpy-2.4.6-cp313-cp313t-win_arm64.whl", hash = "sha256:1e978ec1e8bd0e0e4de6bb75de9d30cbb74db6b6a2bb727618613703ca0167dd", size = 10291881, upload-time = "2026-05-18T23:35:35.465Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/91/3ab2044d05fd16d343c5ac2e69b127f1b2854040dd20b193257c78028bd3/numpy-2.4.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06ca2f61ec4385a07a6977c55ba998a4466c123642b4a32694d3128fce18c079", size = 16683458, upload-time = "2026-05-18T23:35:38.353Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/62/764ce66fa4147ae6d73071a3abf804ffe606f174618697c571acdf26a7c9/numpy-2.4.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:38efbc8de75c7a0fc1ac190162d892787f3f47b57cc291231aafee36b80982b7", size = 14704559, upload-time = "2026-05-18T23:35:42.14Z" },
+ { url = "https://files.pythonhosted.org/packages/60/61/23f27c172f022e04025b7dc2367f4d63c1a398120607ec896228649a6f48/numpy-2.4.6-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:d581b735e177fdcdce6fed8e7e8880a3fb6ee4e3653a3ac6af01c6f4c03effc5", size = 5209716, upload-time = "2026-05-18T23:35:45.377Z" },
+ { url = "https://files.pythonhosted.org/packages/03/71/21cf70dc6ea3e3acb95fc53a265b2fc248b981f0194ceb5b475271b8809d/numpy-2.4.6-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:0a041d3d761dc3c35cc56ce0351506a02bcbc25f7b169f652435141a17db9096", size = 6543947, upload-time = "2026-05-18T23:35:47.926Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/91/64288395ee1799bd2e0b04a305dce9666da90c961e1f3fe982a05ee1c036/numpy-2.4.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40fdc1ae7125e518ea98e53e69a4ebc27e1fd50510c47b7ea130cf21e5e1d42b", size = 15685197, upload-time = "2026-05-18T23:35:50.863Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/eb/ebffaa97dc55502df69584a8f0dcf07f69a3e0b3e2323670a2722db9aa39/numpy-2.4.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2c306dea656c12c68f51f4cea133cbe78ca7435eb28c735eac1d3ebe73be6e8", size = 16638245, upload-time = "2026-05-18T23:35:54.752Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/0b/54f9da33128d7e350fab89c7455902eeae70349ee52bddb448dc4a576f45/numpy-2.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:33111801a01c12a8a1e3721f0a9232f8cfc8ae2c6b7098167e6f623c6073f402", size = 17036587, upload-time = "2026-05-18T23:35:58.355Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/f0/fdebc1052db1cc37c64beb22072d67cd6d1c71adca1299f53dec2b5e20d3/numpy-2.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae506e6902902557576a26ff33eda8695e7ecb3cb36c3b573a0765dee114ebdb", size = 18363226, upload-time = "2026-05-18T23:36:02.845Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/b4/298628d98c72b57e57f7165ae6a481a1deaf6f3c28262a6e4c739c275930/numpy-2.4.6-cp314-cp314-win32.whl", hash = "sha256:aaf159caa35993cb1f56fb9b8e4610d35758e7ca005412eb1daa856a78c9c4b1", size = 6010196, upload-time = "2026-05-18T23:36:05.92Z" },
+ { url = "https://files.pythonhosted.org/packages/df/ac/46de6dda46478f7942f839e094970be2d4a861e005c4b3bf07c92e291a09/numpy-2.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:b507f5c4c1d508876d1819b6bf9a49d365b96320b5d4993426b33a23ca4b8261", size = 12450334, upload-time = "2026-05-18T23:36:09.107Z" },
+ { url = "https://files.pythonhosted.org/packages/78/92/b8b798ac784102c0da830d2257d59358e3d3d90d1e2b3f2575dad976c5cf/numpy-2.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:6f41ae150c4e32db4f3310cdaf64b1593a03dbabe29eec77fc9b50fe64061df6", size = 10495678, upload-time = "2026-05-18T23:36:12.766Z" },
+ { url = "https://files.pythonhosted.org/packages/30/34/ec28d1aa8115971537c01469ab2011ee96827930f0a124de1000cc2a7ed7/numpy-2.4.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ece3d2cfe132e7d51f44a832b303895e6f2d499c5e74dfbdb06ee246147a304a", size = 14823672, upload-time = "2026-05-18T23:36:16.473Z" },
+ { url = "https://files.pythonhosted.org/packages/16/bd/f6d1fede4e54e8042a7ff97bb495510f3c220f94bcd9e8b228e87c92cc0d/numpy-2.4.6-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:e3e5193ef5a3dc73bceee50f7fdc2c90dbb76c42df8d8fae3d1067a583df579e", size = 5328731, upload-time = "2026-05-18T23:36:19.767Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/f0/e105b9e2fd728a9910103884decd6951d9dd73896b914a98d9a231de02ee/numpy-2.4.6-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:17f9ade344e7d9b464a084d69bcf18fc691cb1db67c62ed80820bf4926d78f0e", size = 6649805, upload-time = "2026-05-18T23:36:22.266Z" },
+ { url = "https://files.pythonhosted.org/packages/82/dd/1206a7ca6ab15e3f02069707ca96222e202af681bb73756da7527f3cb837/numpy-2.4.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd5ffd25db4e7ba6a375693b3fc0fc1791ec636c17db3720da19bde7180ec43", size = 15730496, upload-time = "2026-05-18T23:36:25.713Z" },
+ { url = "https://files.pythonhosted.org/packages/51/e7/38d3ea825dcab85a591734decb2f6c67caa7c8367d374df1a1c3842f9b07/numpy-2.4.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d92c3819208a60205a12a245c91ad70cb0a85336659b19b834205573ac8456e", size = 16679616, upload-time = "2026-05-18T23:36:29.652Z" },
+ { url = "https://files.pythonhosted.org/packages/93/b7/caabfdf53edf663e0b4eb74d7d405d83baef09eb5e83bcd32d601d72b93e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e85b752a1e912b70eaad4fafbd4d1238007ab221de2009b9a2f5ae7461239895", size = 17085145, upload-time = "2026-05-18T23:36:33.449Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/45/68d7c33a6bcf3e5aa3bdbd57a367e6f615286dfd6482f97e8ffeb734306e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:29cb7f67d10b479ff07c17d33e39f78c07f71c40ef30d63c153d340e96cd3fb4", size = 18403813, upload-time = "2026-05-18T23:36:37.369Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/50/0753655aa844c99cd9e018aacf76f130f1bd81d881bb74bc0aef5d73a8ba/numpy-2.4.6-cp314-cp314t-win32.whl", hash = "sha256:260a5d70215b61ab4fadf5c7baacd64821842975eea312125ed3c39a6391b063", size = 6156982, upload-time = "2026-05-18T23:36:40.817Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/d4/7c67becf668f973cb490cec3e98dfd799d866f9c989a54d355672cfa0db6/numpy-2.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:81a1cca95ed5bb92aa8b10dd2cdc9a0d3853a50fad926c28b5d7e8ea54389627", size = 12638908, upload-time = "2026-05-18T23:36:43.996Z" },
+ { url = "https://files.pythonhosted.org/packages/43/bb/e1c71a4295b1b1d1393d50dbb4f2a36283c6859d9d3892e84f00ec5a91d5/numpy-2.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:0c9136e14ed34a9e343a31c533d78a9813a69a3148332bce5e9821cb2f996e66", size = 10565867, upload-time = "2026-05-18T23:36:47.114Z" },
+]
+
+[[package]]
+name = "packaging"
+version = "26.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" },
+]
+
+[[package]]
+name = "pandas"
+version = "3.0.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy" },
+ { name = "python-dateutil" },
+ { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f8/87/4341c6252d1c47b08768c3d25ac487362bf403f0313ddae4a2a26c9b1b4c/pandas-3.0.3.tar.gz", hash = "sha256:696a4a00a2a2a35d4e5deb3fc946641b96c944f02230e4f76137fe35d806c4fc", size = 4651414, upload-time = "2026-05-11T18:54:29.21Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/24/f1/392f8c5bfc16f66a0d2d41561c01627c228fe7ed2a0d056ef11315042570/pandas-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fed2ff7fd9779120e388e285fc029bd5cf9490cdd2e4166a9ee22c0e49a9ab09", size = 10357846, upload-time = "2026-05-11T18:52:36.143Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/3d/b16412745651e855f357e5e66930248688378853a6e2698a214e331fba1f/pandas-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b168fc218fd80a6cbdbdbc1a97ddc7889ed057d7eb45f50d866ceab5f39904c4", size = 9899550, upload-time = "2026-05-11T18:52:38.976Z" },
+ { url = "https://files.pythonhosted.org/packages/31/a8/fa2535168fffcedf67f4f6de28d2dd903a747ca7c8ea6989451aaeb3a92f/pandas-3.0.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0383c72c75cdcca61a9e116e611143902dbfd08bff356829c2f6d1cf40a9ca8c", size = 10412965, upload-time = "2026-05-11T18:52:41.915Z" },
+ { url = "https://files.pythonhosted.org/packages/65/b6/09b01cdbc15224e2850365192d17b7bdebb8bdbd8780ed221fcdf0d9a515/pandas-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6dc0b3fd2169c9157deed50b4d519553a3655c8c6a96027136d654592be973a9", size = 10894600, upload-time = "2026-05-11T18:52:45.02Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/a4/2eb28f2fccb4ced4a2c79ab2a5dee9ade1ebf44922ebad6fea158c9f95d4/pandas-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7e65d5407dc0b394f509699650e4a2ec01c0514f21850f453fa60f3be79a5dbf", size = 11422824, upload-time = "2026-05-11T18:52:48.058Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/45/830bb57f533a4604b355e07edcb8ea18cf88b5f94e5fca92f27052d7c597/pandas-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8894dc474d648fe7b6ff0ca9b0bd73950d19952bc1a6534540762c5d79d305c", size = 11950889, upload-time = "2026-05-11T18:52:50.905Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/c5/fc1b368f303087d20e8c9bf3d6ceb186263cfac0ade735cd938538bea839/pandas-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:c7be265b62cef88e253a941e4698604973736dcfe242fdb5198f0f7bc473cdcc", size = 9755463, upload-time = "2026-05-11T18:52:53.386Z" },
+ { url = "https://files.pythonhosted.org/packages/86/bd/fda8f9705b1b09c6ebe14bfc0fa0e4ec8584d54ea673628f157ff55131af/pandas-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:557409bc4178e70ee8d9ddb494798e51ebf6ea59330f6be22c51bab2a7db6c49", size = 9066158, upload-time = "2026-05-11T18:52:56.038Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/90/62d8302883c44308c477e222c3daf7c813a34c8e96985882fbd53d964352/pandas-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:67b3b64c11910cfa29f4e94a14d3bff9ee693b6fc76055e7cad549cee0aec5fa", size = 10331071, upload-time = "2026-05-11T18:52:58.838Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/ae/6a6493c783a101f165e4356953ba3c74d6f77f0042fa7d753da9dfbb640c/pandas-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:39436b377d56d2a2e52d0395bdbee171f01068e99af5250509aceeb929f765c7", size = 9875690, upload-time = "2026-05-11T18:53:01.431Z" },
+ { url = "https://files.pythonhosted.org/packages/62/7c/5df8e9f56c69a2769fbe9382a5ef8f2658c007e376434e1e2cbb57ad895f/pandas-3.0.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4be06d68f9ddcfc645b87534911da79a8fbffc7573c80e0edcf42a5020624d8", size = 10381634, upload-time = "2026-05-11T18:53:04.393Z" },
+ { url = "https://files.pythonhosted.org/packages/99/68/1237369725aa617bb358263d535803e3053fdbc593513ec5ed9c9896b5b6/pandas-3.0.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a4eeb6830daf35a71cc09649bd823e2b542dac246cdee9614c6e4bd65028cd6a", size = 10891243, upload-time = "2026-05-11T18:53:07.643Z" },
+ { url = "https://files.pythonhosted.org/packages/25/93/77d108e8af7222b4a503ebde0e30215b1c2e4f8e53a526431890f22d5586/pandas-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1928e07221f82db493cd4af1e23c1bfca524a19a4699887975bff68f49a72bfb", size = 11388659, upload-time = "2026-05-11T18:53:10.634Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/bd/eff5b4399f332ac386c853f6cd2bd3fa2ca0061b9f36ecd9c4d7c4265649/pandas-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51b1fe551acb77dac643c6fda86084d8d446c10fe64b06a9cc29c4cc8540e7f2", size = 11942880, upload-time = "2026-05-11T18:53:13.536Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/20/559ace4200982c3887d0b86bfd0d856a2143ef8ddab63cc07934951a964c/pandas-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:a82d532a3351d435432cd913edbccaf8b8e01d4dd0e5ced5a8d2e8ecd94c7e44", size = 9757091, upload-time = "2026-05-11T18:53:16.306Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/66/69055a09fe200f29f922a3eeec4804611900b95f52d932ece3393c3c0c19/pandas-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:275c14e0fce14a2ec20eee474aecd305478ea3c1e6f6a9d8fe219a165542717e", size = 9057282, upload-time = "2026-05-11T18:53:18.768Z" },
+ { url = "https://files.pythonhosted.org/packages/57/0e/efe801b0e6811e8e650cd21b7f2608e30f08a7067e2bf6e8752b0d56ee3c/pandas-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:46997386d528eb40376ecd6b033cf4a8a1e5282580f68f43de875b78cba2199d", size = 10767016, upload-time = "2026-05-11T18:53:21.227Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/dc/eb55135a1d5f0f0519f28da1f609a206d2cad1f9c35c32d51e38dd7261ae/pandas-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:261e308dfb22448384b7580cf719d2f998fe2966c92893c3e77d14008af1f066", size = 10420210, upload-time = "2026-05-11T18:53:23.982Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/3e/b1d5d955ce33ffecb407465a60bc32769d74fcf68224b7ae67ae11d4dea4/pandas-3.0.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dd1a5d1def6a46002e964510bdc67c368aa0951df5d1d9f8365336f5a1f490cd", size = 10336126, upload-time = "2026-05-11T18:53:26.731Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/76/a01261711ab60a22d71b862f0de20e4c504bf80457270ad8cb42110f6abc/pandas-3.0.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d72828c20c6d6e83e1e22a6a3b47b326b71664112fa9705dcbccfd7a39b62085", size = 10728051, upload-time = "2026-05-11T18:53:29.125Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/21/ea191195e587b18cf682e97f433f81b2d0fbe341380e80a3e0d6e4403c8e/pandas-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d26cbe1fcfc12e8fd900e2454163e466b2d3af84f7c75481df7683ffc073d870", size = 11350796, upload-time = "2026-05-11T18:53:32.056Z" },
+ { url = "https://files.pythonhosted.org/packages/64/69/f0eaaf54939f0e8c6768fd06be9af2cef9b36048b96dfb9e1b2c685a807e/pandas-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3e91cec1879ada0624fc3dc9953c5cbd60208e59c0db28f540c5d6d47502422f", size = 11799741, upload-time = "2026-05-11T18:53:34.985Z" },
+ { url = "https://files.pythonhosted.org/packages/45/a4/865e0e510cae5fc2194de4db28be638952de942571ba9125934fd9c01d47/pandas-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:08d789b41f87e0905880e293cedf6197ce71fe67cc081358b1e148a491b9bd13", size = 10499958, upload-time = "2026-05-11T18:53:37.857Z" },
+ { url = "https://files.pythonhosted.org/packages/86/54/effdcc3c0ff7a08037889200e148ebe94c16c4f653be078c7b3675955df1/pandas-3.0.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3650109c0f22879df8bd6179ab9ee3d7f1d1d4e7e0094a3f0032d9f51e2e64ac", size = 10336065, upload-time = "2026-05-11T18:53:41.099Z" },
+ { url = "https://files.pythonhosted.org/packages/68/10/bf2d6738d72748b961a3751ab89522d58c54efc36a8e1a12161216cd45cf/pandas-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:bab900348131a7db1f69a7309ef141fd5680f1487094193bcbbb61791573bf8f", size = 9926101, upload-time = "2026-05-11T18:53:43.515Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/e9/e35cf11c8a136e757b956f5f0efdcaa50aecde85ea055f1898dfc68262f3/pandas-3.0.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba7e08b9ac1d54569cd1e256e3668975ed624d6826f7b68df0342b012007bddb", size = 10457553, upload-time = "2026-05-11T18:53:46.394Z" },
+ { url = "https://files.pythonhosted.org/packages/58/3b/1cdec6772bdbaf7b25dab360c59f03cadf05492dd724c6540af905389b07/pandas-3.0.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d71c63ae4ebdbf70209742096f1fc46a83a0613c99d4b23766cced9ff8cd62a", size = 10914065, upload-time = "2026-05-11T18:53:49.134Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/c2/1ef644445fcd72e3627bceec77e3560636f87ddce4ed841afe76b83b5bf9/pandas-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e3a2ec42c98ffa2565a67e08e218d06d72576d758d90facb7c00805194d8f360", size = 11459188, upload-time = "2026-05-11T18:53:52.527Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/49/4d8d4f42cbc9c4adc7a1870f269c02cbd6cd40d059622c06fb298addcbad/pandas-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:335f62418ed562cfc3c49e9e196375c28b729dcef8543abf4f9438e381bf3c76", size = 11982966, upload-time = "2026-05-11T18:53:55.043Z" },
+ { url = "https://files.pythonhosted.org/packages/38/55/792619469bab9882d8bbd5865d45a72f6478762d04a9af4bf0d08c503e95/pandas-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:3c20a521bbb85902f79f7270c80a59e1b5452d96d170c034f207181870f97ac5", size = 9876755, upload-time = "2026-05-11T18:53:58.067Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/af/33c469653b0ba03b50c3a98192d4c07f0c75c66b263ceb097fce0ee97d31/pandas-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:a2d2dff8a04f3917b55ab3910c32990f8ddf7eceba114947838cefa976a68977", size = 9198658, upload-time = "2026-05-11T18:54:00.733Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/fa/b8c257bd76b8bd060c3a9151c1fca05e9b9c5e3af5d0f549c0356f6d143d/pandas-3.0.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:0d589105b3c14645af1738ff279b2995102d8f7a03b0a66dc8d95550eb513e04", size = 10787242, upload-time = "2026-05-11T18:54:03.564Z" },
+ { url = "https://files.pythonhosted.org/packages/54/eb/f19206ffb0bf1919002969aa448b4702c6594845156a6f8050674855aac3/pandas-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:13fc1e853d9e04743d11ba75a985ccbc2a317fe07d8af61e445a6fd24dacd6a6", size = 10436369, upload-time = "2026-05-11T18:54:06.311Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/24/c7c39fb4fe22b71a0c2d78bf0c585c600092d85f94f086d2b3b2f6ca27e2/pandas-3.0.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:819959dab7bbd0049c15623fbac4e29a191b9528160a61fb1032242d8ced2d9c", size = 10358306, upload-time = "2026-05-11T18:54:09.085Z" },
+ { url = "https://files.pythonhosted.org/packages/16/ec/dd2a9eb7fa1204df88c0864164e35b228ac581062ac612ba0a67fd812e4c/pandas-3.0.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:60ae316d3fd75d1858d450d0db0103ea2be3e7d4a95ec2f064f7e2ae63f7b028", size = 10758394, upload-time = "2026-05-11T18:54:11.956Z" },
+ { url = "https://files.pythonhosted.org/packages/95/6e/00c61ea8e85b4f6d8d35e11852a1a4998fc7fafc91c6a602d1cc9c972d64/pandas-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd3a518890b400d32f9023722dc9a9a5c969f00b415419a3c06c043f09bb5d7d", size = 11375717, upload-time = "2026-05-11T18:54:14.539Z" },
+ { url = "https://files.pythonhosted.org/packages/31/89/8fc1c268969fac43688d65fd92e67df24bd128d53cb4d2eee534cd307399/pandas-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c39be2d709d01fa972a0cabc522389fceca4f3969332ba25a7d6c5802cf976a", size = 11828897, upload-time = "2026-05-11T18:54:17.146Z" },
+ { url = "https://files.pythonhosted.org/packages/56/3b/e7d20dea247a3e6dc0bd8a6953854afbedc03951def4e7371e05e7263e25/pandas-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4db8c527972a821cf5286b40ccc57642a39bc62e62022b42f99f8a67fca8c3a1", size = 10900855, upload-time = "2026-05-11T18:54:19.72Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/54/68a0978d1ef8502b8492099beaa6e7a0c1b32e3b5d4f677f5810cb08711c/pandas-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b2c95f8bfc1ee412bf482605d7bfd30c12d1d26bd59fdd91efeef1d4718decb1", size = 9466464, upload-time = "2026-05-11T18:54:22.754Z" },
+]
+
+[[package]]
+name = "parso"
+version = "0.8.7"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/30/4b/90c937815137d43ce71ba043cd3566221e9df6b9c805f24b5d138c9d40a7/parso-0.8.7.tar.gz", hash = "sha256:eaaac4c9fdd5e9e8852dc778d2d7405897ec510f2a298071453e5e3a07914bb1", size = 401824, upload-time = "2026-05-01T23:13:02.138Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/99/5d/8268b644392ee874ee82a635cd0df1773de230bde356c38de28e298392cc/parso-0.8.7-py2.py3-none-any.whl", hash = "sha256:a8926eb2a1b915486941fdbd31e86a4baf88fe8c210f25f2f35ecec5b574ca1c", size = 107025, upload-time = "2026-05-01T23:12:58.867Z" },
+]
+
+[[package]]
+name = "pathspec"
+version = "1.1.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" },
+]
+
+[[package]]
+name = "pexpect"
+version = "4.9.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "ptyprocess" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" },
+]
+
+[[package]]
+name = "pillow"
+version = "12.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/58/be/7482c8a5ebebbc6470b3eb791812fff7d5e0216c2be3827b30b8bb6603ed/pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5", size = 5308279, upload-time = "2026-04-01T14:43:13.246Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421", size = 4695490, upload-time = "2026-04-01T14:43:15.584Z" },
+ { url = "https://files.pythonhosted.org/packages/de/af/4e8e6869cbed569d43c416fad3dc4ecb944cb5d9492defaed89ddd6fe871/pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987", size = 6284462, upload-time = "2026-04-01T14:43:18.268Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/9e/c05e19657fd57841e476be1ab46c4d501bffbadbafdc31a6d665f8b737b6/pillow-12.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76", size = 8094744, upload-time = "2026-04-01T14:43:20.716Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/54/1789c455ed10176066b6e7e6da1b01e50e36f94ba584dc68d9eebfe9156d/pillow-12.2.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005", size = 6398371, upload-time = "2026-04-01T14:43:23.443Z" },
+ { url = "https://files.pythonhosted.org/packages/43/e3/fdc657359e919462369869f1c9f0e973f353f9a9ee295a39b1fea8ee1a77/pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780", size = 7087215, upload-time = "2026-04-01T14:43:26.758Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/f8/2f6825e441d5b1959d2ca5adec984210f1ec086435b0ed5f52c19b3b8a6e/pillow-12.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5", size = 6509783, upload-time = "2026-04-01T14:43:29.56Z" },
+ { url = "https://files.pythonhosted.org/packages/67/f9/029a27095ad20f854f9dba026b3ea6428548316e057e6fc3545409e86651/pillow-12.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5", size = 7212112, upload-time = "2026-04-01T14:43:32.091Z" },
+ { url = "https://files.pythonhosted.org/packages/be/42/025cfe05d1be22dbfdb4f264fe9de1ccda83f66e4fc3aac94748e784af04/pillow-12.2.0-cp312-cp312-win32.whl", hash = "sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940", size = 6378489, upload-time = "2026-04-01T14:43:34.601Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/7b/25a221d2c761c6a8ae21bfa3874988ff2583e19cf8a27bf2fee358df7942/pillow-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5", size = 7084129, upload-time = "2026-04-01T14:43:37.213Z" },
+ { url = "https://files.pythonhosted.org/packages/10/e1/542a474affab20fd4a0f1836cb234e8493519da6b76899e30bcc5d990b8b/pillow-12.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414", size = 2463612, upload-time = "2026-04-01T14:43:39.421Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/01/53d10cf0dbad820a8db274d259a37ba50b88b24768ddccec07355382d5ad/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8297651f5b5679c19968abefd6bb84d95fe30ef712eb1b2d9b2d31ca61267f4c", size = 4100837, upload-time = "2026-04-01T14:43:41.506Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/98/f3a6657ecb698c937f6c76ee564882945f29b79bad496abcba0e84659ec5/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:50d8520da2a6ce0af445fa6d648c4273c3eeefbc32d7ce049f22e8b5c3daecc2", size = 4176528, upload-time = "2026-04-01T14:43:43.773Z" },
+ { url = "https://files.pythonhosted.org/packages/69/bc/8986948f05e3ea490b8442ea1c1d4d990b24a7e43d8a51b2c7d8b1dced36/pillow-12.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:766cef22385fa1091258ad7e6216792b156dc16d8d3fa607e7545b2b72061f1c", size = 3640401, upload-time = "2026-04-01T14:43:45.87Z" },
+ { url = "https://files.pythonhosted.org/packages/34/46/6c717baadcd62bc8ed51d238d521ab651eaa74838291bda1f86fe1f864c9/pillow-12.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d2fd0fa6b5d9d1de415060363433f28da8b1526c1c129020435e186794b3795", size = 5308094, upload-time = "2026-04-01T14:43:48.438Z" },
+ { url = "https://files.pythonhosted.org/packages/71/43/905a14a8b17fdb1ccb58d282454490662d2cb89a6bfec26af6d3520da5ec/pillow-12.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b25336f502b6ed02e889f4ece894a72612fe885889a6e8c4c80239ff6e5f5f", size = 4695402, upload-time = "2026-04-01T14:43:51.292Z" },
+ { url = "https://files.pythonhosted.org/packages/73/dd/42107efcb777b16fa0393317eac58f5b5cf30e8392e266e76e51cff28c3d/pillow-12.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f1c943e96e85df3d3478f7b691f229887e143f81fedab9b20205349ab04d73ed", size = 6280005, upload-time = "2026-04-01T14:43:54.242Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/68/b93e09e5e8549019e61acf49f65b1a8530765a7f812c77a7461bca7e4494/pillow-12.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03f6fab9219220f041c74aeaa2939ff0062bd5c364ba9ce037197f4c6d498cd9", size = 8090669, upload-time = "2026-04-01T14:43:57.335Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/6e/3ccb54ce8ec4ddd1accd2d89004308b7b0b21c4ac3d20fa70af4760a4330/pillow-12.2.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdfebd752ec52bf5bb4e35d9c64b40826bc5b40a13df7c3cda20a2c03a0f5ed", size = 6395194, upload-time = "2026-04-01T14:43:59.864Z" },
+ { url = "https://files.pythonhosted.org/packages/67/ee/21d4e8536afd1a328f01b359b4d3997b291ffd35a237c877b331c1c3b71c/pillow-12.2.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eedf4b74eda2b5a4b2b2fb4c006d6295df3bf29e459e198c90ea48e130dc75c3", size = 7082423, upload-time = "2026-04-01T14:44:02.74Z" },
+ { url = "https://files.pythonhosted.org/packages/78/5f/e9f86ab0146464e8c133fe85df987ed9e77e08b29d8d35f9f9f4d6f917ba/pillow-12.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:00a2865911330191c0b818c59103b58a5e697cae67042366970a6b6f1b20b7f9", size = 6505667, upload-time = "2026-04-01T14:44:05.381Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/1e/409007f56a2fdce61584fd3acbc2bbc259857d555196cedcadc68c015c82/pillow-12.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e1757442ed87f4912397c6d35a0db6a7b52592156014706f17658ff58bbf795", size = 7208580, upload-time = "2026-04-01T14:44:08.39Z" },
+ { url = "https://files.pythonhosted.org/packages/23/c4/7349421080b12fb35414607b8871e9534546c128a11965fd4a7002ccfbee/pillow-12.2.0-cp313-cp313-win32.whl", hash = "sha256:144748b3af2d1b358d41286056d0003f47cb339b8c43a9ea42f5fea4d8c66b6e", size = 6375896, upload-time = "2026-04-01T14:44:11.197Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/82/8a3739a5e470b3c6cbb1d21d315800d8e16bff503d1f16b03a4ec3212786/pillow-12.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:390ede346628ccc626e5730107cde16c42d3836b89662a115a921f28440e6a3b", size = 7081266, upload-time = "2026-04-01T14:44:13.947Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/25/f968f618a062574294592f668218f8af564830ccebdd1fa6200f598e65c5/pillow-12.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:8023abc91fba39036dbce14a7d6535632f99c0b857807cbbbf21ecc9f4717f06", size = 2463508, upload-time = "2026-04-01T14:44:16.312Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/a4/b342930964e3cb4dce5038ae34b0eab4653334995336cd486c5a8c25a00c/pillow-12.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:042db20a421b9bafecc4b84a8b6e444686bd9d836c7fd24542db3e7df7baad9b", size = 5309927, upload-time = "2026-04-01T14:44:18.89Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/de/23198e0a65a9cf06123f5435a5d95cea62a635697f8f03d134d3f3a96151/pillow-12.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd025009355c926a84a612fecf58bb315a3f6814b17ead51a8e48d3823d9087f", size = 4698624, upload-time = "2026-04-01T14:44:21.115Z" },
+ { url = "https://files.pythonhosted.org/packages/01/a6/1265e977f17d93ea37aa28aa81bad4fa597933879fac2520d24e021c8da3/pillow-12.2.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88ddbc66737e277852913bd1e07c150cc7bb124539f94c4e2df5344494e0a612", size = 6321252, upload-time = "2026-04-01T14:44:23.663Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/83/5982eb4a285967baa70340320be9f88e57665a387e3a53a7f0db8231a0cd/pillow-12.2.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d362d1878f00c142b7e1a16e6e5e780f02be8195123f164edf7eddd911eefe7c", size = 8126550, upload-time = "2026-04-01T14:44:26.772Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/48/6ffc514adce69f6050d0753b1a18fd920fce8cac87620d5a31231b04bfc5/pillow-12.2.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c727a6d53cb0018aadd8018c2b938376af27914a68a492f59dfcaca650d5eea", size = 6433114, upload-time = "2026-04-01T14:44:29.615Z" },
+ { url = "https://files.pythonhosted.org/packages/36/a3/f9a77144231fb8d40ee27107b4463e205fa4677e2ca2548e14da5cf18dce/pillow-12.2.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:efd8c21c98c5cc60653bcb311bef2ce0401642b7ce9d09e03a7da87c878289d4", size = 7115667, upload-time = "2026-04-01T14:44:32.773Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/fc/ac4ee3041e7d5a565e1c4fd72a113f03b6394cc72ab7089d27608f8aaccb/pillow-12.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f08483a632889536b8139663db60f6724bfcb443c96f1b18855860d7d5c0fd4", size = 6538966, upload-time = "2026-04-01T14:44:35.252Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/a8/27fb307055087f3668f6d0a8ccb636e7431d56ed0750e07a60547b1e083e/pillow-12.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dac8d77255a37e81a2efcbd1fc05f1c15ee82200e6c240d7e127e25e365c39ea", size = 7238241, upload-time = "2026-04-01T14:44:37.875Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/4b/926ab182c07fccae9fcb120043464e1ff1564775ec8864f21a0ebce6ac25/pillow-12.2.0-cp313-cp313t-win32.whl", hash = "sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24", size = 6379592, upload-time = "2026-04-01T14:44:40.336Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/c4/f9e476451a098181b30050cc4c9a3556b64c02cf6497ea421ac047e89e4b/pillow-12.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98", size = 7085542, upload-time = "2026-04-01T14:44:43.251Z" },
+ { url = "https://files.pythonhosted.org/packages/00/a4/285f12aeacbe2d6dc36c407dfbbe9e96d4a80b0fb710a337f6d2ad978c75/pillow-12.2.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453", size = 2465765, upload-time = "2026-04-01T14:44:45.996Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/98/4595daa2365416a86cb0d495248a393dfc84e96d62ad080c8546256cb9c0/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8", size = 4100848, upload-time = "2026-04-01T14:44:48.48Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/79/40184d464cf89f6663e18dfcf7ca21aae2491fff1a16127681bf1fa9b8cf/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b", size = 4176515, upload-time = "2026-04-01T14:44:51.353Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/63/703f86fd4c422a9cf722833670f4f71418fb116b2853ff7da722ea43f184/pillow-12.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295", size = 3640159, upload-time = "2026-04-01T14:44:53.588Z" },
+ { url = "https://files.pythonhosted.org/packages/71/e0/fb22f797187d0be2270f83500aab851536101b254bfa1eae10795709d283/pillow-12.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed", size = 5312185, upload-time = "2026-04-01T14:44:56.039Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/8c/1a9e46228571de18f8e28f16fabdfc20212a5d019f3e3303452b3f0a580d/pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae", size = 4695386, upload-time = "2026-04-01T14:44:58.663Z" },
+ { url = "https://files.pythonhosted.org/packages/70/62/98f6b7f0c88b9addd0e87c217ded307b36be024d4ff8869a812b241d1345/pillow-12.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601", size = 6280384, upload-time = "2026-04-01T14:45:01.5Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/03/688747d2e91cfbe0e64f316cd2e8005698f76ada3130d0194664174fa5de/pillow-12.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be", size = 8091599, upload-time = "2026-04-01T14:45:04.5Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/35/577e22b936fcdd66537329b33af0b4ccfefaeabd8aec04b266528cddb33c/pillow-12.2.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f", size = 6396021, upload-time = "2026-04-01T14:45:07.117Z" },
+ { url = "https://files.pythonhosted.org/packages/11/8d/d2532ad2a603ca2b93ad9f5135732124e57811d0168155852f37fbce2458/pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286", size = 7083360, upload-time = "2026-04-01T14:45:09.763Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/26/d325f9f56c7e039034897e7380e9cc202b1e368bfd04d4cbe6a441f02885/pillow-12.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50", size = 6507628, upload-time = "2026-04-01T14:45:12.378Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/f7/769d5632ffb0988f1c5e7660b3e731e30f7f8ec4318e94d0a5d674eb65a4/pillow-12.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104", size = 7209321, upload-time = "2026-04-01T14:45:15.122Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/7a/c253e3c645cd47f1aceea6a8bacdba9991bf45bb7dfe927f7c893e89c93c/pillow-12.2.0-cp314-cp314-win32.whl", hash = "sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7", size = 6479723, upload-time = "2026-04-01T14:45:17.797Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/8b/601e6566b957ca50e28725cb6c355c59c2c8609751efbecd980db44e0349/pillow-12.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150", size = 7217400, upload-time = "2026-04-01T14:45:20.529Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/94/220e46c73065c3e2951bb91c11a1fb636c8c9ad427ac3ce7d7f3359b9b2f/pillow-12.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1", size = 2554835, upload-time = "2026-04-01T14:45:23.162Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/ab/1b426a3974cb0e7da5c29ccff4807871d48110933a57207b5a676cccc155/pillow-12.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463", size = 5314225, upload-time = "2026-04-01T14:45:25.637Z" },
+ { url = "https://files.pythonhosted.org/packages/19/1e/dce46f371be2438eecfee2a1960ee2a243bbe5e961890146d2dee1ff0f12/pillow-12.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3", size = 4698541, upload-time = "2026-04-01T14:45:28.355Z" },
+ { url = "https://files.pythonhosted.org/packages/55/c3/7fbecf70adb3a0c33b77a300dc52e424dc22ad8cdc06557a2e49523b703d/pillow-12.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166", size = 6322251, upload-time = "2026-04-01T14:45:30.924Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/3c/7fbc17cfb7e4fe0ef1642e0abc17fc6c94c9f7a16be41498e12e2ba60408/pillow-12.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe", size = 8127807, upload-time = "2026-04-01T14:45:33.908Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/c3/a8ae14d6defd2e448493ff512fae903b1e9bd40b72efb6ec55ce0048c8ce/pillow-12.2.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd", size = 6433935, upload-time = "2026-04-01T14:45:36.623Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/32/2880fb3a074847ac159d8f902cb43278a61e85f681661e7419e6596803ed/pillow-12.2.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e", size = 7116720, upload-time = "2026-04-01T14:45:39.258Z" },
+ { url = "https://files.pythonhosted.org/packages/46/87/495cc9c30e0129501643f24d320076f4cc54f718341df18cc70ec94c44e1/pillow-12.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06", size = 6540498, upload-time = "2026-04-01T14:45:41.879Z" },
+ { url = "https://files.pythonhosted.org/packages/18/53/773f5edca692009d883a72211b60fdaf8871cbef075eaa9d577f0a2f989e/pillow-12.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43", size = 7239413, upload-time = "2026-04-01T14:45:44.705Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/e4/4b64a97d71b2a83158134abbb2f5bd3f8a2ea691361282f010998f339ec7/pillow-12.2.0-cp314-cp314t-win32.whl", hash = "sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354", size = 6482084, upload-time = "2026-04-01T14:45:47.568Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/13/306d275efd3a3453f72114b7431c877d10b1154014c1ebbedd067770d629/pillow-12.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1", size = 7225152, upload-time = "2026-04-01T14:45:50.032Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/6e/cf826fae916b8658848d7b9f38d88da6396895c676e8086fc0988073aaf8/pillow-12.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb", size = 2556579, upload-time = "2026-04-01T14:45:52.529Z" },
+]
+
+[[package]]
+name = "platformdirs"
+version = "4.9.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", size = 29400, upload-time = "2026-04-09T00:04:10.812Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", size = 21348, upload-time = "2026-04-09T00:04:09.463Z" },
+]
+
+[[package]]
+name = "playwright"
+version = "1.60.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "greenlet" },
+ { name = "pyee" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/21/f0/832bd9677194908da118064eef20082f2791e3d18215cc6d9391ee2c5a67/playwright-1.60.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:6a8cd0fec171fb3089e95e898c8bc8a6f35dea0b78b399e12fcc19427e91b1d7", size = 43474635, upload-time = "2026-05-18T12:00:31.969Z" },
+ { url = "https://files.pythonhosted.org/packages/59/7b/e1d32ae8a3ed937ec2be3721c5f728b13d731a0b7c6442e0b3bec5094ac0/playwright-1.60.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:39b5420ba6145045b69ced4c5c47d4d9fe5bddfc8ff816c518913afcb25ec7a5", size = 42261327, upload-time = "2026-05-18T12:00:35.638Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/bc/23de499ded6411c188a20c5a0dea6f0cd4ed5d2b3cc6042a5dbd3ed609aa/playwright-1.60.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:2581d0e6a3392c71f91b27460c7fd093356818dc430f48153896c8aeeaef7705", size = 43474636, upload-time = "2026-05-18T12:00:39.294Z" },
+ { url = "https://files.pythonhosted.org/packages/22/7b/1d679f4fced4ea94efadd17103856d8c565384f68382a1681264e46f5925/playwright-1.60.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:1c2bfae7884fb3fb05b853290eab8f343d524e5016f2f1def702acbbdf14c93e", size = 47467220, upload-time = "2026-05-18T12:00:43.179Z" },
+ { url = "https://files.pythonhosted.org/packages/84/c2/1528d267d4442bd2c6b8eaeab819dd52c2030bf80e89293f0ba1f687473b/playwright-1.60.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43e66564125ee31b07a58cefb21e256d62d67d8d1713e6858df7a3019d8ed353", size = 47154856, upload-time = "2026-05-18T12:00:46.715Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/4e/b008b6440a7a1624378041da94829956d4b8f7ab9ef5aad22d0dc3f2e26d/playwright-1.60.0-py3-none-win32.whl", hash = "sha256:ec94e416ea320711e0ad4bf185dcbf41833672961e90773e1885255d7db7b7e7", size = 37902157, upload-time = "2026-05-18T12:00:50.374Z" },
+ { url = "https://files.pythonhosted.org/packages/55/f0/0541524133104f9cc20bf900870ff4a736b76a23483f3a55295ddfa58409/playwright-1.60.0-py3-none-win_amd64.whl", hash = "sha256:9566821ce6030a1f9e7146a24e19355ab0d98805fd0f9be50bb3d8fef1750c02", size = 37902159, upload-time = "2026-05-18T12:00:53.728Z" },
+ { url = "https://files.pythonhosted.org/packages/80/c8/210f282d278e4709cdd71b12a31af45a30a22ab3207b387e29b37e478713/playwright-1.60.0-py3-none-win_arm64.whl", hash = "sha256:6e4f6700a4c2250efff8e690a81d66e3855754fb587b6b87cf5c784014f91537", size = 34037981, upload-time = "2026-05-18T12:00:57.584Z" },
+]
+
+[[package]]
+name = "pluggy"
+version = "1.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
+]
+
+[[package]]
+name = "pre-commit"
+version = "4.6.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cfgv" },
+ { name = "identify" },
+ { name = "nodeenv" },
+ { name = "pyyaml" },
+ { name = "virtualenv" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/8e/22/2de9408ac81acbb8a7d05d4cc064a152ccf33b3d480ebe0cd292153db239/pre_commit-4.6.0.tar.gz", hash = "sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9", size = 198525, upload-time = "2026-04-21T20:31:41.613Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/80/6e/4b28b62ecb6aae56769c34a8ff1d661473ec1e9519e2d5f8b2c150086b26/pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b", size = 226472, upload-time = "2026-04-21T20:31:40.092Z" },
+]
+
+[[package]]
+name = "prompt-toolkit"
+version = "3.0.52"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "wcwidth" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" },
+]
+
+[[package]]
+name = "psutil"
+version = "7.2.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/51/08/510cbdb69c25a96f4ae523f733cdc963ae654904e8db864c07585ef99875/psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b", size = 130595, upload-time = "2026-01-28T18:14:57.293Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/f5/97baea3fe7a5a9af7436301f85490905379b1c6f2dd51fe3ecf24b4c5fbf/psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea", size = 131082, upload-time = "2026-01-28T18:14:59.732Z" },
+ { url = "https://files.pythonhosted.org/packages/37/d6/246513fbf9fa174af531f28412297dd05241d97a75911ac8febefa1a53c6/psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63", size = 181476, upload-time = "2026-01-28T18:15:01.884Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/b5/9182c9af3836cca61696dabe4fd1304e17bc56cb62f17439e1154f225dd3/psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312", size = 184062, upload-time = "2026-01-28T18:15:04.436Z" },
+ { url = "https://files.pythonhosted.org/packages/16/ba/0756dca669f5a9300d0cbcbfae9a4c30e446dfc7440ffe43ded5724bfd93/psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b", size = 139893, upload-time = "2026-01-28T18:15:06.378Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/61/8fa0e26f33623b49949346de05ec1ddaad02ed8ba64af45f40a147dbfa97/psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9", size = 135589, upload-time = "2026-01-28T18:15:08.03Z" },
+ { url = "https://files.pythonhosted.org/packages/81/69/ef179ab5ca24f32acc1dac0c247fd6a13b501fd5534dbae0e05a1c48b66d/psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00", size = 130664, upload-time = "2026-01-28T18:15:09.469Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/64/665248b557a236d3fa9efc378d60d95ef56dd0a490c2cd37dafc7660d4a9/psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9", size = 131087, upload-time = "2026-01-28T18:15:11.724Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/2e/e6782744700d6759ebce3043dcfa661fb61e2fb752b91cdeae9af12c2178/psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a", size = 182383, upload-time = "2026-01-28T18:15:13.445Z" },
+ { url = "https://files.pythonhosted.org/packages/57/49/0a41cefd10cb7505cdc04dab3eacf24c0c2cb158a998b8c7b1d27ee2c1f5/psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf", size = 185210, upload-time = "2026-01-28T18:15:16.002Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/2c/ff9bfb544f283ba5f83ba725a3c5fec6d6b10b8f27ac1dc641c473dc390d/psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1", size = 141228, upload-time = "2026-01-28T18:15:18.385Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/fc/f8d9c31db14fcec13748d373e668bc3bed94d9077dbc17fb0eebc073233c/psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841", size = 136284, upload-time = "2026-01-28T18:15:19.912Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" },
+ { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" },
+ { url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" },
+ { url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" },
+]
+
+[[package]]
+name = "psycopg2"
+version = "2.9.9"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c9/5e/dc6acaf46d78979d6b03458b7a1618a68e152a6776fce95daac5e0f0301b/psycopg2-2.9.9.tar.gz", hash = "sha256:d1454bde93fb1e224166811694d600e746430c006fbb031ea06ecc2ea41bf156", size = 384926, upload-time = "2023-10-03T12:48:53.323Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/13/13/f74ffe6b6f58822e807c70391dc5679a53feb92ce119ccb8a6546c3fb893/psycopg2-2.9.9-cp312-cp312-win32.whl", hash = "sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024", size = 1024634, upload-time = "2023-10-28T09:37:19.078Z" },
+ { url = "https://files.pythonhosted.org/packages/58/4b/c4a26e191882b60150bfcb639e416524ae7f8249ab7ee854fb5247f16c40/psycopg2-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693", size = 1163789, upload-time = "2023-10-28T09:37:22.214Z" },
+]
+
+[[package]]
+name = "psycopg2-binary"
+version = "2.9.12"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/2a/60/a3624f79acea344c16fbef3a94d28b89a8042ddfb8f3e4ca83f538671409/psycopg2_binary-2.9.12.tar.gz", hash = "sha256:5ac9444edc768c02a6b6a591f070b8aae28ff3a99be57560ac996001580f294c", size = 379686, upload-time = "2026-04-21T09:40:34.304Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e2/9f/ef4ef3c8e15083df90ca35265cfd1a081a2f0cc07bb229c6314c6af817f4/psycopg2_binary-2.9.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5cdc05117180c5fa9c40eea8ea559ce64d73824c39d928b7da9fb5f6a9392433", size = 3712459, upload-time = "2026-04-20T23:34:30.549Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/01/3dd14e46ba48c1e1a6ec58ee599fa1b5efa00c246d5046cd903d0eeb1af1/psycopg2_binary-2.9.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d3227a3bc228c10d21011a99245edca923e4e8bf461857e869a507d9a41fe9f6", size = 3822936, upload-time = "2026-04-20T23:34:32.77Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/f7/0640e4901119d8a9f7a1784b927f494e2198e213ceb593753d1f2c8b1b30/psycopg2_binary-2.9.12-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:995ce929eede89db6254b50827e2b7fd61e50d11f0b116b29fffe4a2e53c4580", size = 4578676, upload-time = "2026-04-20T23:34:35.18Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/55/44df3965b5f297c50cc0b1b594a31c67d6127a9d133045b8a66611b14dfb/psycopg2_binary-2.9.12-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9fe06d93e72f1c048e731a2e3e7854a5bfaa58fc736068df90b352cefe66f03f", size = 4274917, upload-time = "2026-04-20T23:34:37.982Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/4b/74535248b1eac0c9336862e8617c765ac94dac76f9e25d7c4a79588c8907/psycopg2_binary-2.9.12-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40e7b28b63aaf737cb3a1edc3a9bbc9a9f4ad3dcb7152e8c1130e4050eddcb7d", size = 5894843, upload-time = "2026-04-20T23:34:40.856Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/ba/f1bf8d2ae71868ad800b661099086ee52bc0f8d9f05be1acd8ebb06757cc/psycopg2_binary-2.9.12-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:89d19a9f7899e8eb0656a2b3a08e0da04c720a06db6e0033eab5928aabe60fa9", size = 4110556, upload-time = "2026-04-20T23:34:44.016Z" },
+ { url = "https://files.pythonhosted.org/packages/45/46/c15706c338403b7c420bcc0c2905aad116cc064545686d8bf85f1999ea00/psycopg2_binary-2.9.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:612b965daee295ae2da8f8218ce1d274645dc76ef3f1abf6a0a94fd57eff876d", size = 3655714, upload-time = "2026-04-20T23:34:46.233Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/7c/a2d5dc09b64a4564db242a0fe418fde7d33f6f8259dd2c5b9d7def00fb5a/psycopg2_binary-2.9.12-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b9a339b79d37c1b45f3235265f07cdeb0cb5ad7acd2ac7720a5920989c17c24e", size = 3301154, upload-time = "2026-04-20T23:34:49.528Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/e8/cc8c9a4ce71461f9ec548d38cadc41dc184b34c73e6455450775a9334ccd/psycopg2_binary-2.9.12-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:3471336e1acfd9c7fe507b8bad5af9317b6a89294f9eb37bd9a030bb7bebcdc6", size = 3048882, upload-time = "2026-04-20T23:34:51.86Z" },
+ { url = "https://files.pythonhosted.org/packages/19/6a/31e2296bc0787c5ab75d3d118e40b239db8151b5192b90b77c72bc9256e9/psycopg2_binary-2.9.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7af18183109e23502c8b2ae7f6926c0882766f35b5175a4cd737ad825e4d7a1b", size = 3351298, upload-time = "2026-04-20T23:34:54.124Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/a8/75f4e3e11203b590150abed2cf7794b9c9c9f7eceddae955191138b44dde/psycopg2_binary-2.9.12-cp312-cp312-win_amd64.whl", hash = "sha256:398fcd4db988c7d7d3713e2b8e18939776fd3fb447052daae4f24fa39daede4c", size = 2757230, upload-time = "2026-04-20T23:34:56.242Z" },
+ { url = "https://files.pythonhosted.org/packages/91/bb/4608c96f970f6e0c56572e87027ef4404f709382a3503e9934526d7ba051/psycopg2_binary-2.9.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7c729a73c7b1b84de3582f73cdd27d905121dc2c531f3d9a3c32a3011033b965", size = 3712419, upload-time = "2026-04-20T23:34:58.754Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/af/48f76af9d50d61cf390f8cd657b503168b089e2e9298e48465d029fcc713/psycopg2_binary-2.9.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4413d0caef93c5cf50b96863df4c2efe8c269bf2267df353225595e7e15e8df7", size = 3822990, upload-time = "2026-04-20T23:35:00.821Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/df/aba0f99397cd811d32e06fc0cc781f1f3ce98bc0e729cb423925085d781a/psycopg2_binary-2.9.12-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:4dfcf8e45ebb0c663be34a3442f65e17311f3367089cd4e5e3a3e8e62c978777", size = 4578696, upload-time = "2026-04-20T23:35:03.409Z" },
+ { url = "https://files.pythonhosted.org/packages/95/9c/eaa74021ac4e4d5c2f83d82fc6615a63f4fe6c94dc4e94c3990427053f67/psycopg2_binary-2.9.12-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c41321a14dd74aceb6a9a643b9253a334521babfa763fa873e33d89cfa122fb5", size = 4274982, upload-time = "2026-04-20T23:35:05.583Z" },
+ { url = "https://files.pythonhosted.org/packages/35/ed/c25deff98bd26187ba48b3b250a3ffc3037c46c5b89362534a15d200e0db/psycopg2_binary-2.9.12-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83946ba43979ebfdc99a3cd0ee775c89f221df026984ba19d46133d8d75d3cd9", size = 5894867, upload-time = "2026-04-20T23:35:07.902Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/81/8d0e21ca77373c6c9589e5c4528f6e8f0c08c62cafc76fb0bddb7a2cee22/psycopg2_binary-2.9.12-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:411e85815652d13560fbe731878daa5d92378c4995a22302071890ec3397d019", size = 4110578, upload-time = "2026-04-20T23:35:10.149Z" },
+ { url = "https://files.pythonhosted.org/packages/00/fc/f481e2435bd8f742d0123309174aae4165160ad3ef17c1b99c3622c241d2/psycopg2_binary-2.9.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c8ad4c08e00f7679559eaed7aff1edfffc60c086b976f93972f686384a95e2c", size = 3655816, upload-time = "2026-04-20T23:35:12.56Z" },
+ { url = "https://files.pythonhosted.org/packages/53/79/b9f46466bdbe9f239c96cde8be33c1aace4842f06013b47b730dc9759187/psycopg2_binary-2.9.12-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:00814e40fa23c2b37ef0a1e3c749d89982c73a9cb5046137f0752a22d432e82f", size = 3301307, upload-time = "2026-04-20T23:35:15.029Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/19/7dc003b32fe35024df89b658104f7c8538a8b2dcbde7a4e746ce929742e7/psycopg2_binary-2.9.12-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:98062447aebc20ed20add1f547a364fd0ef8933640d5372ff1873f8deb9b61be", size = 3048968, upload-time = "2026-04-20T23:35:16.757Z" },
+ { url = "https://files.pythonhosted.org/packages/91/58/2dbd7db5c604d45f4950d988506aae672a14126ec22998ced5021cbb76bb/psycopg2_binary-2.9.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:66a7685d7e548f10fb4ce32fb01a7b7f4aa702134de92a292c7bd9e0d3dbd290", size = 3351369, upload-time = "2026-04-20T23:35:18.933Z" },
+ { url = "https://files.pythonhosted.org/packages/42/ee/dee8dcaad07f735824de3d6563bc67119fa6c28257b17977a8d624f02fab/psycopg2_binary-2.9.12-cp313-cp313-win_amd64.whl", hash = "sha256:b6937f5fe4e180aeee87de907a2fa982ded6f7f15d7218f78a083e4e1d68f2a0", size = 2757347, upload-time = "2026-04-20T23:35:21.283Z" },
+ { url = "https://files.pythonhosted.org/packages/13/1b/708c0dca874acfad6d65314271859899a79007686f3a1f74e82a2ed4b645/psycopg2_binary-2.9.12-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6f3b3de8a74ef8db215f22edffb19e32dc6fa41340456de7ec99efdc8a7b3ec2", size = 3712428, upload-time = "2026-04-20T23:35:23.453Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/39/ddbea9d4b4de6aca9431b6ed253f530f8a02d3b8f9bcfd0dbfe2b3de6fe4/psycopg2_binary-2.9.12-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1006fb62f0f0bc5ce256a832356c6262e91be43f5e4eb15b5eaf38079464caf2", size = 3823184, upload-time = "2026-04-20T23:35:25.92Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/a0/bc2fef74b106fa345567122a0659e6d94512ed7dc0131ec44c9e5aba3725/psycopg2_binary-2.9.12-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:840066105706cd2eb29b9a1c2329620056582a4bf3e8169dec5c447042d0869f", size = 4579157, upload-time = "2026-04-20T23:35:28.542Z" },
+ { url = "https://files.pythonhosted.org/packages/57/d7/d4e3b2005d3de607ca4fbb0e8742e248056e52184a6b94ebda3c1c2c329b/psycopg2_binary-2.9.12-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:863f5d12241ebe1c76a72a04c2113b6dc905f90b9cef0e9be0efd994affd9354", size = 4274970, upload-time = "2026-04-20T23:35:30.418Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/42/c9853f8db3967fe08bcde11f53d53b85d351750cae726ce001cb68afa9c1/psycopg2_binary-2.9.12-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a99eaab34a9010f1a086b126de467466620a750634d114d20455f3a824aae033", size = 5895175, upload-time = "2026-04-20T23:35:33.584Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/fd/b82b5601a97630308bef079f545ffec481bbbc795c2ba5ec416a01d03f60/psycopg2_binary-2.9.12-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ffdd7dc5463ccd61845ac37b7012d0f35a1548df9febe14f8dd549be4a0bc81e", size = 4110658, upload-time = "2026-04-20T23:35:35.638Z" },
+ { url = "https://files.pythonhosted.org/packages/62/8c/32ca69b0389ef25dd22937bf9e8fbe2ce27aea20b05ded48c4ce4cb42475/psycopg2_binary-2.9.12-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:54a0dfecab1b48731f934e06139dfe11e24219fb6d0ceb32177cf0375f14c7b5", size = 3656251, upload-time = "2026-04-20T23:35:37.854Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/29/96992a2b59e3b9d730fcf9612d0a387305025dc867a9fc490a9e496e074e/psycopg2_binary-2.9.12-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:96937c9c5d891f772430f418a7a8b4691a90c3e6b93cf72b5bd7cad8cbca32a5", size = 3301810, upload-time = "2026-04-20T23:35:39.927Z" },
+ { url = "https://files.pythonhosted.org/packages/56/ad/44b06659949b243ae10112cd3b20a197f9bf3e81d5651379b9eb889bfaad/psycopg2_binary-2.9.12-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:77b348775efd4cdab410ec6609d81ccecd1139c90265fa583a7255c8064bc03d", size = 3048977, upload-time = "2026-04-20T23:35:41.806Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/f2/10a1bcebadb6aa55e280e1f58975c36a7b560ea525184c7aa4064c466633/psycopg2_binary-2.9.12-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:527e6342b3e44c2f0544f6b8e927d60de7f163f5723b8f1dfa7d2a84298738cd", size = 3351466, upload-time = "2026-04-20T23:35:43.993Z" },
+ { url = "https://files.pythonhosted.org/packages/20/be/b732c8418ffa5bcfda002890f5dc4c869fc17db66ff11f53b17cfe44afc0/psycopg2_binary-2.9.12-cp314-cp314-win_amd64.whl", hash = "sha256:f12ae41fcafadb39b2785e64a40f9db05d6de2ac114077457e0e7c597f3af980", size = 2848762, upload-time = "2026-04-20T23:35:46.421Z" },
+]
+
+[[package]]
+name = "ptyprocess"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" },
+]
+
+[[package]]
+name = "pure-eval"
+version = "0.2.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" },
+]
+
+[[package]]
+name = "pyasn1"
+version = "0.6.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" },
+]
+
+[[package]]
+name = "pycparser"
+version = "3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
+]
+
+[[package]]
+name = "pydantic"
+version = "2.13.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-types" },
+ { name = "pydantic-core" },
+ { name = "typing-extensions" },
+ { name = "typing-inspection" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" },
+]
+
+[[package]]
+name = "pydantic-core"
+version = "2.46.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158, upload-time = "2026-05-06T13:38:57.215Z" },
+ { url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724, upload-time = "2026-05-06T13:37:02.697Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742, upload-time = "2026-05-06T13:37:09.448Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", size = 2052418, upload-time = "2026-05-06T13:37:38.234Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", size = 2232274, upload-time = "2026-05-06T13:38:27.753Z" },
+ { url = "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", size = 2309940, upload-time = "2026-05-06T13:38:05.353Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", size = 2094516, upload-time = "2026-05-06T13:39:10.577Z" },
+ { url = "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", size = 2136854, upload-time = "2026-05-06T13:40:22.59Z" },
+ { url = "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", size = 2180306, upload-time = "2026-05-06T13:40:10.666Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", size = 2190044, upload-time = "2026-05-06T13:40:43.231Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", size = 2329133, upload-time = "2026-05-06T13:39:57.365Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", size = 2374464, upload-time = "2026-05-06T13:38:06.976Z" },
+ { url = "https://files.pythonhosted.org/packages/47/bd/6f2fc8188f31bf10590f1e98e7b306336161fac930a8c514cd7bd828c7dc/pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894", size = 1974823, upload-time = "2026-05-06T13:40:47.985Z" },
+ { url = "https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89", size = 2072919, upload-time = "2026-05-06T13:39:21.153Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/ba/f463d006e0c47373ca7ec5e1a261c59dc01ef4d62b2657af925fb0deee3a/pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a", size = 2027604, upload-time = "2026-05-06T13:39:03.753Z" },
+ { url = "https://files.pythonhosted.org/packages/51/a2/5d30b469c5267a17b39dec53208222f76a8d351dfac4af661888c5aee77d/pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008", size = 2106306, upload-time = "2026-05-06T13:37:48.029Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4", size = 1951906, upload-time = "2026-05-06T13:37:17.012Z" },
+ { url = "https://files.pythonhosted.org/packages/03/d5/fd02da45b659668b05923b17ba3a0100a0a3d5541e3bd8fcc4ecb711309e/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76", size = 1976802, upload-time = "2026-05-06T13:37:35.113Z" },
+ { url = "https://files.pythonhosted.org/packages/21/f2/95727e1368be3d3ed485eaab7adbd7dda408f33f7a36e8b48e0144002b91/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3", size = 2052446, upload-time = "2026-05-06T13:37:12.313Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/86/5d99feea3f77c7234b8718075b23db11532773c1a0dbd9b9490215dc2eeb/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76", size = 2232757, upload-time = "2026-05-06T13:39:01.149Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/3a/508ac615935ef7588cf6d9e9b91309fdc2da751af865e02a9098de88258c/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4", size = 2309275, upload-time = "2026-05-06T13:37:41.406Z" },
+ { url = "https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a", size = 2094467, upload-time = "2026-05-06T13:39:18.847Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/e2/f35033184cb11d0052daf4416e8e10a502ea2ac006fc4f459aee872727d1/pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262", size = 2134417, upload-time = "2026-05-06T13:40:17.944Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/7b/6ceeb1cc90e193862f444ebe373d8fdf613f0a82572dde03fb10734c6c71/pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e", size = 2179782, upload-time = "2026-05-06T13:40:32.618Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/f2/c8d7773ede6af08036423a00ae0ceffce266c3c52a096c435d68c896083f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd", size = 2188782, upload-time = "2026-05-06T13:36:51.018Z" },
+ { url = "https://files.pythonhosted.org/packages/59/31/0c864784e31f09f05cdd87606f08923b9c9e7f6e51dd27f20f62f975ce9f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be", size = 2328334, upload-time = "2026-05-06T13:40:37.764Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/eb/4f6c8a41efa30baa755590f4141abf3a8c370fab610915733e74134a7270/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d", size = 2372986, upload-time = "2026-05-06T13:39:34.152Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/24/b375a480d53113860c299764bfe9f349a3dc9108b3adc0d7f0d786492ebf/pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb", size = 1973693, upload-time = "2026-05-06T13:37:55.072Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/e8/cff247591966f2d22ec8c003cd7587e27b7ba7b81ab2fb888e3ab75dc285/pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292", size = 2071819, upload-time = "2026-05-06T13:38:49.139Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/1a/f4aee670d5670e9e148e0c82c7db98d780be566c6e6a97ee8035528ca0b3/pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d", size = 2027411, upload-time = "2026-05-06T13:40:45.796Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb", size = 2102079, upload-time = "2026-05-06T13:38:41.019Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462", size = 1952179, upload-time = "2026-05-06T13:36:59.812Z" },
+ { url = "https://files.pythonhosted.org/packages/95/30/5211a831ae054928054b2f79731661087a2bc5c01e825c672b3a4a8f1b3e/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9", size = 1978926, upload-time = "2026-05-06T13:37:39.933Z" },
+ { url = "https://files.pythonhosted.org/packages/57/e9/689668733b1eb67adeef047db3c2e8788fcf65a7fd9c9e2b46b7744fe245/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4", size = 2046785, upload-time = "2026-05-06T13:38:01.995Z" },
+ { url = "https://files.pythonhosted.org/packages/60/d9/6715260422ff50a2109878fd24d948a6c3446bb2664f34ee78cd972b3acd/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914", size = 2228733, upload-time = "2026-05-06T13:40:50.371Z" },
+ { url = "https://files.pythonhosted.org/packages/18/ae/fdb2f64316afca925640f8e70bb1a564b0ec2721c1389e25b8eb4bf9a299/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28", size = 2307534, upload-time = "2026-05-06T13:37:21.531Z" },
+ { url = "https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b", size = 2099732, upload-time = "2026-05-06T13:39:31.942Z" },
+ { url = "https://files.pythonhosted.org/packages/06/d5/ee5a3366637fee41dee51a1fc91562dcf12ddbc68fda34e6b253da2324bb/pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c", size = 2129627, upload-time = "2026-05-06T13:37:25.033Z" },
+ { url = "https://files.pythonhosted.org/packages/94/33/2414be571d2c6a6c4d08be21f9292b6d3fdb08949a97b6dfe985017821db/pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb", size = 2179141, upload-time = "2026-05-06T13:37:14.046Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/79/7daa95be995be0eecc4cf75064cb33f9bbbfe3fe0158caf2f0d4a996a5c7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898", size = 2184325, upload-time = "2026-05-06T13:36:53.615Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/cb/d0a382f5c0de8a222dc61c65348e0ce831b1f68e0a018450d31c2cace3a5/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e", size = 2323990, upload-time = "2026-05-06T13:40:29.971Z" },
+ { url = "https://files.pythonhosted.org/packages/05/db/d9ba624cc4a5aced1598e88c04fdbd8310c8a69b9d38b9a3d39ce3a61ed7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519", size = 2369978, upload-time = "2026-05-06T13:37:23.027Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/20/d15df15ba918c423461905802bfd2981c3af0bfa0e40d05e13edbfa48bc3/pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4", size = 1966354, upload-time = "2026-05-06T13:38:03.499Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/b6/6b8de4c0a7d7ab3004c439c80c5c1e0a3e8d78bbae19379b01960383d9e5/pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac", size = 2072238, upload-time = "2026-05-06T13:39:40.807Z" },
+ { url = "https://files.pythonhosted.org/packages/32/36/51eb763beec1f4cf59b1db243a7dcc39cbb41230f050a09b9d69faaf0a48/pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a", size = 2018251, upload-time = "2026-05-06T13:37:26.72Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/91/855af51d625b23aa987116a19e231d2aaef9c4a415273ddc189b79a45fee/pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0", size = 2099593, upload-time = "2026-05-06T13:39:47.682Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d", size = 1935226, upload-time = "2026-05-06T13:40:40.428Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/e7/1955d28d1afc56dd4b3ad7cc0cf39df1b9852964cf16e5d13912756d6d6b/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b", size = 1974605, upload-time = "2026-05-06T13:37:32.029Z" },
+ { url = "https://files.pythonhosted.org/packages/93/e2/3fedbf0ba7a22850e6e9fd78117f1c0f10f950182344d8a6c535d468fdd8/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000", size = 2030777, upload-time = "2026-05-06T13:38:55.239Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/61/46be275fcaaba0b4f5b9669dd852267ce1ff616592dccf7a7845588df091/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e", size = 2236641, upload-time = "2026-05-06T13:37:08.096Z" },
+ { url = "https://files.pythonhosted.org/packages/60/db/12e93e46a8bac9988be3c016860f83293daea8c716c029c9ace279036f2f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd", size = 2286404, upload-time = "2026-05-06T13:40:20.221Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/4a/4d8b19008f38d31c53b8219cfedc2e3d5de5fe99d90076b7e767de29274f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3", size = 2109219, upload-time = "2026-05-06T13:38:12.153Z" },
+ { url = "https://files.pythonhosted.org/packages/88/70/3cbc40978fefb7bb09c6708d40d4ad1a5d70fd7213c3d17f971de868ec1f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7", size = 2110594, upload-time = "2026-05-06T13:40:02.971Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/20/b8d36736216e29491125531685b2f9e61aa5b4b2599893f8268551da3338/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff", size = 2159542, upload-time = "2026-05-06T13:39:27.506Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/a2/367df868eb584dacf6bf82a389272406d7178e301c4ac82545ab98bc2dd9/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424", size = 2168146, upload-time = "2026-05-06T13:38:31.93Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/b8/4460f77f7e201893f649a29ab355dddd3beee8a97bcb1a320db414f9a06e/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6", size = 2306309, upload-time = "2026-05-06T13:37:44.717Z" },
+ { url = "https://files.pythonhosted.org/packages/64/c4/be2639293acd87dc8ddbcec41a73cee9b2ebf996fe6d892a1a74e88ad3f7/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565", size = 2369736, upload-time = "2026-05-06T13:37:05.645Z" },
+ { url = "https://files.pythonhosted.org/packages/30/a6/9f9f380dbb301f67023bf8f707aaa75daadf84f7152d95c410fd7e81d994/pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02", size = 1955575, upload-time = "2026-05-06T13:38:51.116Z" },
+ { url = "https://files.pythonhosted.org/packages/40/1f/f1eb9eb350e795d1af8586289746f5c5677d16043040d63710e22abc43c9/pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5", size = 2051624, upload-time = "2026-05-06T13:38:21.672Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/d2/42dd53d0a85c27606f316d3aa5d2869c4e8470a5ed6dec30e4a1abe19192/pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596", size = 2017325, upload-time = "2026-05-06T13:40:52.723Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527, upload-time = "2026-05-06T13:39:52.283Z" },
+ { url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024, upload-time = "2026-05-06T13:40:15.671Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696, upload-time = "2026-05-06T13:38:34.717Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590, upload-time = "2026-05-06T13:39:29.883Z" },
+]
+
+[[package]]
+name = "pydantic-settings"
+version = "2.14.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pydantic" },
+ { name = "python-dotenv" },
+ { name = "typing-inspection" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/07/60/1d1e59c9c90d54591469ada7d268251f71c24bdb765f1a8a832cee8c6653/pydantic_settings-2.14.1.tar.gz", hash = "sha256:e874d3bec7e787b0c9958277956ed9b4dd5de6a80e162188fdaff7c5e26fd5fa", size = 235551, upload-time = "2026-05-08T13:40:06.542Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ae/8d/f1af3832f5e6eb13ba94ee809e72b8ecb5eef226d27ee0bef7d963d943c7/pydantic_settings-2.14.1-py3-none-any.whl", hash = "sha256:6e3c7edfd8277687cdc598f56e5cff0e9bfff0910a3749deaa8d4401c3a2b9de", size = 60964, upload-time = "2026-05-08T13:40:04.958Z" },
+]
+
+[[package]]
+name = "pyee"
+version = "13.0.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/8b/04/e7c1fe4dc78a6fdbfd6c337b1c3732ff543b8a397683ab38378447baa331/pyee-13.0.1.tar.gz", hash = "sha256:0b931f7c14535667ed4c7e0d531716368715e860b988770fc7eb8578d1f67fc8", size = 31655, upload-time = "2026-02-14T21:12:28.044Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a0/c4/b4d4827c93ef43c01f599ef31453ccc1c132b353284fc6c87d535c233129/pyee-13.0.1-py3-none-any.whl", hash = "sha256:af2f8fede4171ef667dfded53f96e2ed0d6e6bd7ee3bb46437f77e3b57689228", size = 15659, upload-time = "2026-02-14T21:12:26.263Z" },
+]
+
+[[package]]
+name = "pygments"
+version = "2.20.0"
+source = { registry = "https://pypi.org/simple" }
+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/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 = "pyjwt"
+version = "2.13.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/3b/81/58d0ac84e1ef3a3843791d6954d94c0b33d526c75eeb1efbce9d0a4c4077/pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423", size = 107515, upload-time = "2026-05-21T19:54:36.618Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728", size = 31274, upload-time = "2026-05-21T19:54:35.362Z" },
+]
+
+[[package]]
+name = "pyparsing"
+version = "3.3.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" },
+]
+
+[[package]]
+name = "pytest"
+version = "9.0.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "iniconfig" },
+ { name = "packaging" },
+ { name = "pluggy" },
+ { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" },
+]
+
+[[package]]
+name = "pytest-asyncio"
+version = "1.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pytest" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/43/7c/d36d04db312ecf4298932ef77e6e4a9e8ad017906e24e34f0b0c361a2473/pytest_asyncio-1.4.0.tar.gz", hash = "sha256:c6c0d2259945122819f171a32ecea2c349ead889ee28176caaf492143424be42", size = 58514, upload-time = "2026-05-26T09:56:04.083Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl", hash = "sha256:933ca923a23075a87fb7070c0ec272a6848489824d887c85c812670932835aa1", size = 16930, upload-time = "2026-05-26T09:56:02.576Z" },
+]
+
+[[package]]
+name = "pytest-base-url"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pytest" },
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ae/1a/b64ac368de6b993135cb70ca4e5d958a5c268094a3a2a4cac6f0021b6c4f/pytest_base_url-2.1.0.tar.gz", hash = "sha256:02748589a54f9e63fcbe62301d6b0496da0d10231b753e950c63e03aee745d45", size = 6702, upload-time = "2024-01-31T22:43:00.81Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/98/1c/b00940ab9eb8ede7897443b771987f2f4a76f06be02f1b3f01eb7567e24a/pytest_base_url-2.1.0-py3-none-any.whl", hash = "sha256:3ad15611778764d451927b2a53240c1a7a591b521ea44cebfe45849d2d2812e6", size = 5302, upload-time = "2024-01-31T22:42:58.897Z" },
+]
+
+[[package]]
+name = "pytest-cov"
+version = "7.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "coverage" },
+ { name = "pluggy" },
+ { name = "pytest" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" },
+]
+
+[[package]]
+name = "pytest-playwright"
+version = "0.8.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "playwright" },
+ { name = "pytest" },
+ { name = "pytest-base-url" },
+ { name = "python-slugify" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/58/ef/172eb8e23c80491fc72f1401c72f9305663873649351306a38b18406b0c9/pytest_playwright-0.8.0.tar.gz", hash = "sha256:7888d4a2443160c82e0c506c437076679f86b36d1910427250d90fbf1843a981", size = 17132, upload-time = "2026-05-18T10:16:15.919Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fe/71/1c545fac6a9054b52b3771238fb2dc6e8f1d0ccec116e1c7786ec191887c/pytest_playwright-0.8.0-py3-none-any.whl", hash = "sha256:856aae6efd4bc055f2ef229c647768760bcaad5cd3a5983c314ac260a974a933", size = 17143, upload-time = "2026-05-18T10:16:18.226Z" },
+]
+
+[[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.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "filelock" },
+ { name = "platformdirs" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/48/60/e88788207d81e46362cfbef0d4aaf4c0f49efc3c12d4c3fa3f542c34ebec/python_discovery-1.3.1.tar.gz", hash = "sha256:62f6db28064c9613e7ca76cb3f00c38c839a07c31c00dfe7ed0986493d2150a6", size = 68011, upload-time = "2026-05-12T20:53:36.336Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b7/6f/a05a317a66fee0aad270011461f1a63a453ed12471249f172f7d2e2bc7b4/python_discovery-1.3.1-py3-none-any.whl", hash = "sha256:ed188687ebb3b82c01a17cd5ac62fc94d9f6487a7f1a0f9dfe89753fec91039c", size = 33185, upload-time = "2026-05-12T20:53:34.969Z" },
+]
+
+[[package]]
+name = "python-dotenv"
+version = "1.2.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" },
+]
+
+[[package]]
+name = "python-jose"
+version = "3.5.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "ecdsa" },
+ { name = "pyasn1" },
+ { name = "rsa" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c6/77/3a1c9039db7124eb039772b935f2244fbb73fc8ee65b9acf2375da1c07bf/python_jose-3.5.0.tar.gz", hash = "sha256:fb4eaa44dbeb1c26dcc69e4bd7ec54a1cb8dd64d3b4d81ef08d90ff453f2b01b", size = 92726, upload-time = "2025-05-28T17:31:54.288Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d9/c3/0bd11992072e6a1c513b16500a5d07f91a24017c5909b02c72c62d7ad024/python_jose-3.5.0-py2.py3-none-any.whl", hash = "sha256:abd1202f23d34dfad2c3d28cb8617b90acf34132c7afd60abd0b0b7d3cb55771", size = 34624, upload-time = "2025-05-28T17:31:52.802Z" },
+]
+
+[package.optional-dependencies]
+cryptography = [
+ { name = "cryptography" },
+]
+
+[[package]]
+name = "python-multipart"
+version = "0.0.29"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4e/fe/70bd71a6738b09a0bdf6480ca6436b167469ca4578b2a0efbe390b4b0e70/python_multipart-0.0.29.tar.gz", hash = "sha256:643e93849196645e2dbdd81a0f8829a23123ad7f797a84a364c6fb3563f18904", size = 45678, upload-time = "2026-05-17T17:29:47.654Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/8f/cb/769cfc37177252872a45a71f3fbdde9d51b471a3f3c14bfe95dde3407386/python_multipart-0.0.29-py3-none-any.whl", hash = "sha256:2ddcc971cef266225f54f552d8fa10bcfbb1f14446caec199060daac59ff2d69", size = 29640, upload-time = "2026-05-17T17:29:45.69Z" },
+]
+
+[[package]]
+name = "python-slugify"
+version = "8.0.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "text-unidecode" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/87/c7/5e1547c44e31da50a460df93af11a535ace568ef89d7a811069ead340c4a/python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856", size = 10921, upload-time = "2024-02-08T18:32:45.488Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a4/62/02da182e544a51a5c3ccf4b03ab79df279f9c60c5e82d5e8bec7ca26ac11/python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8", size = 10051, upload-time = "2024-02-08T18:32:43.911Z" },
+]
+
+[[package]]
+name = "pytokens"
+version = "0.4.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", size = 160663, upload-time = "2026-01-30T01:03:06.473Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", size = 255626, upload-time = "2026-01-30T01:03:08.177Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", size = 269779, upload-time = "2026-01-30T01:03:09.756Z" },
+ { url = "https://files.pythonhosted.org/packages/20/01/7436e9ad693cebda0551203e0bf28f7669976c60ad07d6402098208476de/pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9", size = 268076, upload-time = "2026-01-30T01:03:10.957Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/df/533c82a3c752ba13ae7ef238b7f8cdd272cf1475f03c63ac6cf3fcfb00b6/pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68", size = 103552, upload-time = "2026-01-30T01:03:12.066Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/dc/08b1a080372afda3cceb4f3c0a7ba2bde9d6a5241f1edb02a22a019ee147/pytokens-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8bdb9d0ce90cbf99c525e75a2fa415144fd570a1ba987380190e8b786bc6ef9b", size = 160720, upload-time = "2026-01-30T01:03:13.843Z" },
+ { url = "https://files.pythonhosted.org/packages/64/0c/41ea22205da480837a700e395507e6a24425151dfb7ead73343d6e2d7ffe/pytokens-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5502408cab1cb18e128570f8d598981c68a50d0cbd7c61312a90507cd3a1276f", size = 254204, upload-time = "2026-01-30T01:03:14.886Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/d2/afe5c7f8607018beb99971489dbb846508f1b8f351fcefc225fcf4b2adc0/pytokens-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29d1d8fb1030af4d231789959f21821ab6325e463f0503a61d204343c9b355d1", size = 268423, upload-time = "2026-01-30T01:03:15.936Z" },
+ { url = "https://files.pythonhosted.org/packages/68/d4/00ffdbd370410c04e9591da9220a68dc1693ef7499173eb3e30d06e05ed1/pytokens-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b08dd6b86058b6dc07efe9e98414f5102974716232d10f32ff39701e841c4", size = 266859, upload-time = "2026-01-30T01:03:17.458Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/c9/c3161313b4ca0c601eeefabd3d3b576edaa9afdefd32da97210700e47652/pytokens-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:9bd7d7f544d362576be74f9d5901a22f317efc20046efe2034dced238cbbfe78", size = 103520, upload-time = "2026-01-30T01:03:18.652Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/a7/b470f672e6fc5fee0a01d9e75005a0e617e162381974213a945fcd274843/pytokens-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4a14d5f5fc78ce85e426aa159489e2d5961acf0e47575e08f35584009178e321", size = 160821, upload-time = "2026-01-30T01:03:19.684Z" },
+ { url = "https://files.pythonhosted.org/packages/80/98/e83a36fe8d170c911f864bfded690d2542bfcfacb9c649d11a9e6eb9dc41/pytokens-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f50fd18543be72da51dd505e2ed20d2228c74e0464e4262e4899797803d7fa", size = 254263, upload-time = "2026-01-30T01:03:20.834Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/95/70d7041273890f9f97a24234c00b746e8da86df462620194cef1d411ddeb/pytokens-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc74c035f9bfca0255c1af77ddd2d6ae8419012805453e4b0e7513e17904545d", size = 268071, upload-time = "2026-01-30T01:03:21.888Z" },
+ { url = "https://files.pythonhosted.org/packages/da/79/76e6d09ae19c99404656d7db9c35dfd20f2086f3eb6ecb496b5b31163bad/pytokens-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f66a6bbe741bd431f6d741e617e0f39ec7257ca1f89089593479347cc4d13324", size = 271716, upload-time = "2026-01-30T01:03:23.633Z" },
+ { url = "https://files.pythonhosted.org/packages/79/37/482e55fa1602e0a7ff012661d8c946bafdc05e480ea5a32f4f7e336d4aa9/pytokens-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:b35d7e5ad269804f6697727702da3c517bb8a5228afa450ab0fa787732055fc9", size = 104539, upload-time = "2026-01-30T01:03:24.788Z" },
+ { url = "https://files.pythonhosted.org/packages/30/e8/20e7db907c23f3d63b0be3b8a4fd1927f6da2395f5bcc7f72242bb963dfe/pytokens-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8fcb9ba3709ff77e77f1c7022ff11d13553f3c30299a9fe246a166903e9091eb", size = 168474, upload-time = "2026-01-30T01:03:26.428Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/81/88a95ee9fafdd8f5f3452107748fd04c24930d500b9aba9738f3ade642cc/pytokens-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79fc6b8699564e1f9b521582c35435f1bd32dd06822322ec44afdeba666d8cb3", size = 290473, upload-time = "2026-01-30T01:03:27.415Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/35/3aa899645e29b6375b4aed9f8d21df219e7c958c4c186b465e42ee0a06bf/pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975", size = 303485, upload-time = "2026-01-30T01:03:28.558Z" },
+ { url = "https://files.pythonhosted.org/packages/52/a0/07907b6ff512674d9b201859f7d212298c44933633c946703a20c25e9d81/pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a", size = 306698, upload-time = "2026-01-30T01:03:29.653Z" },
+ { url = "https://files.pythonhosted.org/packages/39/2a/cbbf9250020a4a8dd53ba83a46c097b69e5eb49dd14e708f496f548c6612/pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918", size = 116287, upload-time = "2026-01-30T01:03:30.912Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" },
+]
+
+[[package]]
+name = "pyyaml"
+version = "6.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" },
+ { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" },
+ { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" },
+ { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" },
+ { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" },
+ { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" },
+ { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
+ { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
+ { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
+ { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
+ { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
+ { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
+ { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
+ { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
+ { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
+ { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
+ { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
+ { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
+ { 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 = "referencing"
+version = "0.37.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "attrs" },
+ { name = "rpds-py" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" },
+]
+
+[[package]]
+name = "regex"
+version = "2026.5.9"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/dc/0e/49aee608ad09480e7fd276898c99ec6192985fa331abe4eb3a986094490b/regex-2026.5.9.tar.gz", hash = "sha256:a8234aa23ec39894bfe4a3f1b85616a7032481964a13ac6fc9f10de4f6fca270", size = 416074, upload-time = "2026-05-09T23:15:19.37Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/50/9b/6550044bc44e17c84d312c031c2ec42fbdb6a4ec4e29093be3a172d08772/regex-2026.5.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:57eeeb05db7979413dec5438f2db21d7ecbba787cde7a711df1a6f6df672aa06", size = 490451, upload-time = "2026-05-09T23:12:34.72Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/95/fc7ba4303b5a0f92446a12ee6778ef2c6c799233f5060042a31bf390cfe9/regex-2026.5.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:398c521292f4c7fb807001dcd54694d3a1fcafc179a36ad9cc56f98df85930b6", size = 292112, upload-time = "2026-05-09T23:12:36.285Z" },
+ { url = "https://files.pythonhosted.org/packages/54/4b/ee27938d1b2c443e89a9a10e00d2d19aa5ee300cd3d61140644e93bb083e/regex-2026.5.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f7a7c26137296beba7784de6eba69c6a93a63ccebc385e4962fe67e267a91225", size = 289599, upload-time = "2026-05-09T23:12:38.089Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/dd/ba103dc19614e25f3880800ca67ce093d6e21b325d72b8383c7bf906e9fa/regex-2026.5.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6441cc660d76107934a09c22167200839a0e89604a6297f78a974e66e931d2c0", size = 796732, upload-time = "2026-05-09T23:12:40.062Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/e7/f035b4fd858b050b0080bf302968dc0f59ba34e391872d54936758e6844e/regex-2026.5.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:91328f1c23d47595ca3ef0a7557fa129c5a23404b775c770697d2f35b33e0107", size = 865440, upload-time = "2026-05-09T23:12:42.059Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/51/8cd301ecc899aea28124357f729f4272f44de7806fc7ca02490bfbe253e8/regex-2026.5.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:93a7860539414dddaefba2b40f8771765ae17949d4c7182b876ce429e11a8309", size = 912329, upload-time = "2026-05-09T23:12:44.373Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/1e/3fbe2fa1e8cebd62f3bb7d3321cff1640aca2e240b51d9bd624aad949260/regex-2026.5.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd2810d22146b6d838acc5ec15602cb6b47920aa4e33015df3868eedfd20bab8", size = 801239, upload-time = "2026-05-09T23:12:46.268Z" },
+ { url = "https://files.pythonhosted.org/packages/17/2f/6f6008682bf2cf98040a0d3153a8e557b6ab728d7713d045cee4ce544ab8/regex-2026.5.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:daff2bdbaf1d23e52fdff7c0b7bc2048b68f978df6a4d107ac981f94caef2e66", size = 777054, upload-time = "2026-05-09T23:12:48.051Z" },
+ { url = "https://files.pythonhosted.org/packages/19/2b/eee0d20a6842ba04df4b8847a920b57ef56853f14ef85405473e586b605a/regex-2026.5.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4eeb011098fcb77af513dcef521a3dbecbf8849b1e38940759d293b7a93f5026", size = 785098, upload-time = "2026-05-09T23:12:49.851Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/98/6fc1e6410feefb92159edaed5041992bfe390e8d26c721865434acbca558/regex-2026.5.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ea9c8ecfa1b73c73b626534d6626e5340d429630943672b8480724f44e84b962", size = 860095, upload-time = "2026-05-09T23:12:51.666Z" },
+ { url = "https://files.pythonhosted.org/packages/18/a3/bd855e0f2cb1a978ecf6fa6bb69632dd9c3f6ea3b81cde62fde14c9daec7/regex-2026.5.9-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:cd2846168eb9ee3c513902bc8225409cb1caab31d04728b145171fa1625d9621", size = 765762, upload-time = "2026-05-09T23:12:53.413Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/66/0ae8c092e60b14c79d24f8e0b7f0aea5bfbffdcab00b5483d13404d3c3a5/regex-2026.5.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:39617fb0cde9c0e6306dc70e3bfc096f3da793219879f7ae7aa341a69fbdcf6d", size = 852100, upload-time = "2026-05-09T23:12:55.256Z" },
+ { url = "https://files.pythonhosted.org/packages/21/de/8dfde60fc1b21c946a893ba273403b72617edb261370cb1087099a83f088/regex-2026.5.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fd03c4f0e33280d15cae17159b899245d6b7c53d21def19b263b39655061f5ce", size = 789479, upload-time = "2026-05-09T23:12:57.573Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/1c/bdcc98f9a4af4fdd166c74941174619ccff4726d3ce32faa8e9a2ecd38dd/regex-2026.5.9-cp312-cp312-win32.whl", hash = "sha256:164eba9b755ea6f244b0d881196fbc1fac09714e9782c9e2732b813142033c8e", size = 266699, upload-time = "2026-05-09T23:12:59.14Z" },
+ { url = "https://files.pythonhosted.org/packages/78/87/240d36864f9e48ace85f72e79ced97ceb7f27ce87739a947dcb834b4e6bc/regex-2026.5.9-cp312-cp312-win_amd64.whl", hash = "sha256:86f40a5d6444db30a125c9c9177e6b25dad981cbc37451fd838f145e6edac92e", size = 277783, upload-time = "2026-05-09T23:13:00.789Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/b5/7b30f312b0669dff5beebe5b0989dc2d1a312b1a44fab852199c387a5b96/regex-2026.5.9-cp312-cp312-win_arm64.whl", hash = "sha256:96f5f58b54a063d7ea9dca08e1cf57bfe10499c4d579ee672da284f57f5f0070", size = 270513, upload-time = "2026-05-09T23:13:02.426Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/da/797e91ecec6f84135da778ddce78c20e0af5d2a15c26f87a81bc3eadb6db/regex-2026.5.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d626b84406444b165fc0ba981604edea39f0588ff1f92baa23fe50799ea9afdb", size = 490303, upload-time = "2026-05-09T23:13:04.382Z" },
+ { url = "https://files.pythonhosted.org/packages/44/da/bf30abaaa737b58f4a4b8c4a03659e02fd92092c822e0197ed9e0daab917/regex-2026.5.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d7bdc0ab8f3dd7e1b4f9ab88634e13374669db86bb3c72e8292f07ae313f539f", size = 292019, upload-time = "2026-05-09T23:13:06.022Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/e7/d0eaf5713828417b9e5648cf81fa9bacd4961f6ab98c380c2034f8716e35/regex-2026.5.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a8820737949116ffff55fe18f9fc644530063ba6ebfcb8314239416e78f1347c", size = 289468, upload-time = "2026-05-09T23:13:08.214Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/9b/b3fdd62b003baa1a9b593cd8c8699c9651c2e80cc21a5c715707983c42d7/regex-2026.5.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0fbdbac82cb3e4450d0ccde7d7a35607f4cb2dd9fba4b8b69bfaf8c9fa6aed", size = 796749, upload-time = "2026-05-09T23:13:10.573Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/30/66ab84588765f5b4b271a9ca09ef7ce2b87caa95176ec3d2ad65d7bc4902/regex-2026.5.9-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:57e8915c7986aa33d25e4d3629cef711cd2863f2961b10409f0c04cb8b7d9020", size = 865445, upload-time = "2026-05-09T23:13:12.523Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/89/f05169e8588aac365f35ffc7f3bc3184f095ef4cfded7cfaa3c7fd5dbd89/regex-2026.5.9-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:508f56a89ba9cb26e4168cbc37dbd60a28d82430a9e18ad1d25fe0883c314ca2", size = 912322, upload-time = "2026-05-09T23:13:14.281Z" },
+ { url = "https://files.pythonhosted.org/packages/30/e1/c93444052cf41581f3c884ab3fb5823daf0992f11cd4388d4275ca610558/regex-2026.5.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6d189041f15691cfa2b6c4290448ec221244d225b3f5fe9e7771b34ffcdf6e2", size = 801269, upload-time = "2026-05-09T23:13:16.569Z" },
+ { url = "https://files.pythonhosted.org/packages/50/fe/0cf96b882f540e62e8b9956599798203d599c44cf4c77917ca27400ff69b/regex-2026.5.9-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e82db382b44d0111b22601c509c89f64434816c9e0eef9d1989cda8cc6ff1c04", size = 777085, upload-time = "2026-05-09T23:13:18.675Z" },
+ { url = "https://files.pythonhosted.org/packages/23/5c/d78d4924e7fc875557b9e9b768423925fdfaac5549d06da7810019a9bd26/regex-2026.5.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2acfb48634f64996b57f90f39afa692ff362162722581921fe92239a59960f3c", size = 785153, upload-time = "2026-05-09T23:13:20.525Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/e0/5214774090e7b4524dcea3e3c4aa74141d43043f8beb49c1599db1c8b53a/regex-2026.5.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d29eebfc9525db68cad3c97eedd7f754fa265aa5cd0cf4f863b2421e1b48fc9f", size = 860164, upload-time = "2026-05-09T23:13:22.263Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/e1/4a57a83350319b1271f0d7a249b8672513ed928b237a741631270de6caea/regex-2026.5.9-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:debb893095e944091c16e641a6e33c1b0f4cb61ab945ec5afbf53ce7068834d8", size = 765731, upload-time = "2026-05-09T23:13:24.277Z" },
+ { url = "https://files.pythonhosted.org/packages/12/f4/499e74a20c156fc75836ee04a72a38d1a063978f600937f9760467beb1b0/regex-2026.5.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d659eee77986549c9ea45b861c7567e44d6287c3dc9a4565478853f7b9fe2ff6", size = 852062, upload-time = "2026-05-09T23:13:26.125Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/92/7eebc0d0a01e78629695f342ba17e0deaff8fb45e79cc0d7b98287da6e3e/regex-2026.5.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2efa205e6d98b24d1f3ab395c11aa15cdf10935bca283d0285e0499c284fba21", size = 789577, upload-time = "2026-05-09T23:13:27.814Z" },
+ { url = "https://files.pythonhosted.org/packages/05/a4/018e71f7d2ad48c1ebe6d3ae0026f9b7cb4802fd15c7cc02fdf724355102/regex-2026.5.9-cp313-cp313-win32.whl", hash = "sha256:f3844f134e834076677dd369976e9f5068679fcb8e50102fdf6b7ac96a3ec127", size = 266691, upload-time = "2026-05-09T23:13:29.549Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/1d/861a93719fb9ee7dbfc3761b3797b7a3e112a5d42c6129459d2d741be9b5/regex-2026.5.9-cp313-cp313-win_amd64.whl", hash = "sha256:3527bb4942d2c14552155406cdedd906567456821848aed1cb4933a391bf5eca", size = 277747, upload-time = "2026-05-09T23:13:31.859Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/c6/0a2436ae4da1ba76e51cb98943c6838a9a721faa40ebe2dce07694ae34e3/regex-2026.5.9-cp313-cp313-win_arm64.whl", hash = "sha256:56a33f191f17d8c417f99945ebdc1e691d3af9605d86ec68c7e54a57e3e17af6", size = 270500, upload-time = "2026-05-09T23:13:33.525Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/e9/d21346f7b60ed58789371358ed66b09d00f832e1bd7c06e55d9da5679882/regex-2026.5.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:01f28d868834624c934b8d2e0aa1c8341337e37831f4a012f18a5afcba4cbaf3", size = 494172, upload-time = "2026-05-09T23:13:35.935Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/43/fd1177a2032037c681baecdb3422ee4e1424aec4e4f470ef47793d325274/regex-2026.5.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:48036f6374aaa79eb3b754ec29c61d1c6b1606749d705a13f8854fa2539671f6", size = 293952, upload-time = "2026-05-09T23:13:38.307Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/7d/9fbf919768368d3f8a4f6c692cf2aa61e482b2b81ec6a298ace4cbf02480/regex-2026.5.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b96350aa424e79d4fd6b567b344dcbe2b2d6bfc48dfe7717587e1fa6d43da6ff", size = 292314, upload-time = "2026-05-09T23:13:40.353Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/6c/e41bfeecb589716843e7c4df09ba46ff2a42961457afece19059d85caeef/regex-2026.5.9-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f3af7a4903c5c04a11a196a5aa75cdd7dd3f8508132f9fb3259d9f5908e3b88", size = 811681, upload-time = "2026-05-09T23:13:42.543Z" },
+ { url = "https://files.pythonhosted.org/packages/87/83/a5c1c525fba0aa656e88ad0face0b1829788ef4c2fb6b26df58aa1151b84/regex-2026.5.9-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7e87577720152d2caae19fe2baaf1f8d5ca12091e9e229f03915c37d1e4b9178", size = 871135, upload-time = "2026-05-09T23:13:44.326Z" },
+ { url = "https://files.pythonhosted.org/packages/18/d4/80882e799e440dd878b0979cbebf8fa4d54624a332c83037c7a701649e3f/regex-2026.5.9-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c8b9b9d294cfea3cd19c718ade7cc93492b2c4991abd9a68d0b3477ae6d8e100", size = 917265, upload-time = "2026-05-09T23:13:47.295Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/ff/8db60211e2286e396aad7dc7725356c502bff0901ea05bd6cdc2e1a042b9/regex-2026.5.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:728d8bfd28a8845c8b6bc5dc7ce010453d206396786c0765c2740cb65f37791e", size = 816311, upload-time = "2026-05-09T23:13:49.885Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/47/742ef579c61730f8d268e5cf1f9ce0e37e2ea041ad0f5644724f2378e463/regex-2026.5.9-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7e30b874d341fac767d7df5a0870540541c2c054b80cfaac116e8d367a8a7ff2", size = 785498, upload-time = "2026-05-09T23:13:52.25Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/ab/cb0999802dcb0fb95b1ab005e8d4163d8afdd67efc2cb6b6630ac13f8cb1/regex-2026.5.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fd190e88a895a8901325fad284a3f74ea52b1da8525b76cc811fa9b1edf0ce2b", size = 801348, upload-time = "2026-05-09T23:13:54.127Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/62/8ca59a24c55bc34d166eefaf3717bd77772f329fdbf984d86581e0a3571c/regex-2026.5.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:8e76e8161ad00694cfce6767d5dea860c6391ac5b83e5c3a39661e696f11fc7e", size = 866493, upload-time = "2026-05-09T23:13:56.067Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/3d/30f2ae62cef3278bb5bb821f467277a55fb73f01032cf85997e15e8289a8/regex-2026.5.9-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ddda5340e6c01a293027dd46232fa79eaff1b48058ce7a98f572b6445b088041", size = 772811, upload-time = "2026-05-09T23:13:57.867Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/ae/7d2089bcd78ad0c0161bc684339df50032acb438a7bd3305e7ddb1193cec/regex-2026.5.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:205109e96b3cf5adf8f4cd62bedde9487feb282b9497a3535451e5a24cd706a0", size = 856584, upload-time = "2026-05-09T23:13:59.679Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/29/92ff47f75990131ea4f24ba17819e5a9d141e10819807e09addd73409af6/regex-2026.5.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dfbe4579b9f08036aa7d101d1835437a20783574ac66327e6b29b4018a138081", size = 803453, upload-time = "2026-05-09T23:14:01.978Z" },
+ { url = "https://files.pythonhosted.org/packages/04/99/eff29f1037dcab36702c9ee5d6858cf1ce2336ea8ea2987f64245b99ea5e/regex-2026.5.9-cp313-cp313t-win32.whl", hash = "sha256:ed2c9e8068b614c574d8d30e543d617cf5379b0535d46f97ef00e904745a08b5", size = 269951, upload-time = "2026-05-09T23:14:03.661Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/9d/8870b8981d27b22cda77bb26a5ac7ebfa9c7d9e0dea195a834a82380e748/regex-2026.5.9-cp313-cp313t-win_amd64.whl", hash = "sha256:b46b0f094dc1d3b90356c85a0bd2c9bafc4a6a190b9d6f8ddd5a033b6e088ed4", size = 281240, upload-time = "2026-05-09T23:14:05.56Z" },
+ { url = "https://files.pythonhosted.org/packages/72/b1/3379415e8f135c13ac551353397cc4fe97b4978f3cac73c5fcbcded548b8/regex-2026.5.9-cp313-cp313t-win_arm64.whl", hash = "sha256:872acc074bd29ffc9913ecdfedf6ea77502312ca44a4aa0d3779089c6069d8de", size = 272383, upload-time = "2026-05-09T23:14:07.843Z" },
+ { url = "https://files.pythonhosted.org/packages/13/3e/9c3cd292d8808b3645a2ce517e200179b6d0e903f176300bd8b542e14de5/regex-2026.5.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:1bd7587a2948b4085195d5a3374eaf4a425dc3e55784c038175355ecf3bbbf8a", size = 490376, upload-time = "2026-05-09T23:14:09.64Z" },
+ { url = "https://files.pythonhosted.org/packages/60/70/d43ee8a2ca0a8b68d167f21658b85520ac0574617c7f320367c5047f7556/regex-2026.5.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:dea2e88e1cce4522496cce630e11e67b98b7076620bc4336c3f674bc21a375f4", size = 291964, upload-time = "2026-05-09T23:14:11.424Z" },
+ { url = "https://files.pythonhosted.org/packages/21/91/9d50b433828d8e74196904e168a43abf1e6e88b2a15d47ed742456720c37/regex-2026.5.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2099f7e7ff7b6aa3192312650a56e91cc091e49d50b04e4f6f8b6e28b3b27f1c", size = 289682, upload-time = "2026-05-09T23:14:13.123Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/d2/b835e3cafbb9d977736912436259ff551d60919f7d7b3d37d46659c63564/regex-2026.5.9-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecd353045824e4477562a2ac718c25799cdaaa41f7aa925a806a8a3e6848a5b9", size = 796996, upload-time = "2026-05-09T23:14:14.923Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/a6/9f992d00019166b9de01c546dd4549bc679f2a68df11b877740b0760b7c2/regex-2026.5.9-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65c8c8c37377794bd5b2f3ebe51919042bf17aec802e23c833d89782ed0c78af", size = 866089, upload-time = "2026-05-09T23:14:17.757Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/08/4d32af657e049b19cb62b02e46e38fe1518797bfb2203ee93a510b21b0dc/regex-2026.5.9-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b73ab8afcf66c622db143d1c6fda4e58e4d537ee4f125229ad47b1ab80f34c0", size = 911530, upload-time = "2026-05-09T23:14:20.353Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/27/2af43dd1dc201d1fecefda64a45f4ad0995855b92724f795a777b402ee69/regex-2026.5.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0de5cf193997384ed2ca6f1cd4f78055b255d93d82d5a8cd6ba0d11c10b167e4", size = 800643, upload-time = "2026-05-09T23:14:22.265Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/dd/23a249047013b5321d4a60c4d2437462086f601b061776a525e5fba2a59f/regex-2026.5.9-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d641a8c9a61618047796d572a39a79b26167b0411d2c3031937b2fe2d081e2cf", size = 777223, upload-time = "2026-05-09T23:14:24.179Z" },
+ { url = "https://files.pythonhosted.org/packages/94/6a/e85ed9538cd19586d0465076a4578a12e093ce776d15f3f8ce92733a8dd6/regex-2026.5.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:24b2355ef5cc9aa5b8f07d17704face1c166fdcc2290fa7bd6e6c925655a8346", size = 785760, upload-time = "2026-05-09T23:14:26.065Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/c4/f25473209438638e947c55f9156fd8f236f74169229028cc99116380868e/regex-2026.5.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:a24852d3c29ad9e47593593d8a247c44ccc3d0548ef12c822d6ed0810affe676", size = 860891, upload-time = "2026-05-09T23:14:28.17Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/f7/f4f86e3c74419c37370e91f150ae0c2ef7d34b2e0e4cdd5da046a02e4022/regex-2026.5.9-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:916714069da19329ef7de197dcbc77bb3104145c7c2c864dbfbe318f46b88b14", size = 765891, upload-time = "2026-05-09T23:14:30.06Z" },
+ { url = "https://files.pythonhosted.org/packages/26/70/704d8e13765939146b1cd0ef4e2feb71d7929727d2290f026eed10095955/regex-2026.5.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:fa411799ca8da32a8d38d020a88faa5b6f91657d284761352940ecf9f7c3bbdd", size = 851380, upload-time = "2026-05-09T23:14:32.123Z" },
+ { url = "https://files.pythonhosted.org/packages/26/29/1a13582a8460038edc38e49f64ceb0dd7c60f5caba77571f4bf6601965d9/regex-2026.5.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1e6da47d679b7010ef27556b6e0f99771b744936db1792a10ceac6547ae1503e", size = 789350, upload-time = "2026-05-09T23:14:34.799Z" },
+ { url = "https://files.pythonhosted.org/packages/73/56/3dcafe34fc72e271d62ad9a291801e88a1457bb251c132f15fcc2e5aad1a/regex-2026.5.9-cp314-cp314-win32.whl", hash = "sha256:98bd73080e8756255137e1bd3f3f00295bbc5aa383c0e0f973920e9134d7c4ad", size = 272130, upload-time = "2026-05-09T23:14:36.729Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/9c/02eebf0be95efe416c664db7fb8b6b05b7a0b06a7544f2884f2558b0526f/regex-2026.5.9-cp314-cp314-win_amd64.whl", hash = "sha256:ff8d372ac2acdc048d1c19916f27ee61bc5722728458ba6ca5052f2c72d51763", size = 280999, upload-time = "2026-05-09T23:14:39.126Z" },
+ { url = "https://files.pythonhosted.org/packages/70/5a/1dd1abee76cb7a846a0bcf42fdc87e5720c3c33c24f3e37814310a513d9f/regex-2026.5.9-cp314-cp314-win_arm64.whl", hash = "sha256:e1d93bf647916292e8edcec150c07ddf3dc50179ccaf770c04a7f9e452155372", size = 273500, upload-time = "2026-05-09T23:14:41.059Z" },
+ { url = "https://files.pythonhosted.org/packages/86/c1/c5f619b0057a7965cb78ec559c1d7a45ce8c99a35bea95483d64959a93d9/regex-2026.5.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:83d0ee4a57d1c87cb549e195ec300b8f0ec3a82eba66d835e4e2ed8634fe4499", size = 494269, upload-time = "2026-05-09T23:14:42.869Z" },
+ { url = "https://files.pythonhosted.org/packages/05/2c/5d01f1aee33de4bbe60c8452945bfc8477ca7c5ae4450f6bfe711036cb36/regex-2026.5.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d3d7eb5c9a7f6df82ed3cfac9beb93882a5cbcb5b8b157b56cb2b3b276574ac1", size = 293954, upload-time = "2026-05-09T23:14:44.822Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/fe/e8988b2ae2108c6ef71bd4aa8d87fbe257976dd0810e826cd75f701c68b6/regex-2026.5.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:075160bf16658e16d35233300b8453aac25de4cbea808d22348b6979668e924d", size = 292405, upload-time = "2026-05-09T23:14:47.211Z" },
+ { url = "https://files.pythonhosted.org/packages/79/34/d2b0937faa7859263f7f0a3c6b103a1296306be6952dc173d0154e9a2f49/regex-2026.5.9-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45375819235558a4ff1c4971dc32881f022613abdb180128f5cb4768c1765a1c", size = 811855, upload-time = "2026-05-09T23:14:49.21Z" },
+ { url = "https://files.pythonhosted.org/packages/80/fe/daf53a47457a8486db66c66c01ceb9c2303eecee3f87197f1e77eb1a736d/regex-2026.5.9-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ead4b163ac30a29574510cd4b3e2e985ac5290c05fc7095557d6a5f403fc31b5", size = 871189, upload-time = "2026-05-09T23:14:51.555Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/75/058fc4470cbfbf57d800aff1a0022b929a3f9fa553ee10a0cdf2070eb31f/regex-2026.5.9-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c6e4218fbdfbcd4f6c19efca40930d24a621bf4b48cb76bc6640543bd28ef20", size = 917485, upload-time = "2026-05-09T23:14:53.633Z" },
+ { url = "https://files.pythonhosted.org/packages/88/e7/179cfda3a28bc843b5c6cfe7f79f23489c791ed95f151083803660878432/regex-2026.5.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6351571c8a42b505eb555c0dc47d740d0fb66977dc142919eea6f4325b7c56a0", size = 816369, upload-time = "2026-05-09T23:14:56.198Z" },
+ { url = "https://files.pythonhosted.org/packages/41/90/6f0cc422071688266d344fca8462d787cba0a2c144acb25721f9a61ec265/regex-2026.5.9-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:002205cafd2a9e78c6290c7d1df277bf3277b3b7a30e0b4bb0dac2e2e3f7cb2d", size = 785869, upload-time = "2026-05-09T23:14:58.602Z" },
+ { url = "https://files.pythonhosted.org/packages/02/67/a31f1760f09c27b251ef39e9beb541f462cf977381d067faa764c2c0e393/regex-2026.5.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8abd33fef90b2a9efac5557d6033ca82d1195ed3a15fea5af15ba7b463c6a63b", size = 801427, upload-time = "2026-05-09T23:15:00.642Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/c4/1a80654597b6bc1e1ea0494824c31200e8a956abe290afae9b19a166a148/regex-2026.5.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:31037c82eccb44b7ea2e9e221d7c01429430e989a1f4b91ea5a855f6017b509a", size = 866482, upload-time = "2026-05-09T23:15:03.384Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/11/960724e06482c08466ff5611e242e86f80062949cdf6b4b9cc317b9dd93d/regex-2026.5.9-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5604dfd046dc37eca90250fc3be938b076c8059fa772ac0ed6f499b0f0fb0415", size = 773022, upload-time = "2026-05-09T23:15:05.625Z" },
+ { url = "https://files.pythonhosted.org/packages/50/a8/a9979c3e7918280e93159ebcab5ef1a65116dd4f3bd6091be0eae4a126e8/regex-2026.5.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e1b1b4e496afbb24f4a62aba855ee4f88f25578927697b340702e48c9ee6bc2", size = 856642, upload-time = "2026-05-09T23:15:07.966Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/d4/a9b732f2f0072c0ab12227483abb24fffcb9f73f8a2b203df0a6d0434735/regex-2026.5.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:be3372b9df6ddecff6486d37e19095a7b4973137caf5512407a89f4455361f41", size = 803552, upload-time = "2026-05-09T23:15:10.215Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/fe/1b3113817447a1d4155e4ac76d2e072f42c0bcba2f43fa8a0e756ea2cd91/regex-2026.5.9-cp314-cp314t-win32.whl", hash = "sha256:3ddd90103f9e5c471c49c7852ecc1fe27c7e45eb99e977aefe7caa4e779f4f58", size = 275746, upload-time = "2026-05-09T23:15:12.609Z" },
+ { url = "https://files.pythonhosted.org/packages/92/73/93d42045302636c91f2e5ef588b65b84b01428f28ec77de256b1dfdfbe5c/regex-2026.5.9-cp314-cp314t-win_amd64.whl", hash = "sha256:ca518ed29c46eecba6010b15f1b9a479314d2de409536e71b6a13aa04e3b8a77", size = 285685, upload-time = "2026-05-09T23:15:15.086Z" },
+ { url = "https://files.pythonhosted.org/packages/da/80/35b4c33c804a165a7f55289afda3ea9e3eb6d15800341a2d66455c0f1f30/regex-2026.5.9-cp314-cp314t-win_arm64.whl", hash = "sha256:5e41809d2683fcde7d5a8c87a6567ba1fb1ce0de9f31bff578de00a4b2d76daa", size = 275713, upload-time = "2026-05-09T23:15:16.98Z" },
+]
+
+[[package]]
+name = "requests"
+version = "2.34.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "charset-normalizer" },
+ { name = "idna" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" },
+]
+
+[[package]]
+name = "requests-mock"
+version = "1.12.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/92/32/587625f91f9a0a3d84688bf9cfc4b2480a7e8ec327cefd0ff2ac891fd2cf/requests-mock-1.12.1.tar.gz", hash = "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401", size = 60901, upload-time = "2024-03-29T03:54:29.446Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/97/ec/889fbc557727da0c34a33850950310240f2040f3b1955175fdb2b36a8910/requests_mock-1.12.1-py2.py3-none-any.whl", hash = "sha256:b1e37054004cdd5e56c84454cc7df12b25f90f382159087f4b6915aaeef39563", size = 27695, upload-time = "2024-03-29T03:54:27.64Z" },
+]
+
+[[package]]
+name = "responses"
+version = "0.26.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyyaml" },
+ { name = "requests" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c2/58/1fb6de3503428196df78638f991ec8095274f1ee9723e272ee4d9ff0092b/responses-0.26.1.tar.gz", hash = "sha256:2eb3218553cc8f79b57d257bac23af5e1bf381f5b9390b1767816f0843e01dc2", size = 83088, upload-time = "2026-05-21T19:56:39.747Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3a/31/6a620b4427d546b9e7cca8b3b8c5f0559d9cef2bb9eedcda7f73c1473c19/responses-0.26.1-py3-none-any.whl", hash = "sha256:8aacc4586eb08fb2208ef64a9eb4258d9b0c6e6f4260845f2f018ab847495345", size = 35502, upload-time = "2026-05-21T19:56:38.046Z" },
+]
+
+[[package]]
+name = "rich"
+version = "14.3.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markdown-it-py" },
+ { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e9/67/cae617f1351490c25a4b8ac3b8b63a4dda609295d8222bad12242dfdc629/rich-14.3.4.tar.gz", hash = "sha256:817e02727f2b25b40ef56f5aa2217f400c8489f79ca8f46ea2b70dd5e14558a9", size = 230524, upload-time = "2026-04-11T02:57:45.419Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl", hash = "sha256:07e7adb4690f68864777b1450859253bed81a99a31ac321ac1817b2313558952", size = 310480, upload-time = "2026-04-11T02:57:47.484Z" },
+]
+
+[[package]]
+name = "rpds-py"
+version = "0.30.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/03/e7/98a2f4ac921d82f33e03f3835f5bf3a4a40aa1bfdc57975e74a97b2b4bdd/rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad", size = 375086, upload-time = "2025-11-30T20:22:17.93Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/a1/bca7fd3d452b272e13335db8d6b0b3ecde0f90ad6f16f3328c6fb150c889/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05", size = 359053, upload-time = "2025-11-30T20:22:19.297Z" },
+ { url = "https://files.pythonhosted.org/packages/65/1c/ae157e83a6357eceff62ba7e52113e3ec4834a84cfe07fa4b0757a7d105f/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28", size = 390763, upload-time = "2025-11-30T20:22:21.661Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/36/eb2eb8515e2ad24c0bd43c3ee9cd74c33f7ca6430755ccdb240fd3144c44/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd", size = 408951, upload-time = "2025-11-30T20:22:23.408Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/65/ad8dc1784a331fabbd740ef6f71ce2198c7ed0890dab595adb9ea2d775a1/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f", size = 514622, upload-time = "2025-11-30T20:22:25.16Z" },
+ { url = "https://files.pythonhosted.org/packages/63/8e/0cfa7ae158e15e143fe03993b5bcd743a59f541f5952e1546b1ac1b5fd45/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1", size = 414492, upload-time = "2025-11-30T20:22:26.505Z" },
+ { url = "https://files.pythonhosted.org/packages/60/1b/6f8f29f3f995c7ffdde46a626ddccd7c63aefc0efae881dc13b6e5d5bb16/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23", size = 394080, upload-time = "2025-11-30T20:22:27.934Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/d5/a266341051a7a3ca2f4b750a3aa4abc986378431fc2da508c5034d081b70/rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6", size = 408680, upload-time = "2025-11-30T20:22:29.341Z" },
+ { url = "https://files.pythonhosted.org/packages/10/3b/71b725851df9ab7a7a4e33cf36d241933da66040d195a84781f49c50490c/rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51", size = 423589, upload-time = "2025-11-30T20:22:31.469Z" },
+ { url = "https://files.pythonhosted.org/packages/00/2b/e59e58c544dc9bd8bd8384ecdb8ea91f6727f0e37a7131baeff8d6f51661/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5", size = 573289, upload-time = "2025-11-30T20:22:32.997Z" },
+ { url = "https://files.pythonhosted.org/packages/da/3e/a18e6f5b460893172a7d6a680e86d3b6bc87a54c1f0b03446a3c8c7b588f/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e", size = 599737, upload-time = "2025-11-30T20:22:34.419Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/e2/714694e4b87b85a18e2c243614974413c60aa107fd815b8cbc42b873d1d7/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394", size = 563120, upload-time = "2025-11-30T20:22:35.903Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/ab/d5d5e3bcedb0a77f4f613706b750e50a5a3ba1c15ccd3665ecc636c968fd/rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf", size = 223782, upload-time = "2025-11-30T20:22:37.271Z" },
+ { url = "https://files.pythonhosted.org/packages/39/3b/f786af9957306fdc38a74cef405b7b93180f481fb48453a114bb6465744a/rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b", size = 240463, upload-time = "2025-11-30T20:22:39.021Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/d2/b91dc748126c1559042cfe41990deb92c4ee3e2b415f6b5234969ffaf0cc/rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e", size = 230868, upload-time = "2025-11-30T20:22:40.493Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/dc/d61221eb88ff410de3c49143407f6f3147acf2538c86f2ab7ce65ae7d5f9/rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2", size = 374887, upload-time = "2025-11-30T20:22:41.812Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/32/55fb50ae104061dbc564ef15cc43c013dc4a9f4527a1f4d99baddf56fe5f/rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8", size = 358904, upload-time = "2025-11-30T20:22:43.479Z" },
+ { url = "https://files.pythonhosted.org/packages/58/70/faed8186300e3b9bdd138d0273109784eea2396c68458ed580f885dfe7ad/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4", size = 389945, upload-time = "2025-11-30T20:22:44.819Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/a8/073cac3ed2c6387df38f71296d002ab43496a96b92c823e76f46b8af0543/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136", size = 407783, upload-time = "2025-11-30T20:22:46.103Z" },
+ { url = "https://files.pythonhosted.org/packages/77/57/5999eb8c58671f1c11eba084115e77a8899d6e694d2a18f69f0ba471ec8b/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7", size = 515021, upload-time = "2025-11-30T20:22:47.458Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/af/5ab4833eadc36c0a8ed2bc5c0de0493c04f6c06de223170bd0798ff98ced/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2", size = 414589, upload-time = "2025-11-30T20:22:48.872Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/de/f7192e12b21b9e9a68a6d0f249b4af3fdcdff8418be0767a627564afa1f1/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6", size = 394025, upload-time = "2025-11-30T20:22:50.196Z" },
+ { url = "https://files.pythonhosted.org/packages/91/c4/fc70cd0249496493500e7cc2de87504f5aa6509de1e88623431fec76d4b6/rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e", size = 408895, upload-time = "2025-11-30T20:22:51.87Z" },
+ { url = "https://files.pythonhosted.org/packages/58/95/d9275b05ab96556fefff73a385813eb66032e4c99f411d0795372d9abcea/rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d", size = 422799, upload-time = "2025-11-30T20:22:53.341Z" },
+ { url = "https://files.pythonhosted.org/packages/06/c1/3088fc04b6624eb12a57eb814f0d4997a44b0d208d6cace713033ff1a6ba/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7", size = 572731, upload-time = "2025-11-30T20:22:54.778Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/42/c612a833183b39774e8ac8fecae81263a68b9583ee343db33ab571a7ce55/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31", size = 599027, upload-time = "2025-11-30T20:22:56.212Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/60/525a50f45b01d70005403ae0e25f43c0384369ad24ffe46e8d9068b50086/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95", size = 563020, upload-time = "2025-11-30T20:22:58.2Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/5d/47c4655e9bcd5ca907148535c10e7d489044243cc9941c16ed7cd53be91d/rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d", size = 223139, upload-time = "2025-11-30T20:23:00.209Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/e1/485132437d20aa4d3e1d8b3fb5a5e65aa8139f1e097080c2a8443201742c/rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15", size = 240224, upload-time = "2025-11-30T20:23:02.008Z" },
+ { url = "https://files.pythonhosted.org/packages/24/95/ffd128ed1146a153d928617b0ef673960130be0009c77d8fbf0abe306713/rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1", size = 230645, upload-time = "2025-11-30T20:23:03.43Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/1b/b10de890a0def2a319a2626334a7f0ae388215eb60914dbac8a3bae54435/rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a", size = 364443, upload-time = "2025-11-30T20:23:04.878Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/bf/27e39f5971dc4f305a4fb9c672ca06f290f7c4e261c568f3dea16a410d47/rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e", size = 353375, upload-time = "2025-11-30T20:23:06.342Z" },
+ { url = "https://files.pythonhosted.org/packages/40/58/442ada3bba6e8e6615fc00483135c14a7538d2ffac30e2d933ccf6852232/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000", size = 383850, upload-time = "2025-11-30T20:23:07.825Z" },
+ { url = "https://files.pythonhosted.org/packages/14/14/f59b0127409a33c6ef6f5c1ebd5ad8e32d7861c9c7adfa9a624fc3889f6c/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db", size = 392812, upload-time = "2025-11-30T20:23:09.228Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/66/e0be3e162ac299b3a22527e8913767d869e6cc75c46bd844aa43fb81ab62/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2", size = 517841, upload-time = "2025-11-30T20:23:11.186Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/55/fa3b9cf31d0c963ecf1ba777f7cf4b2a2c976795ac430d24a1f43d25a6ba/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa", size = 408149, upload-time = "2025-11-30T20:23:12.864Z" },
+ { url = "https://files.pythonhosted.org/packages/60/ca/780cf3b1a32b18c0f05c441958d3758f02544f1d613abf9488cd78876378/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083", size = 383843, upload-time = "2025-11-30T20:23:14.638Z" },
+ { url = "https://files.pythonhosted.org/packages/82/86/d5f2e04f2aa6247c613da0c1dd87fcd08fa17107e858193566048a1e2f0a/rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9", size = 396507, upload-time = "2025-11-30T20:23:16.105Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/9a/453255d2f769fe44e07ea9785c8347edaf867f7026872e76c1ad9f7bed92/rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0", size = 414949, upload-time = "2025-11-30T20:23:17.539Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/31/622a86cdc0c45d6df0e9ccb6becdba5074735e7033c20e401a6d9d0e2ca0/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94", size = 565790, upload-time = "2025-11-30T20:23:19.029Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/5d/15bbf0fb4a3f58a3b1c67855ec1efcc4ceaef4e86644665fff03e1b66d8d/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08", size = 590217, upload-time = "2025-11-30T20:23:20.885Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/61/21b8c41f68e60c8cc3b2e25644f0e3681926020f11d06ab0b78e3c6bbff1/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27", size = 555806, upload-time = "2025-11-30T20:23:22.488Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/39/7e067bb06c31de48de3eb200f9fc7c58982a4d3db44b07e73963e10d3be9/rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6", size = 211341, upload-time = "2025-11-30T20:23:24.449Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/4d/222ef0b46443cf4cf46764d9c630f3fe4abaa7245be9417e56e9f52b8f65/rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d", size = 225768, upload-time = "2025-11-30T20:23:25.908Z" },
+ { url = "https://files.pythonhosted.org/packages/86/81/dad16382ebbd3d0e0328776d8fd7ca94220e4fa0798d1dc5e7da48cb3201/rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0", size = 362099, upload-time = "2025-11-30T20:23:27.316Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/60/19f7884db5d5603edf3c6bce35408f45ad3e97e10007df0e17dd57af18f8/rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be", size = 353192, upload-time = "2025-11-30T20:23:29.151Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/c4/76eb0e1e72d1a9c4703c69607cec123c29028bff28ce41588792417098ac/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f", size = 384080, upload-time = "2025-11-30T20:23:30.785Z" },
+ { url = "https://files.pythonhosted.org/packages/72/87/87ea665e92f3298d1b26d78814721dc39ed8d2c74b86e83348d6b48a6f31/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f", size = 394841, upload-time = "2025-11-30T20:23:32.209Z" },
+ { url = "https://files.pythonhosted.org/packages/77/ad/7783a89ca0587c15dcbf139b4a8364a872a25f861bdb88ed99f9b0dec985/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87", size = 516670, upload-time = "2025-11-30T20:23:33.742Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/3c/2882bdac942bd2172f3da574eab16f309ae10a3925644e969536553cb4ee/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18", size = 408005, upload-time = "2025-11-30T20:23:35.253Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/81/9a91c0111ce1758c92516a3e44776920b579d9a7c09b2b06b642d4de3f0f/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad", size = 382112, upload-time = "2025-11-30T20:23:36.842Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/8e/1da49d4a107027e5fbc64daeab96a0706361a2918da10cb41769244b805d/rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07", size = 399049, upload-time = "2025-11-30T20:23:38.343Z" },
+ { url = "https://files.pythonhosted.org/packages/df/5a/7ee239b1aa48a127570ec03becbb29c9d5a9eb092febbd1699d567cae859/rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f", size = 415661, upload-time = "2025-11-30T20:23:40.263Z" },
+ { url = "https://files.pythonhosted.org/packages/70/ea/caa143cf6b772f823bc7929a45da1fa83569ee49b11d18d0ada7f5ee6fd6/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65", size = 565606, upload-time = "2025-11-30T20:23:42.186Z" },
+ { url = "https://files.pythonhosted.org/packages/64/91/ac20ba2d69303f961ad8cf55bf7dbdb4763f627291ba3d0d7d67333cced9/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f", size = 591126, upload-time = "2025-11-30T20:23:44.086Z" },
+ { url = "https://files.pythonhosted.org/packages/21/20/7ff5f3c8b00c8a95f75985128c26ba44503fb35b8e0259d812766ea966c7/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53", size = 553371, upload-time = "2025-11-30T20:23:46.004Z" },
+ { url = "https://files.pythonhosted.org/packages/72/c7/81dadd7b27c8ee391c132a6b192111ca58d866577ce2d9b0ca157552cce0/rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed", size = 215298, upload-time = "2025-11-30T20:23:47.696Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/d2/1aaac33287e8cfb07aab2e6b8ac1deca62f6f65411344f1433c55e6f3eb8/rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950", size = 228604, upload-time = "2025-11-30T20:23:49.501Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/95/ab005315818cc519ad074cb7784dae60d939163108bd2b394e60dc7b5461/rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6", size = 222391, upload-time = "2025-11-30T20:23:50.96Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/68/154fe0194d83b973cdedcdcc88947a2752411165930182ae41d983dcefa6/rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb", size = 364868, upload-time = "2025-11-30T20:23:52.494Z" },
+ { url = "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8", size = 353747, upload-time = "2025-11-30T20:23:54.036Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/00/ba2e50183dbd9abcce9497fa5149c62b4ff3e22d338a30d690f9af970561/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7", size = 383795, upload-time = "2025-11-30T20:23:55.556Z" },
+ { url = "https://files.pythonhosted.org/packages/05/6f/86f0272b84926bcb0e4c972262f54223e8ecc556b3224d281e6598fc9268/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898", size = 393330, upload-time = "2025-11-30T20:23:57.033Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/e9/0e02bb2e6dc63d212641da45df2b0bf29699d01715913e0d0f017ee29438/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e", size = 518194, upload-time = "2025-11-30T20:23:58.637Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/ca/be7bca14cf21513bdf9c0606aba17d1f389ea2b6987035eb4f62bd923f25/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419", size = 408340, upload-time = "2025-11-30T20:24:00.2Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/c7/736e00ebf39ed81d75544c0da6ef7b0998f8201b369acf842f9a90dc8fce/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551", size = 383765, upload-time = "2025-11-30T20:24:01.759Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/3f/da50dfde9956aaf365c4adc9533b100008ed31aea635f2b8d7b627e25b49/rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8", size = 396834, upload-time = "2025-11-30T20:24:03.687Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/00/34bcc2565b6020eab2623349efbdec810676ad571995911f1abdae62a3a0/rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5", size = 415470, upload-time = "2025-11-30T20:24:05.232Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/28/882e72b5b3e6f718d5453bd4d0d9cf8df36fddeb4ddbbab17869d5868616/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404", size = 565630, upload-time = "2025-11-30T20:24:06.878Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/97/04a65539c17692de5b85c6e293520fd01317fd878ea1995f0367d4532fb1/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856", size = 591148, upload-time = "2025-11-30T20:24:08.445Z" },
+ { url = "https://files.pythonhosted.org/packages/85/70/92482ccffb96f5441aab93e26c4d66489eb599efdcf96fad90c14bbfb976/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40", size = 556030, upload-time = "2025-11-30T20:24:10.956Z" },
+ { url = "https://files.pythonhosted.org/packages/20/53/7c7e784abfa500a2b6b583b147ee4bb5a2b3747a9166bab52fec4b5b5e7d/rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0", size = 211570, upload-time = "2025-11-30T20:24:12.735Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/02/fa464cdfbe6b26e0600b62c528b72d8608f5cc49f96b8d6e38c95d60c676/rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3", size = 226532, upload-time = "2025-11-30T20:24:14.634Z" },
+]
+
+[[package]]
+name = "rsa"
+version = "4.9.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyasn1" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" },
+]
+
+[[package]]
+name = "ruff"
+version = "0.15.14"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/dc/8a/8bce2894573e9dae6ff4d77fe34ad727d79b9e6238ad288c5638990d90f6/ruff-0.15.14.tar.gz", hash = "sha256:48e866b165be4a9bdbf310f7d3c9a07edef2fe8cd63ffeb4e00bb590506ebf9f", size = 4700910, upload-time = "2026-05-21T14:34:55.177Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b9/c8/74a92c6ff9fcfb4f1f947126d3ebee8389276e161ecc85de5bda7cda51bd/ruff-0.15.14-py3-none-linux_armv6l.whl", hash = "sha256:8dd2db9416e487c8d4b01fa7056bb02c4d05969d4f8d17a08c229c2f4ff3c108", size = 10739177, upload-time = "2026-05-21T14:34:37.332Z" },
+ { url = "https://files.pythonhosted.org/packages/45/91/254a35c20acc38a7223c9d2d594af12e794432464f2cdeb52af1dc4a892d/ruff-0.15.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:be4ff55af755bd71a00ab3dc6bd7ffc467bd76e0df6881e286c2e3d23e8fb43b", size = 11144969, upload-time = "2026-05-21T14:34:43.978Z" },
+ { url = "https://files.pythonhosted.org/packages/56/9e/d13e40f83b8d0a94430e6778ce1d94a43b38cf2efe63278bdd2b4c65abbf/ruff-0.15.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:48d5909d7d06276ce7dde6d32bfa4b0d4cb2651145cd8ee4b440722cbc77832f", size = 10478207, upload-time = "2026-05-21T14:34:48.378Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/f1/b15a7839fa4f332f8acec78e20564f26bb2d866e3d21710b877fd0263000/ruff-0.15.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca8cbfa94c4f90984a67561978602746d4cd27103568f745fa90eee3f0d4107d", size = 10818459, upload-time = "2026-05-21T14:34:22.318Z" },
+ { url = "https://files.pythonhosted.org/packages/45/33/53d651177f84f94b400a0e27f8824eeada3dddc9d5ee8aeb048f4352a520/ruff-0.15.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a6bbc0333f1ab053423bcbf6226477d266ca7cec7738c4c8e3f55647803f3c4", size = 10541800, upload-time = "2026-05-21T14:34:20.209Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/a6/868f87e0bf9786ed24b5d0d0ad8676b8a94fd1912f42cddf9cfc7857818a/ruff-0.15.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a24a4f7605d7003a6674d4387651effd939dead3fddd0f36561eb77a9a2e542", size = 11342149, upload-time = "2026-05-21T14:34:46.365Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/8b/38cd5c19faffdcc05a408d2b78edccc69492ab9720eadb49ea15ef80d768/ruff-0.15.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:049b5326e53ed80978f2fc041a280603f69dd6b0c95464342a2bb4572d9d9e2f", size = 12212563, upload-time = "2026-05-21T14:34:28.579Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/4d/a3c5b874a556d5731e3e657aaf04311bb76f0a5c3ec220ed43051be6b64b/ruff-0.15.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4ed42e6696c8dfa5f06728e6441993901f548eb92d73bc472cb5a38d1395fbf", size = 11493299, upload-time = "2026-05-21T14:34:41.836Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/c0/56472c251d09858a53e51efbd485b09e1995d8731668b76d52e5dd6ee0f1/ruff-0.15.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:715c543cf450c4888251f91c52f1942a800541d9bddd7ac060aa4e6b77ae7cba", size = 11455931, upload-time = "2026-05-21T14:34:57.276Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/4a/e2e7b4d8dbf233d4eace59c75bc3435fa6d8bd3bae82d351d4e4300c0fd1/ruff-0.15.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ebab6013ec887d439d8b7593737a0a4ffb06d45d209d4e4bf2e92813082d3f", size = 11400794, upload-time = "2026-05-21T14:34:39.773Z" },
+ { url = "https://files.pythonhosted.org/packages/97/c7/83c0539fe34c3e09136204d1e75d6052492364e0b3cb05e9465423f567d7/ruff-0.15.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:49072d36abdbe97a8dd7f480afe9c675699c0c495d4c84076e2c1203c4550581", size = 10804759, upload-time = "2026-05-21T14:34:31.045Z" },
+ { url = "https://files.pythonhosted.org/packages/86/a6/18f2bfc095a2ab4a78745644e428205532ce6653a5d0fa8501572891534d/ruff-0.15.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:958522aee105068640c2c2ceae08f413ae44d922f52a1374ac13d6a96032fc93", size = 10539517, upload-time = "2026-05-21T14:34:53.064Z" },
+ { url = "https://files.pythonhosted.org/packages/54/3a/5a8b3b69c654d4e4bf1d246ac5b49cbcdac6eaab6905925f8915f31e3b80/ruff-0.15.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f3707da619a143a2e8830e2abab8224478d69ace2d28cb6c20543ae97c36bf61", size = 11065169, upload-time = "2026-05-21T14:34:24.484Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/c5/8864e4e7925b836ea354b31d57641ec03830564e281a8b6f061f8c3e0ec1/ruff-0.15.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:bb01d645694e3ec0102105d07ef2d53703970407d59c04e59d3ba0b7a1d53553", size = 11560214, upload-time = "2026-05-21T14:34:50.975Z" },
+ { url = "https://files.pythonhosted.org/packages/36/38/012bf76752e1f89ed50b77b99532d90f3a3e287bc7918e1fc0948ac866ac/ruff-0.15.14-py3-none-win32.whl", hash = "sha256:6d0c1ad2a0ab718d39b6d8fd2217981ce4d625cd96a720095f798fb47d8b13e6", size = 10805548, upload-time = "2026-05-21T14:34:33.453Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/b7/4ea2c170f10ad760fff2a5250beb18897719dc8b52b53a24cddbb9dd3f19/ruff-0.15.14-py3-none-win_amd64.whl", hash = "sha256:802342981e056db3851a7836e5b070f8f15f67d4a685ae2a6160939d364b2902", size = 11939523, upload-time = "2026-05-21T14:34:18.077Z" },
+ { url = "https://files.pythonhosted.org/packages/62/d5/bc97ff895ec35cf3925d4bd60f3b39d822f377a446906ec9bcc87405e59b/ruff-0.15.14-py3-none-win_arm64.whl", hash = "sha256:ff47b90a9ef6a40c9e2f3b479c1fb78531adf055b94c1eba0a7ba04b31951826", size = 11208607, upload-time = "2026-05-21T14:34:26.525Z" },
+]
+
+[[package]]
+name = "s3transfer"
+version = "0.17.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "botocore" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/11/b3/bcdc2f58fa92592db511beda154c2c08d28f21f6c4637f06a42a24b10c21/s3transfer-0.17.1.tar.gz", hash = "sha256:042dd5e3b1b512355e35a23f0223e426b7042e80b97830ea2680ddce327fc45e", size = 159439, upload-time = "2026-05-26T19:45:01.714Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/85/dd/904873250a6554fbae40cddbf9198e3cc37a2f1319d5e1a5ce82fe269c17/s3transfer-0.17.1-py3-none-any.whl", hash = "sha256:5b9827d1044159bbb01b86ef8902760ea39281927f5de31de75e1d657177bf4c", size = 88264, upload-time = "2026-05-26T19:45:00.452Z" },
+]
+
+[[package]]
+name = "shellingham"
+version = "1.5.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
+]
+
+[[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 = "sqlalchemy"
+version = "2.0.50"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/57/da/6fbf010c8ebb347679d0d100b22fe9ba5e13fd04046c5df7280d2f0bf706/sqlalchemy-2.0.50.tar.gz", hash = "sha256:af5607d11ef90fd6a5c0549fe0045dce1663d427426bcfb506dcb5346a85a3b9", size = 9907424, upload-time = "2026-05-24T19:20:04.018Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/be/b0/a9d19b43f38f878b1278bca5b00b909f7540d41494396dd2561f9ad0956d/sqlalchemy-2.0.50-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23ae23d8b9d344d30d0a92f06d45825024a5790f1c1dd4cf452636a50d3e58cb", size = 2159807, upload-time = "2026-05-24T19:27:53.086Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/2c/191dd58a248fd2cfd4780fa82c375c505e4ad98c8b522fa69ec492130d77/sqlalchemy-2.0.50-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47b71b933e7b4ebad407c8fdfd70d2c4f08b78b3238bb30eebdd6eb32ca51b89", size = 3343358, upload-time = "2026-05-24T20:09:29.279Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/2b/514fce8a7df81cf5bad7ff7865de7ac0c5776a38cc043475c4703eb7fe8b/sqlalchemy-2.0.50-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:110fdac56ace278949f00de805edacbd6141e382d992f9ba28238b3a0827a600", size = 3357994, upload-time = "2026-05-24T20:17:13.495Z" },
+ { url = "https://files.pythonhosted.org/packages/35/a6/a0e283f5494f92b0d77e319ff77e437b1ffe4a051ba67c81d53234825475/sqlalchemy-2.0.50-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0f5e4ac70e9e757f6b3e87c0491ff034442ecd8dfd36d041a50564c322dafc0e", size = 3289399, upload-time = "2026-05-24T20:09:32.239Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/96/1b07325ba71752d6a028b77d07bed1483ad545f794e8b1dc89b3ba3b3c68/sqlalchemy-2.0.50-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:724f3dcbe53dd0151e3cb5e7ec4ba4c620bede579caacd16275dc35ce06e8615", size = 3321216, upload-time = "2026-05-24T20:17:15.581Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/8e/bad6ed253e8a99edfc99af02f7173ec48a1d3ed1b9b35a1b8bc1700900cc/sqlalchemy-2.0.50-cp312-cp312-win32.whl", hash = "sha256:1208050441471d003b7c8cb4054fb084f185cf35ac3f0ea270803865bca9939a", size = 2119194, upload-time = "2026-05-24T19:50:04.943Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/2d/314a6690dda4b9cfc571eab1a63cf6fe6e1470aa3759ccda6aa016ee0f5a/sqlalchemy-2.0.50-cp312-cp312-win_amd64.whl", hash = "sha256:9d1af51558029a156a70986b7df88f042b3d158d7c8d8fb5072912d4b32d89c7", size = 2146186, upload-time = "2026-05-24T19:50:06.74Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/c4/c42356b527296e9862f67990efce31ef78b4cf69cd3f80873a528a060320/sqlalchemy-2.0.50-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:06a9210bdc5f4298cff0781087e2ff45683922252dacc452846373a58761f093", size = 2156697, upload-time = "2026-05-24T19:27:54.764Z" },
+ { url = "https://files.pythonhosted.org/packages/60/a1/b1a70e3c4365ac7fe9e347f3710f19b562c866fb96d45e3c891588789a7b/sqlalchemy-2.0.50-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b53784972ade4f8174b9aa661f31a06f8a936d2cfdd602913ff3c6dd40ae873", size = 3284260, upload-time = "2026-05-24T20:09:34.195Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/4a/f3ac3caa19f263d57b0a47f8c91bbf56583dc2d3fc63acfbf644abb24fe0/sqlalchemy-2.0.50-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31648fa14460537e768a7303b078e4344d208e0d23e06867c1f376a227ed82db", size = 3302280, upload-time = "2026-05-24T20:17:17.825Z" },
+ { url = "https://files.pythonhosted.org/packages/66/55/ccada3e3d62254587819749a0bc69f41173eb48a6e385d10e66d32a9c88e/sqlalchemy-2.0.50-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:03f4323c980ad0e918cc9e5369b015f759f4e534db5bbaf4dc36832c10d05064", size = 3231580, upload-time = "2026-05-24T20:09:36.406Z" },
+ { url = "https://files.pythonhosted.org/packages/05/f6/6809349130a2de0e109e7f00fd7d431da9565b9b2868b32ee684754f672b/sqlalchemy-2.0.50-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2b9dcc43afef8ac157cd92fce96985d6b8b0cfbd3df4d666f66b4d55a75d202f", size = 3269375, upload-time = "2026-05-24T20:17:20.34Z" },
+ { url = "https://files.pythonhosted.org/packages/48/84/278a811ef4e07be9c89dc5cdd7be833268509a66a68c4897cf585e67428f/sqlalchemy-2.0.50-cp313-cp313-win32.whl", hash = "sha256:60922d6599065ddca2c6f376b9aa2f41a6b85a271725e0909490bbc50b1998a5", size = 2117229, upload-time = "2026-05-24T19:50:08.215Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/1c/067cc6187ed32d2ec222fe6d2643acc1659a6d0659f8a7cbc5ad3ae83280/sqlalchemy-2.0.50-cp313-cp313-win_amd64.whl", hash = "sha256:287086e67275a212c4582d166a6fb03a65ccc5551d80866270ce0dd9f34eccd3", size = 2143126, upload-time = "2026-05-24T19:50:09.691Z" },
+ { url = "https://files.pythonhosted.org/packages/df/32/10ac51b4be7cdecd7e93d069251c86dfbf70b7adbd7c67b48ccea6c49e1c/sqlalchemy-2.0.50-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c966932507a4d7d0a37314927dbfcd89720e3f37d2a1e3352e7ae7939fa8e8a0", size = 2158519, upload-time = "2026-05-24T19:27:56.472Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/76/e703d2f7681d7d66c4c891af3f07c7ccf4c76ad7f18351de035b5eda007a/sqlalchemy-2.0.50-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:faffef4bcc20a1892e65e155293d99d60855bbbc79250ab712819cfd56a8e6bb", size = 3282063, upload-time = "2026-05-24T20:09:38.57Z" },
+ { url = "https://files.pythonhosted.org/packages/31/26/ef168b184a25701f9995e8fb7e503fafd7a99c1c77cda1bc1a26ea2ed486/sqlalchemy-2.0.50-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c206aec519a2e7bd08abbfb33436e325fd22c632d9c21a9047e376ce241646e", size = 3287069, upload-time = "2026-05-24T20:17:21.942Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/15/765acc2bc693bccc43ca4a95d5b69750da8aaf6db1b5c616536e087f8920/sqlalchemy-2.0.50-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bef4ac756363227ef6402a75fee025a4bc690f92328e825868939b3b3a446a6d", size = 3230453, upload-time = "2026-05-24T20:09:40.398Z" },
+ { url = "https://files.pythonhosted.org/packages/63/61/08e03c3adbf5db0087a0b6816746fec8f3032fb2f7fc899a9bb9b2a48ce4/sqlalchemy-2.0.50-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:96fbee6b19c19cd1556c8bf9419447cf2ec149ffcab7ab64348c23e54ef8547f", size = 3252413, upload-time = "2026-05-24T20:17:24.067Z" },
+ { url = "https://files.pythonhosted.org/packages/03/0c/370a1f2db38436c615e10134c8a37de3688e74084792380695f3f5083860/sqlalchemy-2.0.50-cp314-cp314-win32.whl", hash = "sha256:8f00e3eb43ba30eb1b238ee03a8a62309486d1321eda3328bb611e0340033ad8", size = 2120063, upload-time = "2026-05-24T19:50:11.08Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/a0/fe92bb9817863bc13ba093bda931979a26cc2ca69f8e8f26d07add3d7c6f/sqlalchemy-2.0.50-cp314-cp314-win_amd64.whl", hash = "sha256:15708c613cd5005b7dffe1f66ee6a63ee8f5e46799f71c70ebad74178c676a39", size = 2145830, upload-time = "2026-05-24T19:50:12.452Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/ff/e5640a98a0b2f491eb8fde10fb6c773621a2e44340de231fafcc9370f4a9/sqlalchemy-2.0.50-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3699dac4be410e97049a1658e9480da9cde956594aa0f3aebc60b88f21c5ba70", size = 2178435, upload-time = "2026-05-24T19:42:58.889Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/85/337116e186f1236375b5fb70c21cfac98e8e8ab0d3a47be838dc47a59e08/sqlalchemy-2.0.50-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f96233858e3df43932ac11589e22520da6e8aeb624b03fedfeebb0e8ea213086", size = 3566059, upload-time = "2026-05-24T20:01:20.848Z" },
+ { url = "https://files.pythonhosted.org/packages/96/34/bb0e190e161c3c2c24314a65add57218be14a4a9486886b7f5047c1ff7c8/sqlalchemy-2.0.50-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c4e70c46fad30c3bcc6a4708bc0130a3173e11a5b25f0ea4a9d8911b450f1f52", size = 3535366, upload-time = "2026-05-24T20:03:56.768Z" },
+ { url = "https://files.pythonhosted.org/packages/df/5a/a7f759f97e4fd499c5d4e4488c760d5a7fbecf3028b465a04274fcd52384/sqlalchemy-2.0.50-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1918a3cf564d16d95bca7301005f41ab2ad50b07cd3b9da50d3ed986db148d6a", size = 3474879, upload-time = "2026-05-24T20:01:23.058Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/d9/2907ea38eb60687d297bf9c39e5ee58053c87b57fe8a9cae97090cecbf10/sqlalchemy-2.0.50-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b00098cdbdbd38c7be3d568b0c9c3122b8c0ec62b911b57cd5e6e0254d60a76d", size = 3486117, upload-time = "2026-05-24T20:03:59.052Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/e3/5aa06f167559f8c0bdae487e297d23ba548150ab016a3418265d617a4985/sqlalchemy-2.0.50-cp314-cp314t-win32.whl", hash = "sha256:1fbd55a969d7ac44a98e3dec75016074f809fa08f871585ace58dde110d1bf3e", size = 2150823, upload-time = "2026-05-24T20:08:58.644Z" },
+ { url = "https://files.pythonhosted.org/packages/65/9b/112fb8f977582d7489d036e409e3723948bcf5320b3ac465f3c481bbe8f9/sqlalchemy-2.0.50-cp314-cp314t-win_amd64.whl", hash = "sha256:c5c3cdb753a9004183e1ccb634b41611654c989e61bc68617ce878e46d6f1e51", size = 2185794, upload-time = "2026-05-24T20:09:00.319Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/10/f7220e9b784d295d241c86ed99aeb537f92afcd469a64861f2717e9bb077/sqlalchemy-2.0.50-py3-none-any.whl", hash = "sha256:92064363517a3ff8212b5a93b8c62876579d8dfd1ca5b561335f30152d884fa9", size = 1943861, upload-time = "2026-05-24T19:59:01.119Z" },
+]
+
+[[package]]
+name = "stack-data"
+version = "0.6.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "asttokens" },
+ { name = "executing" },
+ { name = "pure-eval" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" },
+]
+
+[[package]]
+name = "starlette"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/95/66/4d20cdf39a8d6a51e663b7038e3b828ff211d3891a43a713fe7e4643f3a8/starlette-1.1.0.tar.gz", hash = "sha256:e83c7fe0ddecd8719c5b840080325aec0260acec86e9832899e377b91d65e90f", size = 2660060, upload-time = "2026-05-23T16:55:41.376Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/93/79/920b8e0a8b20f793e8d64855095cb8febabf6175b8550b6f7a547d813891/starlette-1.1.0-py3-none-any.whl", hash = "sha256:7f0dfd38e428aad5cb6f9f667f0ca1d2d8ca3f3385dccac8305f79ec98458382", size = 72899, upload-time = "2026-05-23T16:55:39.201Z" },
+]
+
+[[package]]
+name = "stevedore"
+version = "5.8.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e9/88/35e4d27d9177d7df76d060e0a18f69c6c5794c96960c94042e20a12c8ba2/stevedore-5.8.0.tar.gz", hash = "sha256:b49867b32ca3016e94100e68dbf26e72aa7b8708d0a3f73c08aeb220370ac715", size = 514710, upload-time = "2026-05-18T09:15:27.731Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f5/ac/19f9941c74add59d17694930ec8105d5eddeee4ce56dd8632b765ca16d6c/stevedore-5.8.0-py3-none-any.whl", hash = "sha256:88eede9e66ca80e34085b9174e2327da2c61ac91f24f70e41c3ad76e4bb4872b", size = 54553, upload-time = "2026-05-18T09:15:25.82Z" },
+]
+
+[[package]]
+name = "text-unidecode"
+version = "1.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ab/e2/e9a00f0ccb71718418230718b3d900e71a5d16e701a3dae079a21e9cd8f8/text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93", size = 76885, upload-time = "2019-08-30T21:36:45.405Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", size = 78154, upload-time = "2019-08-30T21:37:03.543Z" },
+]
+
+[[package]]
+name = "tqdm"
+version = "4.67.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" },
+]
+
+[[package]]
+name = "traitlets"
+version = "5.15.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1b/22/40f55b26baeab80c2d7b3f1db0682f8954e4617fee7d90ce634022ef05c6/traitlets-5.15.0.tar.gz", hash = "sha256:4fead733f81cf1c4c938e06f8ca4633896833c9d89eff878159457f4d4392971", size = 163197, upload-time = "2026-05-06T08:05:58.016Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/da/98/a9937a969d018a23badfea0b381f66783649d48e0ea6c41923265c3cbeb3/traitlets-5.15.0-py3-none-any.whl", hash = "sha256:fb36a18867a6803deab09f3c5e0fa81bb7b26a5c9e82501c9933f759166eff40", size = 85877, upload-time = "2026-05-06T08:05:55.853Z" },
+]
+
+[[package]]
+name = "typer"
+version = "0.21.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-doc" },
+ { name = "click" },
+ { name = "rich" },
+ { name = "shellingham" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f2/1e/a27cc02a0cd715118c71fa2aef2c687fdefc3c28d90fd0dd789c5118154c/typer-0.21.2.tar.gz", hash = "sha256:1abd95a3b675e17ff61b0838ac637fe9478d446d62ad17fa4bb81ea57cc54028", size = 120426, upload-time = "2026-02-10T19:33:46.182Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b8/cc/d59f893fbdfb5f58770c05febfc4086a46875f1084453621c35605cec946/typer-0.21.2-py3-none-any.whl", hash = "sha256:c3d8de54d00347ef90b82131ca946274f017cffb46683ae3883c360fa958f55c", size = 56728, upload-time = "2026-02-10T19:33:48.01Z" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.15.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
+]
+
+[[package]]
+name = "typing-inspection"
+version = "0.4.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
+]
+
+[[package]]
+name = "tzdata"
+version = "2026.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" },
+]
+
+[[package]]
+name = "urllib3"
+version = "2.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
+]
+
+[[package]]
+name = "uuid6"
+version = "2025.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ca/b7/4c0f736ca824b3a25b15e8213d1bcfc15f8ac2ae48d1b445b310892dc4da/uuid6-2025.0.1.tar.gz", hash = "sha256:cd0af94fa428675a44e32c5319ec5a3485225ba2179eefcf4c3f205ae30a81bd", size = 13932, upload-time = "2025-07-04T18:30:35.186Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3d/b2/93faaab7962e2aa8d6e174afb6f76be2ca0ce89fde14d3af835acebcaa59/uuid6-2025.0.1-py3-none-any.whl", hash = "sha256:80530ce4d02a93cdf82e7122ca0da3ebbbc269790ec1cb902481fa3e9cc9ff99", size = 6979, upload-time = "2025-07-04T18:30:34.001Z" },
+]
+
+[[package]]
+name = "uvicorn"
+version = "0.48.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "click" },
+ { name = "h11" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e6/bf/f6544ba992ddb9a6077343a576f9844f7f8f06ab819aefd00206e9255f18/uvicorn-0.48.0.tar.gz", hash = "sha256:a5504207195d08c2511bf9125ede5ac4a4b71725d519e758d01dcf0bc2d31c37", size = 91074, upload-time = "2026-05-24T12:08:41.925Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/01/be/72532be3da7acc5fdfbccdb95215cd04f995a0886532a5b423f929cda4cc/uvicorn-0.48.0-py3-none-any.whl", hash = "sha256:48097851328b87ec36117d3d575234519eb58c2b22d79666e9bbc6c49a761dad", size = 71410, upload-time = "2026-05-24T12:08:40.258Z" },
+]
+
+[[package]]
+name = "virtualenv"
+version = "21.3.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "distlib" },
+ { name = "filelock" },
+ { name = "platformdirs" },
+ { name = "python-discovery" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/15/ba/1f6e8c957e4932be060dcdc482d339c12e0216351478add3645cdaa53c05/virtualenv-21.3.3.tar.gz", hash = "sha256:f5bda277e553b1c2b3c1a8debfc30496e1288cc93ce6b7b71b3280047e317328", size = 7613784, upload-time = "2026-05-13T18:01:30.19Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f4/34/a9dbe051de88a63eb7408ea66630bac38e72f7f6077d4be58737106860d9/virtualenv-21.3.3-py3-none-any.whl", hash = "sha256:7d5987d8369e098e41406efb780a3d4ca79280097293899e351a6407ee153ab3", size = 7594554, upload-time = "2026-05-13T18:01:27.815Z" },
+]
+
+[[package]]
+name = "wcwidth"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/2c/ee/afaf0f85a9a18fe47a67f1e4422ed6cf1fe642f0ae0a2f81166231303c52/wcwidth-0.7.0.tar.gz", hash = "sha256:90e3a7ea092341c44b99562e75d09e4d5160fe7a3974c6fb842a101a95e7eed0", size = 182132, upload-time = "2026-05-02T16:04:12.653Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/41/52/e465037f5375f43533d1a80b6923955201596a99142ed524d77b571a1418/wcwidth-0.7.0-py3-none-any.whl", hash = "sha256:5d69154c429a82910e241c738cd0e2976fac8a2dd47a1a805f4afed1c0f136f2", size = 110825, upload-time = "2026-05-02T16:04:11.033Z" },
+]
+
+[[package]]
+name = "werkzeug"
+version = "3.1.8"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markupsafe" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/dd/b2/381be8cfdee792dd117872481b6e378f85c957dd7c5bca38897b08f765fd/werkzeug-3.1.8.tar.gz", hash = "sha256:9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44", size = 875852, upload-time = "2026-04-02T18:49:14.268Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl", hash = "sha256:63a77fb8892bf28ebc3178683445222aa500e48ebad5ec77b0ad80f8726b1f50", size = 226459, upload-time = "2026-04-02T18:49:12.72Z" },
+]
+
+[[package]]
+name = "xmltodict"
+version = "1.0.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/19/70/80f3b7c10d2630aa66414bf23d210386700aa390547278c789afa994fd7e/xmltodict-1.0.4.tar.gz", hash = "sha256:6d94c9f834dd9e44514162799d344d815a3a4faec913717a9ecbfa5be1bb8e61", size = 26124, upload-time = "2026-02-22T02:21:22.074Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/38/34/98a2f52245f4d47be93b580dae5f9861ef58977d73a79eb47c58f1ad1f3a/xmltodict-1.0.4-py3-none-any.whl", hash = "sha256:a4a00d300b0e1c59fc2bfccb53d7b2e88c32f200df138a0dd2229f842497026a", size = 13580, upload-time = "2026-02-22T02:21:21.039Z" },
+]
+
+[[package]]
+name = "yaml-config-day"
+version = "0.0.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyyaml" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/ece7b06909afbd673cf2d77a354528174126c22b6f0b57038dc6cf03900d/yaml_config_day-0.0.5.tar.gz", hash = "sha256:88cd1d3aa668c8c2362f2cb36a2ca97cab36c78edc6c673001e0db41235ccf4b", size = 4563, upload-time = "2023-10-07T22:11:56.814Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/97/5d/c46e00911b71c1a03a3bbef719b081d962e97b0169dd70056c330461cbd9/yaml_config_day-0.0.5-py3-none-any.whl", hash = "sha256:b8aca2c420b9979056257e9ff78b08499d7435cba64baec64b63c806f4fc8ddf", size = 3962, upload-time = "2023-10-07T22:11:54.351Z" },
+]
From c343d03f992631d463958da9b567416998a0172a Mon Sep 17 00:00:00 2001
From: John Major
Date: Thu, 28 May 2026 10:25:53 -0700
Subject: [PATCH 02/47] Formalize inf6 deployment readiness
---
AGENTS.md | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/AGENTS.md b/AGENTS.md
index 893ead6..b491752 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -1,3 +1,10 @@
+# Shell Session Defaults
+
+- Default to an interactive shell for shell work. On this Mac, use the user's default shell unless the user explicitly asks for another shell.
+- For AWS EC2, ParallelCluster, and other remote Linux hosts, default to an interactive `bash` login shell as `ubuntu`. Do not use `root` unless the user explicitly grants permission for that specific work; use targeted `sudo` from `ubuntu` when escalation is required.
+- For Daylily/DayOA/DAY-EC headnode workflow work, use an interactive `ubuntu` tmux/login-shell pane for controllers and workflow commands. Run setup as separate commands in that pane (`source dyoainit`, then `dy-a ...`, then `dy-r ...`) so aliases/functions are defined before use.
+- SSM Run Command is for simple inspection or for writing helper scripts through the supported helpers. Do not launch workflow controllers or rely on `dy-*` aliases from non-interactive SSM scripts.
+
# Bloom CLI Policy
## Session Setup
@@ -57,6 +64,16 @@ source ./activate
- Service-host certs use DNS-01 renewal; do not depend on HTTP-01 public reachability for Bloom service hosts.
- Future dev, test, and stage deployments must use their own approved-source lists, credentials, certificates, TapDB schemas, and tenant data, separate from production.
+## Version Tags
+
+- Use non-v semver tags for package releases, e.g. `2.0.19` or `5.0.21`, not `v2.0.19`.
+- Commit first, then tag the exact clean release commit.
+- Use annotated tags for release provenance: `git tag -a 2.0.19 -m "Release 2.0.19"`.
+- Lightweight tags are acceptable only for scratch/internal marks, not package releases.
+- Do not move or overwrite pushed version tags. If a pushed tag is wrong, cut the next patch version.
+- If signing is configured and expected, use signed annotated tags: `git tag -s 2.0.19 -m "Release 2.0.19"`.
+- Verify tag type with `git cat-file -t 2.0.18`; `tag` means annotated and `commit` means lightweight.
+
## Bloom Examples
- Start with `source ./activate `
From 901d340d2b8d352e395261613551565ec284a697 Mon Sep 17 00:00:00 2001
From: John Major
Date: Thu, 28 May 2026 14:14:57 -0700
Subject: [PATCH 03/47] Package Bloom TapDB templates in container image
---
Dockerfile | 1 +
tests/test_packaging_metadata.py | 10 +++++++++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/Dockerfile b/Dockerfile
index 046d925..875e66f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -17,6 +17,7 @@ RUN apt-get update \
COPY pyproject.toml uv.lock README.md ./
RUN uv sync --frozen --no-dev --no-install-project
+COPY config ./config
COPY bloom_lims ./bloom_lims
COPY main.py ./main.py
RUN uv sync --frozen --no-dev
diff --git a/tests/test_packaging_metadata.py b/tests/test_packaging_metadata.py
index ec4b740..0cf2482 100644
--- a/tests/test_packaging_metadata.py
+++ b/tests/test_packaging_metadata.py
@@ -15,9 +15,17 @@ def test_project_dependencies_pin_release_train_versions() -> None:
assert "cli-core-yo==2.1.1" in dependencies
assert "daylily-auth-cognito==2.1.5" in dependencies
- assert "daylily-tapdb>=7.0.3,<8.0.0" in dependencies
+ assert "daylily-tapdb>=7.0.5,<8.0.0" in dependencies
assert "IPython>=8.18.1" in dependencies
assert "psycopg2==2.9.9" in dependencies
assert not any(str(dep).startswith("zebra-day") for dep in dependencies)
assert "djlint" in dependencies
assert "optional-dependencies" not in data["project"]
+
+
+def test_dockerfile_copies_tapdb_template_config() -> None:
+ dockerfile = (Path(__file__).resolve().parents[1] / "Dockerfile").read_text(
+ encoding="utf-8"
+ )
+
+ assert "COPY config ./config" in dockerfile
From c7040467dd939f9d78fe16726b334b59d2abc2f4 Mon Sep 17 00:00:00 2001
From: John Major
Date: Thu, 28 May 2026 14:46:02 -0700
Subject: [PATCH 04/47] Initialize Bloom container runtime context
---
bloom_lims/container_entry.py | 29 +++++++++++++++++-
tests/test_container_entry_runtime.py | 42 +++++++++++++++++++++++++++
2 files changed, 70 insertions(+), 1 deletion(-)
create mode 100644 tests/test_container_entry_runtime.py
diff --git a/bloom_lims/container_entry.py b/bloom_lims/container_entry.py
index 4011afc..657ff4b 100644
--- a/bloom_lims/container_entry.py
+++ b/bloom_lims/container_entry.py
@@ -5,6 +5,7 @@
import os
from pathlib import Path
+
def _required_env(name: str) -> str:
value = os.environ.get(name, "").strip()
if not value:
@@ -27,8 +28,34 @@ def _start_server(**kwargs: object) -> None:
start(**kwargs)
+def _initialize_runtime_context(config_path: Path) -> None:
+ from cli_core_yo.errors import ContextNotInitializedError
+ from cli_core_yo.runtime import get_context, initialize
+ from cli_core_yo.xdg import resolve_paths
+
+ from bloom_lims.cli import spec
+
+ try:
+ get_context()
+ return
+ except ContextNotInitializedError:
+ pass
+
+ initialize(
+ spec,
+ resolve_paths(spec.xdg),
+ config_path=config_path,
+ invocation={"entrypoint": "container"},
+ backend_name="container",
+ backend_kind="container",
+ runtime_guard_mode="off",
+ runtime_check_skipped=True,
+ )
+
+
def main() -> None:
- _required_absolute_file("BLOOM_CONFIG_PATH")
+ config_path = _required_absolute_file("BLOOM_CONFIG_PATH")
+ _initialize_runtime_context(config_path)
_start_server(
port=int(_required_env("PORT")),
host=_required_env("HOST"),
diff --git a/tests/test_container_entry_runtime.py b/tests/test_container_entry_runtime.py
new file mode 100644
index 0000000..00656b1
--- /dev/null
+++ b/tests/test_container_entry_runtime.py
@@ -0,0 +1,42 @@
+from __future__ import annotations
+
+from cli_core_yo import runtime as cli_runtime
+
+
+def test_container_entry_initializes_cli_runtime(monkeypatch, tmp_path):
+ import bloom_lims.container_entry as entry
+
+ config_path = tmp_path / "bloom.yaml"
+ config_path.write_text("application: {}\n", encoding="utf-8")
+ monkeypatch.setenv("BLOOM_CONFIG_PATH", str(config_path))
+ monkeypatch.setenv("PORT", "8912")
+ monkeypatch.setenv("HOST", "0.0.0.0")
+ monkeypatch.setenv("DEPLOYMENT_CODE", "inf9")
+ monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path / "xdg" / "config"))
+ monkeypatch.setenv("XDG_STATE_HOME", str(tmp_path / "xdg" / "state"))
+ monkeypatch.setenv("XDG_DATA_HOME", str(tmp_path / "xdg" / "data"))
+ monkeypatch.setenv("XDG_CACHE_HOME", str(tmp_path / "xdg" / "cache"))
+
+ observed: dict[str, object] = {}
+
+ def fake_start(**kwargs: object) -> None:
+ observed["kwargs"] = kwargs
+ observed["config_path"] = cli_runtime.get_context().config_path
+
+ monkeypatch.setattr(entry, "_start_server", fake_start)
+ cli_runtime._reset()
+ try:
+ entry.main()
+ finally:
+ cli_runtime._reset()
+
+ assert observed["config_path"] == config_path
+ assert observed["kwargs"] == {
+ "port": 8912,
+ "host": "0.0.0.0",
+ "reload": False,
+ "background": False,
+ "ssl": False,
+ "cert": None,
+ "key": None,
+ }
From fcac343eb5eac33e910e2d20bc70a41c16d65674 Mon Sep 17 00:00:00 2001
From: John Major
Date: Thu, 28 May 2026 15:09:04 -0700
Subject: [PATCH 05/47] Copy Bloom UI assets into container image
---
Dockerfile | 2 ++
tests/test_packaging_metadata.py | 2 ++
2 files changed, 4 insertions(+)
diff --git a/Dockerfile b/Dockerfile
index 875e66f..1aec54f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -20,6 +20,8 @@ RUN uv sync --frozen --no-dev --no-install-project
COPY config ./config
COPY bloom_lims ./bloom_lims
COPY main.py ./main.py
+COPY static ./static
+COPY templates ./templates
RUN uv sync --frozen --no-dev
FROM python:${PYTHON_VERSION}-slim-bookworm AS runtime
diff --git a/tests/test_packaging_metadata.py b/tests/test_packaging_metadata.py
index 0cf2482..6213dd8 100644
--- a/tests/test_packaging_metadata.py
+++ b/tests/test_packaging_metadata.py
@@ -29,3 +29,5 @@ def test_dockerfile_copies_tapdb_template_config() -> None:
)
assert "COPY config ./config" in dockerfile
+ assert "COPY static ./static" in dockerfile
+ assert "COPY templates ./templates" in dockerfile
From e7caca9b9e41e9e49f19d3732553a3659a839e1e Mon Sep 17 00:00:00 2001
From: John Major
Date: Fri, 29 May 2026 14:48:01 -0700
Subject: [PATCH 06/47] Standardize Bloom GUI auth entrypoints
---
AGENTS.md | 6 ++++++
Dockerfile | 1 +
bloom_lims/app.py | 11 +++--------
bloom_lims/gui/routes/auth.py | 4 ++--
bloom_lims/integrations/tapdb_mount.py | 10 +++++++++-
pyproject.toml | 2 +-
tests/test_deploy_contract.py | 8 ++++++++
tests/test_route_coverage_gaps_gui.py | 5 +----
tests/test_route_inventory_guard.py | 4 ++++
tests/test_tapdb_mount.py | 2 +-
10 files changed, 36 insertions(+), 17 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
index b491752..74472f0 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -81,3 +81,9 @@ source ./activate
- Use `bloom db seed`
- Use `bloom server start --port 8912`
- Use `tapdb ...` and `daycog ...` only where Bloom docs or Bloom CLI explicitly delegate to them
+# DEPLOYED SERVICE GUI AUTH EVIDENCE
+
+- For deployed service acceptance, API health checks and HTTP `302` redirects are not sufficient. Also use Playwright or the bundled Playwright CLI workflow to open each deployed GUI login page, snapshot the page, click through to the Google OAuth option, and capture screenshots.
+- Store screenshots and records under `output/playwright/` or the deployment ledger evidence directory. Record service name, deploy name, URL, timestamp, screenshot paths, and status as `confirmed_success` or `confirmed_fail`.
+- If the Google OAuth click reaches an expected external blocker, such as `redirect_uri_mismatch`, record the exact callback URI and mark the row blocked instead of treating the service as healthy.
+- Debug and fix failures that are in repository/deployment scope. If the failure requires external configuration or human credentials, annotate the reason precisely. Do not enter real user credentials unless the user explicitly authorizes that in the current turn.
diff --git a/Dockerfile b/Dockerfile
index 1aec54f..bda0787 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -18,6 +18,7 @@ COPY pyproject.toml uv.lock README.md ./
RUN uv sync --frozen --no-dev --no-install-project
COPY config ./config
+COPY auth ./auth
COPY bloom_lims ./bloom_lims
COPY main.py ./main.py
COPY static ./static
diff --git a/bloom_lims/app.py b/bloom_lims/app.py
index d7eb2f0..5fb5d86 100644
--- a/bloom_lims/app.py
+++ b/bloom_lims/app.py
@@ -193,14 +193,9 @@ async def _enforce_origin_allowlist(request, call_next):
app.include_router(probe_router)
app.include_router(observability_router)
app.include_router(api_v1_router)
- try:
- from bloom_lims.gui.router import router as gui_router
- except ModuleNotFoundError as exc:
- logging.warning(
- "Skipping GUI router due to missing optional dependency: %s", exc.name
- )
- else:
- app.include_router(gui_router)
+ from bloom_lims.gui.router import router as gui_router
+
+ app.include_router(gui_router)
register_exception_handlers(app)
return app
diff --git a/bloom_lims/gui/routes/auth.py b/bloom_lims/gui/routes/auth.py
index a93a3ea..2c9165a 100644
--- a/bloom_lims/gui/routes/auth.py
+++ b/bloom_lims/gui/routes/auth.py
@@ -788,5 +788,5 @@ async def auth_logout_post(request: Request, response: Response):
@router.get("/logout")
-async def logout(request: Request, response: Response):
- return await _logout_response(request, response)
+async def logout():
+ return RedirectResponse(url="/auth/logout", status_code=status.HTTP_303_SEE_OTHER)
diff --git a/bloom_lims/integrations/tapdb_mount.py b/bloom_lims/integrations/tapdb_mount.py
index f5a3e02..e44e0b8 100644
--- a/bloom_lims/integrations/tapdb_mount.py
+++ b/bloom_lims/integrations/tapdb_mount.py
@@ -8,6 +8,7 @@
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Awaitable, Callable
+from urllib.parse import quote
from fastapi import FastAPI
from starlette.datastructures import Headers
@@ -143,7 +144,14 @@ async def __call__(
content={"detail": "Authentication required"},
)
else:
- response = RedirectResponse(url="/login", status_code=303)
+ next_path = str(scope.get("path") or "/")
+ query_string = scope.get("query_string") or b""
+ if query_string:
+ next_path = f"{next_path}?{query_string.decode('utf-8', errors='ignore')}"
+ response = RedirectResponse(
+ url=f"/login?next={quote(next_path, safe='/')}",
+ status_code=303,
+ )
await response(scope, receive, send)
return
diff --git a/pyproject.toml b/pyproject.toml
index bad3528..65559a0 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -91,7 +91,7 @@ version_file = "bloom_lims/_scm_version.py"
[tool.setuptools.packages.find]
where = ["."]
-include = ["bloom_lims*"]
+include = ["auth*", "bloom_lims*"]
[tool.setuptools.package-data]
bloom_lims = ["etc/*.yaml", "etc/*.json"]
diff --git a/tests/test_deploy_contract.py b/tests/test_deploy_contract.py
index baf5d85..5701efe 100644
--- a/tests/test_deploy_contract.py
+++ b/tests/test_deploy_contract.py
@@ -43,3 +43,11 @@ def test_db_build_help_mentions_target_option() -> None:
result = runner.invoke(build_app(), ["db", "build", "--help"])
assert result.exit_code == 0
assert "--target" in result.output
+
+
+def test_container_packages_gui_auth_module() -> None:
+ dockerfile = (PROJECT_ROOT / "Dockerfile").read_text(encoding="utf-8")
+ pyproject = (PROJECT_ROOT / "pyproject.toml").read_text(encoding="utf-8")
+
+ assert "COPY auth ./auth" in dockerfile
+ assert '"auth*"' in pyproject
diff --git a/tests/test_route_coverage_gaps_gui.py b/tests/test_route_coverage_gaps_gui.py
index 710123d..7829a83 100644
--- a/tests/test_route_coverage_gaps_gui.py
+++ b/tests/test_route_coverage_gaps_gui.py
@@ -349,7 +349,4 @@ def test_logout_alias_routes_execute_handler_body(client: TestClient) -> None:
logout = client.get("/logout", follow_redirects=False)
assert logout.status_code == 303
- assert (
- logout.headers["location"]
- == "https://example.auth.us-west-2.amazoncognito.com/logout"
- )
+ assert logout.headers["location"] == "/auth/logout"
diff --git a/tests/test_route_inventory_guard.py b/tests/test_route_inventory_guard.py
index f912ea5..8633583 100644
--- a/tests/test_route_inventory_guard.py
+++ b/tests/test_route_inventory_guard.py
@@ -89,6 +89,10 @@ def _iter_runtime_routes() -> set[tuple[str, str]]:
def test_docs_routes_remain_enabled_and_render(client: TestClient) -> None:
+ root = client.get("/", follow_redirects=False)
+ assert root.status_code in {200, 302, 303, 307, 308}
+ assert root.status_code != 404
+
openapi = client.get("/openapi.json")
assert openapi.status_code == 200
assert openapi.json()["openapi"].startswith("3.")
diff --git a/tests/test_tapdb_mount.py b/tests/test_tapdb_mount.py
index edd0f36..29ffc7a 100644
--- a/tests/test_tapdb_mount.py
+++ b/tests/test_tapdb_mount.py
@@ -29,7 +29,7 @@ def test_unauthenticated_request_redirects_to_bloom_login():
with _client() as client:
response = client.get("/admin/tapdb/login", follow_redirects=False)
assert response.status_code == 303
- assert response.headers.get("location") == "/login"
+ assert response.headers.get("location") == "/login?next=/admin/tapdb/login"
json_response = client.get(
"/admin/tapdb/login",
From 896569bbec267be573bd566ad1ec5e673c3843b5 Mon Sep 17 00:00:00 2001
From: John Major
Date: Mon, 1 Jun 2026 13:10:37 -0700
Subject: [PATCH 07/47] Restore Bloom prefix taxonomy templates
---
README.md | 59 +
bloom_lims/domain/beta_lab.py | 20 +-
bloom_lims/domain/beta_lab_stages.py | 38 +-
bloom_lims/domain/beta_lab_store.py | 10 +-
bloom_lims/domain/execution_queue.py | 20 +-
bloom_lims/etc/prefix_ownership_registry.json | 120 +
bloom_lims/schemas/beta_lab.py | 25 +-
config/tapdb_templates/bloom/templates.json | 4100 ++++++++++++++++-
tests/test_bloom_prefix_taxonomy.py | 162 +
tests/test_queue_flow.py | 24 +-
tests/test_sequencing_run_contract.py | 48 +-
11 files changed, 4486 insertions(+), 140 deletions(-)
create mode 100644 tests/test_bloom_prefix_taxonomy.py
diff --git a/README.md b/README.md
index 0037720..7b9a562 100644
--- a/README.md
+++ b/README.md
@@ -226,6 +226,65 @@ curl -k https://localhost:8912/api/v1/external/specimens \
Deep dive: [docs/apis.md](docs/apis.md)
+## Prefix Taxonomy
+
+Bloom EUID prefixes are governed display labels for operators and downstream
+records. Prefixes are governance and display labels only; they do not drive
+behavior, authorization, routing, template lookup, or workflow dispatch. Code
+should use explicit template codes and semantic properties for behavior.
+
+| Family | Meaning |
+| --- | --- |
+| `BC*` | Containers |
+| `BN*` | Contents, materials, and reagents |
+| `BD*` | Data and evidence objects |
+| `BR*` | Runs and executions |
+| `BG*` | Generic helpers and external-object mappings |
+
+Concrete template kinds use three-letter prefixes. Two-letter prefixes are
+generic class reserves only: `BC`, `BN`, `BD`, `BR`, and `BG`. New Bloom-owned
+prefixes must not contain `I`, `L`, `O`, or `U`, and explicit numeric EUID
+input must not use leading zeros.
+
+Current concrete wet-lab prefixes:
+
+| Template kind | Category | Prefix |
+| --- | --- | --- |
+| tube container | `container` | `BCT` |
+| plate container | `container` | `BCP` |
+| well container | `container` | `BCW` |
+| bottle container | `container` | `BCB` |
+| flowcell container | `container` | `BCF` |
+| flowcell lane container | `container` | `BCE` |
+| rack, box, or storage container | `container` | `BCR` |
+| blood specimen/content | `content` | `BNB` |
+| buccal specimen content | `content` | `BNS` |
+| saliva specimen content | `content` | `BNA` |
+| gDNA content | `content` | `BNG` |
+| cfDNA content | `content` | `BNC` |
+| sequencing library content | `content` | `BNQ` |
+| sequencing library pool content | `content` | `BNP` |
+| generic reagent content | `content` | `BNR` |
+| sequencing index reagent content | `content` | `BNX` |
+| control material content | `content` | `BNK` |
+| gDNA quantification data | `data` | `BDQ` |
+| extraction run evidence/data | `data` | `BDX` |
+| extraction QC run evidence/data | `data` | `BDY` |
+| library prep run evidence/data | `data` | `BDP` |
+| pooling run evidence/data | `data` | `BDN` |
+| library-index assignment data | `data` | `BDA` |
+| transfer execution data | `data` | `BDT` |
+| Illumina sequencing run | `run` | `BRM` |
+| ONT sequencing run | `run` | `BRN` |
+| Ultima sequencing run | `run` | `BRT` |
+| PacBio sequencing run | `run` | `BRP` |
+| Complete Genomics sequencing run | `run` | `BRC` |
+| external object mapping | `generic` | `BGX` |
+
+Invalid historical proposals are explicitly replaced: `BCL` becomes `BCE`,
+`BRI` becomes `BRM`, `BRO` becomes `BRN`, `BRU` becomes `BRT`, `BNL` becomes
+`BNQ`, and `BDL` becomes `BDP`. Existing historical objects keep their already minted EUIDs; template prefix changes only affect future object creation.
+
## GUI Overview
Bloom's GUI is an operator and developer surface, not just a demo shell. The main current routes are:
diff --git a/bloom_lims/domain/beta_lab.py b/bloom_lims/domain/beta_lab.py
index 295d3dd..1c1a4b4 100644
--- a/bloom_lims/domain/beta_lab.py
+++ b/bloom_lims/domain/beta_lab.py
@@ -35,6 +35,15 @@ class BetaLabService(
ORGANIZATION_SITE_REFERENCE_TYPE = "atlas_organization_site"
COLLECTION_EVENT_REFERENCE_TYPE = "atlas_collection_event"
GENERIC_DATA_TEMPLATE_CODE = "data/generic/generic/1.0"
+ DATA_TEMPLATE_BY_BETA_KIND = {
+ "extraction_batch": "data/operation/extraction/1.0",
+ "extraction_run": "data/operation/extraction/1.0",
+ "post_extract_qc_result": "data/operation/extraction-qc/1.0",
+ "library_qc_result": "data/operation/library-prep/1.0",
+ "pooling_run": "data/operation/pooling/1.0",
+ "sequenced_library_assignment": "data/library-index-assignment/sequencing-library/1.0",
+ "run_artifact": "data/execution/transfer/1.0",
+ }
BETA_KIND_QUEUE_DEFINITION = "queue_definition"
BETA_KIND_QUEUE_EVENT = "queue_event"
BETA_KIND_WORK_ITEM = "beta_work_item"
@@ -51,15 +60,18 @@ class BetaLabService(
REL_MATERIAL_CONSUMPTION = "beta_material_consumption"
REL_USED_INSTRUMENT = "beta_used_instrument"
REL_USED_REAGENT = "beta_used_reagent"
- POOL_TEMPLATE_CODE = "content/pool/generic/1.0"
+ POOL_TEMPLATE_CODE = "content/pool/sequencing-library/1.0"
POOL_CONTAINER_TEMPLATE_CODE = "container/tube/tube-generic-10ml/1.0"
- LIBRARY_PREP_OUTPUT_TEMPLATE_CODE = "data/wetlab/library_prep_output/1.0"
+ LIBRARY_PREP_OUTPUT_TEMPLATE_CODE = "data/operation/library-prep/1.0"
+ LIBRARY_MATERIAL_TEMPLATE_CODE = "content/sample/sequencing-library/1.0"
SEQUENCING_RUN_TEMPLATE_BY_SUBTYPE = {
"illumina": "data/sequencing_run/illumina/1.0",
"ont": "data/sequencing_run/ont/1.0",
- "novaseq": "data/sequencing_run/novaseq/1.0",
+ "ultima": "data/sequencing_run/ultima/1.0",
+ "pacbio": "data/sequencing_run/pacbio/1.0",
+ "completegenomics": "data/sequencing_run/completegenomics/1.0",
}
- LIBRARY_PLATE_TEMPLATE_CODE = "container/plate/fixed-plate-96/1.0"
+ LIBRARY_PLATE_TEMPLATE_CODE = "container/plate/sequencing-library-plate-96/1.0"
EXTRACTION_TEMPLATE_BY_TYPE = {
"cfdna": "content/sample/cfdna/1.0",
"gdna": "content/sample/gdna/1.0",
diff --git a/bloom_lims/domain/beta_lab_stages.py b/bloom_lims/domain/beta_lab_stages.py
index 9d927fe..ae620b1 100644
--- a/bloom_lims/domain/beta_lab_stages.py
+++ b/bloom_lims/domain/beta_lab_stages.py
@@ -61,6 +61,7 @@ def _resolve_or_create_stage_data_record(
"idempotency_key": record_idempotency_key,
"occurred_at": self._timestamp(),
},
+ template_code=self.DATA_TEMPLATE_BY_BETA_KIND.get(beta_kind),
)
def create_extraction(
@@ -388,6 +389,9 @@ def record_post_extract_qc(
"idempotency_key": idempotency_key or "",
"occurred_at": self._timestamp(),
},
+ template_code=self.DATA_TEMPLATE_BY_BETA_KIND.get(
+ "post_extract_qc_result"
+ ),
)
if payload.quant_artifact_euid:
qc_props = self._props(qc_record)
@@ -627,14 +631,13 @@ def create_library_prep(
str(self._props(source).get("extraction_type") or "gdna").strip().lower()
)
library_material = self.bobj.create_instance_by_code(
- self.EXTRACTION_TEMPLATE_BY_TYPE.get(
- extraction_type, "content/sample/gdna/1.0"
- ),
+ self.LIBRARY_MATERIAL_TEMPLATE_CODE,
{
"json_addl": {
"properties": {
"beta_kind": "library_material",
"platform": payload.platform,
+ "source_extraction_type": extraction_type,
"idempotency_key": idempotency_key or "",
"metadata": normalized_metadata,
}
@@ -843,6 +846,7 @@ def record_library_qc(
"idempotency_key": idempotency_key or "",
"occurred_at": self._timestamp(),
},
+ template_code=self.DATA_TEMPLATE_BY_BETA_KIND.get("library_qc_result"),
)
self.bobj.create_generic_instance_lineage_by_euids(
library_material.euid,
@@ -980,6 +984,24 @@ def create_pool(
pool.name = pool_name
pool_props["name"] = pool_name
self._write_props(pool, pool_props)
+ pooling_run = self._create_data_record(
+ beta_kind="pooling_run",
+ name=f"pooling:{pool.euid}",
+ properties={
+ "platform": payload.platform,
+ "member_euids": [member.euid for member in members],
+ "pool_euid": pool.euid,
+ "metadata": normalized_metadata,
+ "idempotency_key": idempotency_key or "",
+ "occurred_at": self._timestamp(),
+ },
+ template_code=self.DATA_TEMPLATE_BY_BETA_KIND.get("pooling_run"),
+ )
+ self.bobj.create_generic_instance_lineage_by_euids(
+ pooling_run.euid,
+ pool.euid,
+ relationship_type="beta_pooling_run_output",
+ )
pool_container = self.bobj.create_instance_by_code(
payload.pool_container_template_code or self.POOL_CONTAINER_TEMPLATE_CODE,
@@ -996,6 +1018,11 @@ def create_pool(
pool.euid,
relationship_type="beta_pool_member",
)
+ self.bobj.create_generic_instance_lineage_by_euids(
+ member.euid,
+ pooling_run.euid,
+ relationship_type="beta_pooling_run_input",
+ )
self._write_graph_metadata(
pool,
node_role="sequencing_pool",
@@ -1065,6 +1092,7 @@ def create_pool(
result={
"status": "success",
"pool_euid": pool.euid,
+ "pooling_run_euid": pooling_run.euid,
"pool_container_euid": pool_container.euid,
"current_queue": self.START_RUN_QUEUE_BY_PLATFORM[payload.platform],
"member_count": len(members),
@@ -1229,6 +1257,9 @@ def create_run(
"library_material_euid": assignment.library_material_euid or "",
"barcode_reagent_euid": assignment.barcode_reagent_euid or "",
},
+ template_code=self.DATA_TEMPLATE_BY_BETA_KIND.get(
+ "sequenced_library_assignment"
+ ),
)
self.bobj.create_generic_instance_lineage_by_euids(
run.euid,
@@ -1310,6 +1341,7 @@ def create_run(
"s3_uri": s3_uri,
"dewey_artifact_euid": dewey_artifact_euid or "",
},
+ template_code=self.DATA_TEMPLATE_BY_BETA_KIND.get("run_artifact"),
)
self.bobj.create_generic_instance_lineage_by_euids(
run.euid,
diff --git a/bloom_lims/domain/beta_lab_store.py b/bloom_lims/domain/beta_lab_store.py
index 91b3bf7..a4381a9 100644
--- a/bloom_lims/domain/beta_lab_store.py
+++ b/bloom_lims/domain/beta_lab_store.py
@@ -293,8 +293,14 @@ def _ensure_fixed_container_graph_metadata(self, instance) -> None:
return
type_name = str(instance.type or "").strip()
subtype = str(instance.subtype or "").strip()
- if type_name == "plate" and subtype in {"fixed-plate-96", "fixed-plate-24"}:
- max_wells = 96 if subtype == "fixed-plate-96" else 24
+ plate_well_counts = {
+ "fixed-plate-24": 24,
+ "fixed-plate-96": 96,
+ "index-plate-96": 96,
+ "sequencing-library-plate-96": 96,
+ }
+ if type_name == "plate" and subtype in plate_well_counts:
+ max_wells = plate_well_counts[subtype]
self._write_graph_metadata(
instance,
node_role=subtype,
diff --git a/bloom_lims/domain/execution_queue.py b/bloom_lims/domain/execution_queue.py
index febf736..7d7e038 100644
--- a/bloom_lims/domain/execution_queue.py
+++ b/bloom_lims/domain/execution_queue.py
@@ -165,8 +165,7 @@ class ExecutionQueueService:
"display_name": "Illumina Library QC",
"dispatch_priority": 100,
"subject_template_codes": [
- "content/sample/cfdna/1.0",
- "content/sample/gdna/1.0",
+ "content/sample/sequencing-library/1.0",
],
"required_worker_capabilities": ["wetlab.library_qc", "platform.ILMN"],
},
@@ -183,9 +182,8 @@ class ExecutionQueueService:
"display_name": "Illumina Sequencing Pool",
"dispatch_priority": 100,
"subject_template_codes": [
- "data/wetlab/library_prep_output/1.0",
- "content/sample/cfdna/1.0",
- "content/sample/gdna/1.0",
+ "data/operation/library-prep/1.0",
+ "content/sample/sequencing-library/1.0",
],
"required_worker_capabilities": ["wetlab.pooling", "platform.ILMN"],
},
@@ -193,22 +191,21 @@ class ExecutionQueueService:
"display_name": "ONT Sequencing Pool",
"dispatch_priority": 100,
"subject_template_codes": [
- "data/wetlab/library_prep_output/1.0",
- "content/sample/cfdna/1.0",
- "content/sample/gdna/1.0",
+ "data/operation/library-prep/1.0",
+ "content/sample/sequencing-library/1.0",
],
"required_worker_capabilities": ["wetlab.pooling", "platform.ONT"],
},
"ilmn_start_seq_run": {
"display_name": "Illumina Start Run",
"dispatch_priority": 100,
- "subject_template_codes": ["content/pool/generic/1.0"],
+ "subject_template_codes": ["content/pool/sequencing-library/1.0"],
"required_worker_capabilities": ["wetlab.run_start", "platform.ILMN"],
},
"ont_start_seq_run": {
"display_name": "ONT Start Run",
"dispatch_priority": 100,
- "subject_template_codes": ["content/pool/generic/1.0"],
+ "subject_template_codes": ["content/pool/sequencing-library/1.0"],
"required_worker_capabilities": ["wetlab.run_start", "platform.ONT"],
},
"post_extract_exception": {
@@ -224,8 +221,7 @@ class ExecutionQueueService:
"display_name": "Illumina Library QC Exception",
"dispatch_priority": 10,
"subject_template_codes": [
- "content/sample/cfdna/1.0",
- "content/sample/gdna/1.0",
+ "content/sample/sequencing-library/1.0",
],
"required_worker_capabilities": [
"wetlab.exception_review",
diff --git a/bloom_lims/etc/prefix_ownership_registry.json b/bloom_lims/etc/prefix_ownership_registry.json
index 43581fc..f187f31 100644
--- a/bloom_lims/etc/prefix_ownership_registry.json
+++ b/bloom_lims/etc/prefix_ownership_registry.json
@@ -13,27 +13,147 @@
"BBX": {
"issuer_app_code": "bloom"
},
+ "BC": {
+ "issuer_app_code": "bloom"
+ },
+ "BCB": {
+ "issuer_app_code": "bloom"
+ },
+ "BCE": {
+ "issuer_app_code": "bloom"
+ },
+ "BCF": {
+ "issuer_app_code": "bloom"
+ },
"BCN": {
"issuer_app_code": "bloom"
},
+ "BCP": {
+ "issuer_app_code": "bloom"
+ },
+ "BCR": {
+ "issuer_app_code": "bloom"
+ },
"BCT": {
"issuer_app_code": "bloom"
},
+ "BCW": {
+ "issuer_app_code": "bloom"
+ },
+ "BD": {
+ "issuer_app_code": "bloom"
+ },
+ "BDA": {
+ "issuer_app_code": "bloom"
+ },
+ "BDC": {
+ "issuer_app_code": "bloom"
+ },
+ "BDN": {
+ "issuer_app_code": "bloom"
+ },
+ "BDP": {
+ "issuer_app_code": "bloom"
+ },
+ "BDQ": {
+ "issuer_app_code": "bloom"
+ },
"BDT": {
"issuer_app_code": "bloom"
},
+ "BDX": {
+ "issuer_app_code": "bloom"
+ },
+ "BDY": {
+ "issuer_app_code": "bloom"
+ },
"BEQ": {
"issuer_app_code": "bloom"
},
"BFX": {
"issuer_app_code": "bloom"
},
+ "BG": {
+ "issuer_app_code": "bloom"
+ },
+ "BGM": {
+ "issuer_app_code": "bloom"
+ },
+ "BGP": {
+ "issuer_app_code": "bloom"
+ },
+ "BGR": {
+ "issuer_app_code": "bloom"
+ },
+ "BGS": {
+ "issuer_app_code": "bloom"
+ },
"BGT": {
"issuer_app_code": "bloom"
},
+ "BGV": {
+ "issuer_app_code": "bloom"
+ },
+ "BGX": {
+ "issuer_app_code": "bloom"
+ },
"BHE": {
"issuer_app_code": "bloom"
},
+ "BN": {
+ "issuer_app_code": "bloom"
+ },
+ "BNA": {
+ "issuer_app_code": "bloom"
+ },
+ "BNB": {
+ "issuer_app_code": "bloom"
+ },
+ "BNC": {
+ "issuer_app_code": "bloom"
+ },
+ "BNF": {
+ "issuer_app_code": "bloom"
+ },
+ "BNG": {
+ "issuer_app_code": "bloom"
+ },
+ "BNK": {
+ "issuer_app_code": "bloom"
+ },
+ "BNP": {
+ "issuer_app_code": "bloom"
+ },
+ "BNQ": {
+ "issuer_app_code": "bloom"
+ },
+ "BNR": {
+ "issuer_app_code": "bloom"
+ },
+ "BNS": {
+ "issuer_app_code": "bloom"
+ },
+ "BNX": {
+ "issuer_app_code": "bloom"
+ },
+ "BR": {
+ "issuer_app_code": "bloom"
+ },
+ "BRC": {
+ "issuer_app_code": "bloom"
+ },
+ "BRM": {
+ "issuer_app_code": "bloom"
+ },
+ "BRN": {
+ "issuer_app_code": "bloom"
+ },
+ "BRP": {
+ "issuer_app_code": "bloom"
+ },
+ "BRT": {
+ "issuer_app_code": "bloom"
+ },
"BSJ": {
"issuer_app_code": "bloom"
},
diff --git a/bloom_lims/schemas/beta_lab.py b/bloom_lims/schemas/beta_lab.py
index d6ca59f..ea589d6 100644
--- a/bloom_lims/schemas/beta_lab.py
+++ b/bloom_lims/schemas/beta_lab.py
@@ -347,8 +347,10 @@ class BetaRunArtifactInput(BaseModel):
class BetaRunCreateRequest(BaseModel):
pool_euid: str
- platform: Literal["ILMN", "ONT"]
- run_subtype: Literal["illumina", "ont", "novaseq"] = Field(default="illumina")
+ platform: Literal["ILMN", "ONT", "Ultima", "PacBio", "CompleteGenomics"]
+ run_subtype: Literal[
+ "illumina", "ont", "ultima", "pacbio", "completegenomics"
+ ] = Field(default="illumina")
flowcell_id: str
run_name: str | None = None
status: Literal["started", "completed"] = Field(default="completed")
@@ -367,13 +369,18 @@ def validate_assignments(self) -> "BetaRunCreateRequest":
raise ValueError("flowcell_id must not be empty")
if not self.assignments:
raise ValueError("assignments must not be empty")
- if self.platform == "ONT" and self.run_subtype != "ont":
- raise ValueError("platform=ONT requires run_subtype=ont")
- if self.platform == "ILMN" and self.run_subtype not in {
- "illumina",
- "novaseq",
- }:
- raise ValueError("platform=ILMN requires run_subtype=illumina or novaseq")
+ expected_subtype_by_platform = {
+ "ILMN": "illumina",
+ "ONT": "ont",
+ "Ultima": "ultima",
+ "PacBio": "pacbio",
+ "CompleteGenomics": "completegenomics",
+ }
+ expected_subtype = expected_subtype_by_platform[self.platform]
+ if self.run_subtype != expected_subtype:
+ raise ValueError(
+ f"platform={self.platform} requires run_subtype={expected_subtype}"
+ )
if self.instrument_euid is not None and not self.instrument_euid.strip():
raise ValueError("instrument_euid must not be empty when provided")
for field_name in ("operator_start_datetime", "sequencing_end_datetime"):
diff --git a/config/tapdb_templates/bloom/templates.json b/config/tapdb_templates/bloom/templates.json
index fc7edf2..c6feaaa 100644
--- a/config/tapdb_templates/bloom/templates.json
+++ b/config/tapdb_templates/bloom/templates.json
@@ -2701,11 +2701,11 @@
{
"name": "Generic External Object Link",
"polymorphic_discriminator": "generic_template",
- "category": "BGT",
+ "category": "BGX",
"type": "generic",
"subtype": "external_object_link",
"version": "1.0",
- "instance_prefix": "BGT",
+ "instance_prefix": "BGX",
"instance_polymorphic_identity": "generic_instance",
"bstatus": "active",
"is_singleton": false,
@@ -2759,11 +2759,11 @@
{
"name": "24 fixed well plate",
"polymorphic_discriminator": "container_template",
- "category": "BCN",
+ "category": "BCP",
"type": "plate",
"subtype": "fixed-plate-24",
"version": "1.0",
- "instance_prefix": "BCN",
+ "instance_prefix": "BCP",
"instance_polymorphic_identity": "container_instance",
"bstatus": "active",
"is_singleton": false,
@@ -3300,11 +3300,11 @@
{
"name": "96 well fixed plate",
"polymorphic_discriminator": "container_template",
- "category": "BCN",
+ "category": "BCP",
"type": "plate",
"subtype": "fixed-plate-96",
"version": "1.0",
- "instance_prefix": "BCN",
+ "instance_prefix": "BCP",
"instance_polymorphic_identity": "container_instance",
"bstatus": "active",
"is_singleton": false,
@@ -4934,11 +4934,11 @@
{
"name": "4 position Rack",
"polymorphic_discriminator": "container_template",
- "category": "BCN",
+ "category": "BCR",
"type": "rack",
"subtype": "tube-rack-4-empty",
"version": "1.0",
- "instance_prefix": "BCN",
+ "instance_prefix": "BCR",
"instance_polymorphic_identity": "container_instance",
"bstatus": "active",
"is_singleton": false,
@@ -4987,11 +4987,11 @@
{
"name": "4 position Rack",
"polymorphic_discriminator": "container_template",
- "category": "BCN",
+ "category": "BCR",
"type": "rack",
"subtype": "tube-rack-generic",
"version": "1.0",
- "instance_prefix": "BCN",
+ "instance_prefix": "BCR",
"instance_polymorphic_identity": "container_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5094,11 +5094,11 @@
{
"name": "Shelf",
"polymorphic_discriminator": "container_template",
- "category": "BCN",
+ "category": "BCR",
"type": "shelf",
"subtype": "generic",
"version": "1.0",
- "instance_prefix": "BCN",
+ "instance_prefix": "BCR",
"instance_polymorphic_identity": "container_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5150,11 +5150,11 @@
{
"name": "10ml glass tube",
"polymorphic_discriminator": "container_template",
- "category": "BCN",
+ "category": "BCT",
"type": "tube",
"subtype": "tube-10ml-glass",
"version": "1.0",
- "instance_prefix": "BCN",
+ "instance_prefix": "BCT",
"instance_polymorphic_identity": "container_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5206,11 +5206,11 @@
{
"name": "1.5ml eppi tube",
"polymorphic_discriminator": "container_template",
- "category": "BCN",
+ "category": "BCT",
"type": "tube",
"subtype": "tube-eppi-1.5ml",
"version": "1.0",
- "instance_prefix": "BCN",
+ "instance_prefix": "BCT",
"instance_polymorphic_identity": "container_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5262,11 +5262,11 @@
{
"name": "Generic 10ml tube",
"polymorphic_discriminator": "container_template",
- "category": "BCN",
+ "category": "BCT",
"type": "tube",
"subtype": "tube-generic-10ml",
"version": "1.0",
- "instance_prefix": "BCN",
+ "instance_prefix": "BCT",
"instance_polymorphic_identity": "container_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5318,11 +5318,11 @@
{
"name": "strek 10ml",
"polymorphic_discriminator": "container_template",
- "category": "BCN",
+ "category": "BCT",
"type": "tube",
"subtype": "tube-strek-10ml",
"version": "1.0",
- "instance_prefix": "BCN",
+ "instance_prefix": "BCT",
"instance_polymorphic_identity": "container_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5375,11 +5375,11 @@
{
"name": "Mawi DNA Technologies - ISD-T-250 - iSWAB DNA Collection Tube - Buccal",
"polymorphic_discriminator": "container_template",
- "category": "BCN",
+ "category": "BCT",
"type": "tube",
"subtype": "mawi-isd-t-250-iswab-dna-collection-tube-buccal",
"version": "1.0",
- "instance_prefix": "BCN",
+ "instance_prefix": "BCT",
"instance_polymorphic_identity": "container_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5435,11 +5435,11 @@
{
"name": "plate well - fixed",
"polymorphic_discriminator": "container_template",
- "category": "BCN",
+ "category": "BCW",
"type": "well",
"subtype": "fixed-plate-well",
"version": "1.0",
- "instance_prefix": "BCN",
+ "instance_prefix": "BCW",
"instance_polymorphic_identity": "container_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5490,11 +5490,11 @@
{
"name": "giab NA12878",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNK",
"type": "control",
"subtype": "giab-HG001",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNK",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5534,11 +5534,11 @@
{
"name": "giab NA24385",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNK",
"type": "control",
"subtype": "giab-HG002",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNK",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5578,11 +5578,11 @@
{
"name": "synthetic-cfdna",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNK",
"type": "control",
"subtype": "synthetic-cfdna",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNK",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5622,11 +5622,11 @@
{
"name": "NTC - water",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNK",
"type": "control",
"subtype": "water-ntc",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNK",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5666,11 +5666,11 @@
{
"name": "Pool of Contents",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNP",
"type": "pool",
"subtype": "generic",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNP",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5702,11 +5702,11 @@
{
"name": "Novaseq sequencing kit",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNR",
"type": "reagent",
"subtype": "ILMN-nova-seq-kit",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNR",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5745,11 +5745,11 @@
{
"name": "idt probes for rare mendelian disease, v1.0",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNR",
"type": "reagent",
"subtype": "idt-probes-rare-mendelian",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNR",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5788,11 +5788,11 @@
{
"name": "NaOH",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNR",
"type": "reagent",
"subtype": "naoh",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNR",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5832,11 +5832,11 @@
{
"name": "plasma (whole blood)",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNB",
"type": "sample",
"subtype": "blood-plasma",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNB",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5870,11 +5870,11 @@
{
"name": "cell free DNA ",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNC",
"type": "sample",
"subtype": "cfdna",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNC",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5908,11 +5908,11 @@
{
"name": "genomic DNA",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNG",
"type": "sample",
"subtype": "gdna",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNG",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5946,11 +5946,11 @@
{
"name": "Whole Blood",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNB",
"type": "specimen",
"subtype": "blood-whole",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNB",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -5984,11 +5984,11 @@
{
"name": "Buccal Swab",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNS",
"type": "specimen",
"subtype": "buccal-swab",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNS",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -6022,11 +6022,11 @@
{
"name": "FFPE Block",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNF",
"type": "specimen",
"subtype": "ffpe-block",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNF",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -6060,11 +6060,11 @@
{
"name": "FFPE Slides",
"polymorphic_discriminator": "content_template",
- "category": "BCT",
+ "category": "BNF",
"type": "specimen",
"subtype": "ffpe-slice",
"version": "1.0",
- "instance_prefix": "BCT",
+ "instance_prefix": "BNF",
"instance_polymorphic_identity": "content_instance",
"bstatus": "active",
"is_singleton": false,
@@ -6335,11 +6335,11 @@
{
"name": "Generic Data Record",
"polymorphic_discriminator": "data_template",
- "category": "BDT",
+ "category": "BD",
"type": "generic",
"subtype": "generic",
"version": "1.0",
- "instance_prefix": "BDT",
+ "instance_prefix": "BD",
"instance_polymorphic_identity": "data_instance",
"bstatus": "active",
"is_singleton": false,
@@ -6365,11 +6365,11 @@
{
"name": "DNA Quant Data",
"polymorphic_discriminator": "data_template",
- "category": "BDT",
+ "category": "BDQ",
"type": "generic",
"subtype": "gdna-quantification",
"version": "1.0",
- "instance_prefix": "BDT",
+ "instance_prefix": "BDQ",
"instance_polymorphic_identity": "data_instance",
"bstatus": "active",
"is_singleton": false,
@@ -6408,11 +6408,11 @@
{
"name": "Temperature Log Data",
"polymorphic_discriminator": "data_template",
- "category": "BDT",
+ "category": "BDC",
"type": "generic",
"subtype": "temperature-log",
"version": "1.0",
- "instance_prefix": "BDT",
+ "instance_prefix": "BDC",
"instance_polymorphic_identity": "data_instance",
"bstatus": "active",
"is_singleton": false,
@@ -6445,11 +6445,11 @@
{
"name": "Wet-Lab Library Prep Output",
"polymorphic_discriminator": "data_template",
- "category": "BDT",
+ "category": "BDP",
"type": "wetlab",
"subtype": "library_prep_output",
"version": "1.0",
- "instance_prefix": "BDT",
+ "instance_prefix": "BDP",
"instance_polymorphic_identity": "data_instance",
"bstatus": "active",
"is_singleton": false,
@@ -6478,11 +6478,11 @@
{
"name": "Illumina Sequencing Run",
"polymorphic_discriminator": "data_template",
- "category": "BDT",
+ "category": "BRM",
"type": "sequencing_run",
"subtype": "illumina",
"version": "1.0",
- "instance_prefix": "BDT",
+ "instance_prefix": "BRM",
"instance_polymorphic_identity": "data_instance",
"bstatus": "active",
"is_singleton": false,
@@ -6516,11 +6516,11 @@
{
"name": "ONT Sequencing Run",
"polymorphic_discriminator": "data_template",
- "category": "BDT",
+ "category": "BRN",
"type": "sequencing_run",
"subtype": "ont",
"version": "1.0",
- "instance_prefix": "BDT",
+ "instance_prefix": "BRN",
"instance_polymorphic_identity": "data_instance",
"bstatus": "active",
"is_singleton": false,
@@ -6552,13 +6552,13 @@
}
},
{
- "name": "NovaSeq Sequencing Run",
+ "name": "Ultima Sequencing Run",
"polymorphic_discriminator": "data_template",
- "category": "BDT",
+ "category": "BRT",
"type": "sequencing_run",
- "subtype": "novaseq",
+ "subtype": "ultima",
"version": "1.0",
- "instance_prefix": "BDT",
+ "instance_prefix": "BRT",
"instance_polymorphic_identity": "data_instance",
"bstatus": "active",
"is_singleton": false,
@@ -6569,20 +6569,96 @@
"create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
"set_object_status": "BAC/core/set_object_status/1.0"
},
- "description": "Sequencing run executed on an Illumina NovaSeq instrument.",
+ "description": "Sequencing run executed on an Ultima instrument.",
"expected_inputs": [],
"expected_outputs": [],
"instantiation_layouts": [],
"properties": {
"beta_kind": "sequencing_run",
- "platform": "ILMN",
- "run_subtype": "novaseq",
+ "platform": "Ultima",
+ "run_subtype": "ultima",
+ "flowcell_id": "",
+ "operator_start_datetime": null,
+ "sequencing_end_datetime": null,
+ "instrument_euid": "",
+ "metadata": {},
+ "name": "Ultima Sequencing Run",
+ "idempotency_key": ""
+ },
+ "singleton": "0",
+ "semantic_category": "data"
+ }
+ },
+ {
+ "name": "CompleteGenomics Sequencing Run",
+ "polymorphic_discriminator": "data_template",
+ "category": "BRC",
+ "type": "sequencing_run",
+ "subtype": "completegenomics",
+ "version": "1.0",
+ "instance_prefix": "BRC",
+ "instance_polymorphic_identity": "data_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "action_groups": {},
+ "action_imports": {
+ "add_relationships": "BAC/core/add-relationships/1.0",
+ "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
+ "set_object_status": "BAC/core/set_object_status/1.0"
+ },
+ "description": "Sequencing run executed on a Complete Genomics instrument.",
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "instantiation_layouts": [],
+ "properties": {
+ "beta_kind": "sequencing_run",
+ "platform": "CompleteGenomics",
+ "run_subtype": "completegenomics",
+ "flowcell_id": "",
+ "operator_start_datetime": null,
+ "sequencing_end_datetime": null,
+ "instrument_euid": "",
+ "metadata": {},
+ "name": "CompleteGenomics Sequencing Run",
+ "idempotency_key": ""
+ },
+ "singleton": "0",
+ "semantic_category": "data"
+ }
+ },
+ {
+ "name": "PacBio Sequencing Run",
+ "polymorphic_discriminator": "data_template",
+ "category": "BRP",
+ "type": "sequencing_run",
+ "subtype": "pacbio",
+ "version": "1.0",
+ "instance_prefix": "BRP",
+ "instance_polymorphic_identity": "data_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "action_groups": {},
+ "action_imports": {
+ "add_relationships": "BAC/core/add-relationships/1.0",
+ "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
+ "set_object_status": "BAC/core/set_object_status/1.0"
+ },
+ "description": "Sequencing run executed on a PacBio instrument.",
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "instantiation_layouts": [],
+ "properties": {
+ "beta_kind": "sequencing_run",
+ "platform": "PacBio",
+ "run_subtype": "pacbio",
"flowcell_id": "",
"operator_start_datetime": null,
"sequencing_end_datetime": null,
"instrument_euid": "",
"metadata": {},
- "name": "NovaSeq Sequencing Run",
+ "name": "PacBio Sequencing Run",
"idempotency_key": ""
},
"singleton": "0",
@@ -6630,7 +6706,7 @@
"relationship_type": "contains",
"child_templates": [
{
- "template_code": "BCN/shelf/generic/1.0",
+ "template_code": "BCR/shelf/generic/1.0",
"json_addl": {
"cont_address": {
"capacity": "10",
@@ -6643,7 +6719,7 @@
}
},
{
- "template_code": "BCN/shelf/generic/1.0",
+ "template_code": "BCR/shelf/generic/1.0",
"json_addl": {
"cont_address": {
"capacity": "10",
@@ -6712,7 +6788,7 @@
"relationship_type": "contains",
"child_templates": [
{
- "template_code": "BCN/shelf/generic/1.0",
+ "template_code": "BCR/shelf/generic/1.0",
"json_addl": {
"cont_address": {
"capacity": "10",
@@ -6725,7 +6801,7 @@
}
},
{
- "template_code": "BCN/shelf/generic/1.0",
+ "template_code": "BCR/shelf/generic/1.0",
"json_addl": {
"cont_address": {
"capacity": "10",
@@ -6738,7 +6814,7 @@
}
},
{
- "template_code": "BCN/shelf/generic/1.0",
+ "template_code": "BCR/shelf/generic/1.0",
"json_addl": {
"cont_address": {
"capacity": "10",
@@ -6751,7 +6827,7 @@
}
},
{
- "template_code": "BCN/shelf/generic/1.0",
+ "template_code": "BCR/shelf/generic/1.0",
"json_addl": {
"cont_address": {
"capacity": "10",
@@ -10382,6 +10458,3870 @@
},
"semantic_category": "workflow_step"
}
+ },
+ {
+ "name": "Sequencing Library Plate 96",
+ "polymorphic_discriminator": "container_template",
+ "category": "BCP",
+ "type": "plate",
+ "subtype": "sequencing-library-plate-96",
+ "version": "1.0",
+ "instance_prefix": "BCP",
+ "instance_polymorphic_identity": "container_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "action_groups": {},
+ "action_imports": {
+ "add_relationships": "BAC/core/add-relationships/1.0",
+ "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
+ "download_plate_map": "BAC/plate/download_plate_map/1.0",
+ "print_barcode_label": "BAC/core/print_barcode_label/1.0",
+ "set_object_status": "BAC/core/set_object_status/1.0",
+ "stamp_plates_into_plate": "BAC/plate/stamp_plates_into_plate/1.0"
+ },
+ "cogs": {
+ "allocation_type": "",
+ "cost": "4.00",
+ "cost_split_by_children": [
+ {
+ "*/*/*/*": {}
+ }
+ ],
+ "state": "active"
+ },
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "",
+ "row_idx": "0",
+ "row_name": ""
+ },
+ "description": "96 well fixed plate",
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "instantiation_layouts": [
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "1",
+ "name": "A1",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A1"
+ }
+ },
+ "name_pattern": "A1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "1",
+ "name": "A2",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A2"
+ }
+ },
+ "name_pattern": "A2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "1",
+ "name": "A3",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A3"
+ }
+ },
+ "name_pattern": "A3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "1",
+ "name": "A4",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A4"
+ }
+ },
+ "name_pattern": "A4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "1",
+ "name": "A5",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A5"
+ }
+ },
+ "name_pattern": "A5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "1",
+ "name": "A6",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A6"
+ }
+ },
+ "name_pattern": "A6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "1",
+ "name": "A7",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A7"
+ }
+ },
+ "name_pattern": "A7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "1",
+ "name": "A8",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A8"
+ }
+ },
+ "name_pattern": "A8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "1",
+ "name": "A9",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A9"
+ }
+ },
+ "name_pattern": "A9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "1",
+ "name": "A10",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A10"
+ }
+ },
+ "name_pattern": "A10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "1",
+ "name": "A11",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A11"
+ }
+ },
+ "name_pattern": "A11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "1",
+ "name": "A12",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A12"
+ }
+ },
+ "name_pattern": "A12"
+ }
+ ]
+ },
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "2",
+ "name": "B1",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B1"
+ }
+ },
+ "name_pattern": "B1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "2",
+ "name": "B2",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B2"
+ }
+ },
+ "name_pattern": "B2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "2",
+ "name": "B3",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B3"
+ }
+ },
+ "name_pattern": "B3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "2",
+ "name": "B4",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B4"
+ }
+ },
+ "name_pattern": "B4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "2",
+ "name": "B5",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B5"
+ }
+ },
+ "name_pattern": "B5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "2",
+ "name": "B6",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B6"
+ }
+ },
+ "name_pattern": "B6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "2",
+ "name": "B7",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B7"
+ }
+ },
+ "name_pattern": "B7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "2",
+ "name": "B8",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B8"
+ }
+ },
+ "name_pattern": "B8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "2",
+ "name": "B9",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B9"
+ }
+ },
+ "name_pattern": "B9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "2",
+ "name": "B10",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B10"
+ }
+ },
+ "name_pattern": "B10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "2",
+ "name": "B11",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B11"
+ }
+ },
+ "name_pattern": "B11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "2",
+ "name": "B12",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B12"
+ }
+ },
+ "name_pattern": "B12"
+ }
+ ]
+ },
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "3",
+ "name": "C1",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C1"
+ }
+ },
+ "name_pattern": "C1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "3",
+ "name": "C2",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C2"
+ }
+ },
+ "name_pattern": "C2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "3",
+ "name": "C3",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C3"
+ }
+ },
+ "name_pattern": "C3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "3",
+ "name": "C4",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C4"
+ }
+ },
+ "name_pattern": "C4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "3",
+ "name": "C5",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C5"
+ }
+ },
+ "name_pattern": "C5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "3",
+ "name": "C6",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C6"
+ }
+ },
+ "name_pattern": "C6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "3",
+ "name": "C7",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C7"
+ }
+ },
+ "name_pattern": "C7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "3",
+ "name": "C8",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C8"
+ }
+ },
+ "name_pattern": "C8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "3",
+ "name": "C9",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C9"
+ }
+ },
+ "name_pattern": "C9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "3",
+ "name": "C10",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C10"
+ }
+ },
+ "name_pattern": "C10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "3",
+ "name": "C11",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C11"
+ }
+ },
+ "name_pattern": "C11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "3",
+ "name": "C12",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C12"
+ }
+ },
+ "name_pattern": "C12"
+ }
+ ]
+ },
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "4",
+ "name": "D1",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D1"
+ }
+ },
+ "name_pattern": "D1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "4",
+ "name": "D2",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D2"
+ }
+ },
+ "name_pattern": "D2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "4",
+ "name": "D3",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D3"
+ }
+ },
+ "name_pattern": "D3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "4",
+ "name": "D4",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D4"
+ }
+ },
+ "name_pattern": "D4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "4",
+ "name": "D5",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D5"
+ }
+ },
+ "name_pattern": "D5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "4",
+ "name": "D6",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D6"
+ }
+ },
+ "name_pattern": "D6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "4",
+ "name": "D7",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D7"
+ }
+ },
+ "name_pattern": "D7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "4",
+ "name": "D8",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D8"
+ }
+ },
+ "name_pattern": "D8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "4",
+ "name": "D9",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D9"
+ }
+ },
+ "name_pattern": "D9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "4",
+ "name": "D10",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D10"
+ }
+ },
+ "name_pattern": "D10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "4",
+ "name": "D11",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D11"
+ }
+ },
+ "name_pattern": "D11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "4",
+ "name": "D12",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D12"
+ }
+ },
+ "name_pattern": "D12"
+ }
+ ]
+ },
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "5",
+ "name": "E1",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E1"
+ }
+ },
+ "name_pattern": "E1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "5",
+ "name": "E2",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E2"
+ }
+ },
+ "name_pattern": "E2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "5",
+ "name": "E3",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E3"
+ }
+ },
+ "name_pattern": "E3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "5",
+ "name": "E4",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E4"
+ }
+ },
+ "name_pattern": "E4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "5",
+ "name": "E5",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E5"
+ }
+ },
+ "name_pattern": "E5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "5",
+ "name": "E6",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E6"
+ }
+ },
+ "name_pattern": "E6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "5",
+ "name": "E7",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E7"
+ }
+ },
+ "name_pattern": "E7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "5",
+ "name": "E8",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E8"
+ }
+ },
+ "name_pattern": "E8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "5",
+ "name": "E9",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E9"
+ }
+ },
+ "name_pattern": "E9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "5",
+ "name": "E10",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E10"
+ }
+ },
+ "name_pattern": "E10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "5",
+ "name": "E11",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E11"
+ }
+ },
+ "name_pattern": "E11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "5",
+ "name": "E12",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E12"
+ }
+ },
+ "name_pattern": "E12"
+ }
+ ]
+ },
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "6",
+ "name": "F1",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F1"
+ }
+ },
+ "name_pattern": "F1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "6",
+ "name": "F2",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F2"
+ }
+ },
+ "name_pattern": "F2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "6",
+ "name": "F3",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F3"
+ }
+ },
+ "name_pattern": "F3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "6",
+ "name": "F4",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F4"
+ }
+ },
+ "name_pattern": "F4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "6",
+ "name": "F5",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F5"
+ }
+ },
+ "name_pattern": "F5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "6",
+ "name": "F6",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F6"
+ }
+ },
+ "name_pattern": "F6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "6",
+ "name": "F7",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F7"
+ }
+ },
+ "name_pattern": "F7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "6",
+ "name": "F8",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F8"
+ }
+ },
+ "name_pattern": "F8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "6",
+ "name": "F9",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F9"
+ }
+ },
+ "name_pattern": "F9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "6",
+ "name": "F10",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F10"
+ }
+ },
+ "name_pattern": "F10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "6",
+ "name": "F11",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F11"
+ }
+ },
+ "name_pattern": "F11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "6",
+ "name": "F12",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F12"
+ }
+ },
+ "name_pattern": "F12"
+ }
+ ]
+ },
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "7",
+ "name": "G1",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G1"
+ }
+ },
+ "name_pattern": "G1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "7",
+ "name": "G2",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G2"
+ }
+ },
+ "name_pattern": "G2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "7",
+ "name": "G3",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G3"
+ }
+ },
+ "name_pattern": "G3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "7",
+ "name": "G4",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G4"
+ }
+ },
+ "name_pattern": "G4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "7",
+ "name": "G5",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G5"
+ }
+ },
+ "name_pattern": "G5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "7",
+ "name": "G6",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G6"
+ }
+ },
+ "name_pattern": "G6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "7",
+ "name": "G7",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G7"
+ }
+ },
+ "name_pattern": "G7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "7",
+ "name": "G8",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G8"
+ }
+ },
+ "name_pattern": "G8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "7",
+ "name": "G9",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G9"
+ }
+ },
+ "name_pattern": "G9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "7",
+ "name": "G10",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G10"
+ }
+ },
+ "name_pattern": "G10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "7",
+ "name": "G11",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G11"
+ }
+ },
+ "name_pattern": "G11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "7",
+ "name": "G12",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G12"
+ }
+ },
+ "name_pattern": "G12"
+ }
+ ]
+ },
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "8",
+ "name": "H1",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H1"
+ }
+ },
+ "name_pattern": "H1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "8",
+ "name": "H2",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H2"
+ }
+ },
+ "name_pattern": "H2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "8",
+ "name": "H3",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H3"
+ }
+ },
+ "name_pattern": "H3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "8",
+ "name": "H4",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H4"
+ }
+ },
+ "name_pattern": "H4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "8",
+ "name": "H5",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H5"
+ }
+ },
+ "name_pattern": "H5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "8",
+ "name": "H6",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H6"
+ }
+ },
+ "name_pattern": "H6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "8",
+ "name": "H7",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H7"
+ }
+ },
+ "name_pattern": "H7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "8",
+ "name": "H8",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H8"
+ }
+ },
+ "name_pattern": "H8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "8",
+ "name": "H9",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H9"
+ }
+ },
+ "name_pattern": "H9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "8",
+ "name": "H10",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H10"
+ }
+ },
+ "name_pattern": "H10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "8",
+ "name": "H11",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H11"
+ }
+ },
+ "name_pattern": "H11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "8",
+ "name": "H12",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H12"
+ }
+ },
+ "name_pattern": "H12"
+ }
+ ]
+ }
+ ],
+ "properties": {
+ "comments": "",
+ "lab_code": "",
+ "lot_expiration_date": "",
+ "lot_number": "",
+ "manufacturer": "",
+ "name": "Sequencing Library Plate 96",
+ "plate_role": "sequencing_library"
+ },
+ "singleton": "0",
+ "valid_content": [
+ "none"
+ ],
+ "valid_parents": [],
+ "semantic_category": "container"
+ }
+ },
+ {
+ "name": "Sequencing Index Plate 96",
+ "polymorphic_discriminator": "container_template",
+ "category": "BCP",
+ "type": "plate",
+ "subtype": "index-plate-96",
+ "version": "1.0",
+ "instance_prefix": "BCP",
+ "instance_polymorphic_identity": "container_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "action_groups": {},
+ "action_imports": {
+ "add_relationships": "BAC/core/add-relationships/1.0",
+ "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
+ "download_plate_map": "BAC/plate/download_plate_map/1.0",
+ "print_barcode_label": "BAC/core/print_barcode_label/1.0",
+ "set_object_status": "BAC/core/set_object_status/1.0",
+ "stamp_plates_into_plate": "BAC/plate/stamp_plates_into_plate/1.0"
+ },
+ "cogs": {
+ "allocation_type": "",
+ "cost": "4.00",
+ "cost_split_by_children": [
+ {
+ "*/*/*/*": {}
+ }
+ ],
+ "state": "active"
+ },
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "",
+ "row_idx": "0",
+ "row_name": ""
+ },
+ "description": "96 well fixed plate",
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "instantiation_layouts": [
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "1",
+ "name": "A1",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A1"
+ }
+ },
+ "name_pattern": "A1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "1",
+ "name": "A2",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A2"
+ }
+ },
+ "name_pattern": "A2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "1",
+ "name": "A3",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A3"
+ }
+ },
+ "name_pattern": "A3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "1",
+ "name": "A4",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A4"
+ }
+ },
+ "name_pattern": "A4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "1",
+ "name": "A5",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A5"
+ }
+ },
+ "name_pattern": "A5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "1",
+ "name": "A6",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A6"
+ }
+ },
+ "name_pattern": "A6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "1",
+ "name": "A7",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A7"
+ }
+ },
+ "name_pattern": "A7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "1",
+ "name": "A8",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A8"
+ }
+ },
+ "name_pattern": "A8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "1",
+ "name": "A9",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A9"
+ }
+ },
+ "name_pattern": "A9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "1",
+ "name": "A10",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A10"
+ }
+ },
+ "name_pattern": "A10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "1",
+ "name": "A11",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A11"
+ }
+ },
+ "name_pattern": "A11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "1",
+ "name": "A12",
+ "row_idx": "0",
+ "row_name": "A"
+ },
+ "properties": {
+ "name": "A12"
+ }
+ },
+ "name_pattern": "A12"
+ }
+ ]
+ },
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "2",
+ "name": "B1",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B1"
+ }
+ },
+ "name_pattern": "B1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "2",
+ "name": "B2",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B2"
+ }
+ },
+ "name_pattern": "B2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "2",
+ "name": "B3",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B3"
+ }
+ },
+ "name_pattern": "B3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "2",
+ "name": "B4",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B4"
+ }
+ },
+ "name_pattern": "B4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "2",
+ "name": "B5",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B5"
+ }
+ },
+ "name_pattern": "B5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "2",
+ "name": "B6",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B6"
+ }
+ },
+ "name_pattern": "B6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "2",
+ "name": "B7",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B7"
+ }
+ },
+ "name_pattern": "B7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "2",
+ "name": "B8",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B8"
+ }
+ },
+ "name_pattern": "B8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "2",
+ "name": "B9",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B9"
+ }
+ },
+ "name_pattern": "B9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "2",
+ "name": "B10",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B10"
+ }
+ },
+ "name_pattern": "B10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "2",
+ "name": "B11",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B11"
+ }
+ },
+ "name_pattern": "B11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "2",
+ "name": "B12",
+ "row_idx": "1",
+ "row_name": "B"
+ },
+ "properties": {
+ "name": "B12"
+ }
+ },
+ "name_pattern": "B12"
+ }
+ ]
+ },
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "3",
+ "name": "C1",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C1"
+ }
+ },
+ "name_pattern": "C1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "3",
+ "name": "C2",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C2"
+ }
+ },
+ "name_pattern": "C2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "3",
+ "name": "C3",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C3"
+ }
+ },
+ "name_pattern": "C3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "3",
+ "name": "C4",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C4"
+ }
+ },
+ "name_pattern": "C4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "3",
+ "name": "C5",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C5"
+ }
+ },
+ "name_pattern": "C5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "3",
+ "name": "C6",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C6"
+ }
+ },
+ "name_pattern": "C6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "3",
+ "name": "C7",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C7"
+ }
+ },
+ "name_pattern": "C7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "3",
+ "name": "C8",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C8"
+ }
+ },
+ "name_pattern": "C8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "3",
+ "name": "C9",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C9"
+ }
+ },
+ "name_pattern": "C9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "3",
+ "name": "C10",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C10"
+ }
+ },
+ "name_pattern": "C10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "3",
+ "name": "C11",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C11"
+ }
+ },
+ "name_pattern": "C11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "3",
+ "name": "C12",
+ "row_idx": "2",
+ "row_name": "C"
+ },
+ "properties": {
+ "name": "C12"
+ }
+ },
+ "name_pattern": "C12"
+ }
+ ]
+ },
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "4",
+ "name": "D1",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D1"
+ }
+ },
+ "name_pattern": "D1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "4",
+ "name": "D2",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D2"
+ }
+ },
+ "name_pattern": "D2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "4",
+ "name": "D3",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D3"
+ }
+ },
+ "name_pattern": "D3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "4",
+ "name": "D4",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D4"
+ }
+ },
+ "name_pattern": "D4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "4",
+ "name": "D5",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D5"
+ }
+ },
+ "name_pattern": "D5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "4",
+ "name": "D6",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D6"
+ }
+ },
+ "name_pattern": "D6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "4",
+ "name": "D7",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D7"
+ }
+ },
+ "name_pattern": "D7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "4",
+ "name": "D8",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D8"
+ }
+ },
+ "name_pattern": "D8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "4",
+ "name": "D9",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D9"
+ }
+ },
+ "name_pattern": "D9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "4",
+ "name": "D10",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D10"
+ }
+ },
+ "name_pattern": "D10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "4",
+ "name": "D11",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D11"
+ }
+ },
+ "name_pattern": "D11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "4",
+ "name": "D12",
+ "row_idx": "3",
+ "row_name": "D"
+ },
+ "properties": {
+ "name": "D12"
+ }
+ },
+ "name_pattern": "D12"
+ }
+ ]
+ },
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "5",
+ "name": "E1",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E1"
+ }
+ },
+ "name_pattern": "E1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "5",
+ "name": "E2",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E2"
+ }
+ },
+ "name_pattern": "E2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "5",
+ "name": "E3",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E3"
+ }
+ },
+ "name_pattern": "E3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "5",
+ "name": "E4",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E4"
+ }
+ },
+ "name_pattern": "E4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "5",
+ "name": "E5",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E5"
+ }
+ },
+ "name_pattern": "E5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "5",
+ "name": "E6",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E6"
+ }
+ },
+ "name_pattern": "E6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "5",
+ "name": "E7",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E7"
+ }
+ },
+ "name_pattern": "E7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "5",
+ "name": "E8",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E8"
+ }
+ },
+ "name_pattern": "E8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "5",
+ "name": "E9",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E9"
+ }
+ },
+ "name_pattern": "E9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "5",
+ "name": "E10",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E10"
+ }
+ },
+ "name_pattern": "E10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "5",
+ "name": "E11",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E11"
+ }
+ },
+ "name_pattern": "E11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "5",
+ "name": "E12",
+ "row_idx": "4",
+ "row_name": "E"
+ },
+ "properties": {
+ "name": "E12"
+ }
+ },
+ "name_pattern": "E12"
+ }
+ ]
+ },
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "6",
+ "name": "F1",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F1"
+ }
+ },
+ "name_pattern": "F1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "6",
+ "name": "F2",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F2"
+ }
+ },
+ "name_pattern": "F2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "6",
+ "name": "F3",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F3"
+ }
+ },
+ "name_pattern": "F3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "6",
+ "name": "F4",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F4"
+ }
+ },
+ "name_pattern": "F4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "6",
+ "name": "F5",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F5"
+ }
+ },
+ "name_pattern": "F5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "6",
+ "name": "F6",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F6"
+ }
+ },
+ "name_pattern": "F6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "6",
+ "name": "F7",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F7"
+ }
+ },
+ "name_pattern": "F7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "6",
+ "name": "F8",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F8"
+ }
+ },
+ "name_pattern": "F8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "6",
+ "name": "F9",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F9"
+ }
+ },
+ "name_pattern": "F9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "6",
+ "name": "F10",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F10"
+ }
+ },
+ "name_pattern": "F10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "6",
+ "name": "F11",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F11"
+ }
+ },
+ "name_pattern": "F11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "6",
+ "name": "F12",
+ "row_idx": "5",
+ "row_name": "F"
+ },
+ "properties": {
+ "name": "F12"
+ }
+ },
+ "name_pattern": "F12"
+ }
+ ]
+ },
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "7",
+ "name": "G1",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G1"
+ }
+ },
+ "name_pattern": "G1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "7",
+ "name": "G2",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G2"
+ }
+ },
+ "name_pattern": "G2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "7",
+ "name": "G3",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G3"
+ }
+ },
+ "name_pattern": "G3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "7",
+ "name": "G4",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G4"
+ }
+ },
+ "name_pattern": "G4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "7",
+ "name": "G5",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G5"
+ }
+ },
+ "name_pattern": "G5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "7",
+ "name": "G6",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G6"
+ }
+ },
+ "name_pattern": "G6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "7",
+ "name": "G7",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G7"
+ }
+ },
+ "name_pattern": "G7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "7",
+ "name": "G8",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G8"
+ }
+ },
+ "name_pattern": "G8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "7",
+ "name": "G9",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G9"
+ }
+ },
+ "name_pattern": "G9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "7",
+ "name": "G10",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G10"
+ }
+ },
+ "name_pattern": "G10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "7",
+ "name": "G11",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G11"
+ }
+ },
+ "name_pattern": "G11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "7",
+ "name": "G12",
+ "row_idx": "6",
+ "row_name": "G"
+ },
+ "properties": {
+ "name": "G12"
+ }
+ },
+ "name_pattern": "G12"
+ }
+ ]
+ },
+ {
+ "relationship_type": "contains",
+ "child_templates": [
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "8",
+ "name": "H1",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H1"
+ }
+ },
+ "name_pattern": "H1"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "1",
+ "col_name": "8",
+ "name": "H2",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H2"
+ }
+ },
+ "name_pattern": "H2"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "2",
+ "col_name": "8",
+ "name": "H3",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H3"
+ }
+ },
+ "name_pattern": "H3"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "3",
+ "col_name": "8",
+ "name": "H4",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H4"
+ }
+ },
+ "name_pattern": "H4"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "4",
+ "col_name": "8",
+ "name": "H5",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H5"
+ }
+ },
+ "name_pattern": "H5"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "5",
+ "col_name": "8",
+ "name": "H6",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H6"
+ }
+ },
+ "name_pattern": "H6"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "6",
+ "col_name": "8",
+ "name": "H7",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H7"
+ }
+ },
+ "name_pattern": "H7"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "7",
+ "col_name": "8",
+ "name": "H8",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H8"
+ }
+ },
+ "name_pattern": "H8"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "8",
+ "col_name": "8",
+ "name": "H9",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H9"
+ }
+ },
+ "name_pattern": "H9"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "9",
+ "col_name": "8",
+ "name": "H10",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H10"
+ }
+ },
+ "name_pattern": "H10"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "10",
+ "col_name": "8",
+ "name": "H11",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H11"
+ }
+ },
+ "name_pattern": "H11"
+ },
+ {
+ "template_code": "container/well/fixed-plate-well/*/",
+ "json_addl": {
+ "cont_address": {
+ "col_idx": "11",
+ "col_name": "8",
+ "name": "H12",
+ "row_idx": "7",
+ "row_name": "H"
+ },
+ "properties": {
+ "name": "H12"
+ }
+ },
+ "name_pattern": "H12"
+ }
+ ]
+ }
+ ],
+ "properties": {
+ "comments": "",
+ "lab_code": "",
+ "lot_expiration_date": "",
+ "lot_number": "",
+ "manufacturer": "",
+ "name": "Sequencing Index Plate 96",
+ "plate_role": "sequencing_index"
+ },
+ "singleton": "0",
+ "valid_content": [
+ "none"
+ ],
+ "valid_parents": [],
+ "semantic_category": "container"
+ }
+ },
+ {
+ "name": "Generic Reagent Bottle",
+ "polymorphic_discriminator": "container_template",
+ "category": "BCB",
+ "type": "bottle",
+ "subtype": "generic",
+ "version": "1.0",
+ "instance_prefix": "BCB",
+ "instance_polymorphic_identity": "container_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "action_groups": {},
+ "action_imports": {
+ "add_relationships": "BAC/core/add-relationships/1.0",
+ "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "BAC/core/print_barcode_label/1.0",
+ "set_object_status": "BAC/core/set_object_status/1.0"
+ },
+ "cogs": {
+ "allocation_type": "",
+ "cost": "1.50",
+ "cost_split_by_children": [
+ {
+ "*/*/*/*": {}
+ }
+ ],
+ "state": "active"
+ },
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "",
+ "name": "",
+ "row_idx": "0",
+ "row_name": ""
+ },
+ "description": "Generic 10ml tube",
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "instantiation_layouts": [],
+ "properties": {
+ "comments": "",
+ "lab_code": "",
+ "lot_expiration_date": "",
+ "lot_number": "",
+ "manufacturer": "",
+ "manufacturer_other": "",
+ "name": "Generic Reagent Bottle",
+ "container_role": "bottle"
+ },
+ "valid_content": [
+ "content/.*"
+ ],
+ "valid_parents": [],
+ "semantic_category": "container"
+ }
+ },
+ {
+ "name": "Flowcell",
+ "polymorphic_discriminator": "container_template",
+ "category": "BCF",
+ "type": "flowcell",
+ "subtype": "generic",
+ "version": "1.0",
+ "instance_prefix": "BCF",
+ "instance_polymorphic_identity": "container_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "action_groups": {},
+ "action_imports": {
+ "add_relationships": "BAC/core/add-relationships/1.0",
+ "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "BAC/core/print_barcode_label/1.0",
+ "set_object_status": "BAC/core/set_object_status/1.0"
+ },
+ "cogs": {
+ "allocation_type": "",
+ "cost": "1.50",
+ "cost_split_by_children": [
+ {
+ "*/*/*/*": {}
+ }
+ ],
+ "state": "active"
+ },
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "",
+ "name": "",
+ "row_idx": "0",
+ "row_name": ""
+ },
+ "description": "Generic 10ml tube",
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "instantiation_layouts": [],
+ "properties": {
+ "name": "Flowcell",
+ "platform": "",
+ "flowcell_id": "",
+ "manufacturer": "",
+ "lot_number": "",
+ "comments": "",
+ "lab_code": ""
+ },
+ "valid_content": [
+ "content/.*"
+ ],
+ "valid_parents": [],
+ "semantic_category": "container"
+ }
+ },
+ {
+ "name": "Flowcell Lane",
+ "polymorphic_discriminator": "container_template",
+ "category": "BCE",
+ "type": "flowcell_lane",
+ "subtype": "generic",
+ "version": "1.0",
+ "instance_prefix": "BCE",
+ "instance_polymorphic_identity": "container_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "action_groups": {},
+ "action_imports": {
+ "set_object_status": "BAC/core/set_object_status/1.0"
+ },
+ "cogs": {
+ "allocation_type": "",
+ "cost": "0.00",
+ "cost_split_by_children": [
+ {
+ "*/*/*/*": {}
+ }
+ ],
+ "state": "active"
+ },
+ "cont_address": {
+ "col_idx": "0",
+ "col_name": "",
+ "row_idx": "0",
+ "row_name": ""
+ },
+ "description": "plate well - fixed",
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "instantiation_layouts": [],
+ "properties": {
+ "name": "Flowcell Lane",
+ "flowcell_euid": "",
+ "lane": "",
+ "lane_index": "",
+ "comments": "",
+ "lab_code": ""
+ },
+ "singleton": "0",
+ "valid_content": [
+ "content/.*"
+ ],
+ "valid_parents": [
+ "container/plate/fixed-plate.*?/.*?"
+ ],
+ "semantic_category": "container"
+ }
+ },
+ {
+ "name": "Saliva Specimen",
+ "polymorphic_discriminator": "content_template",
+ "category": "BNA",
+ "type": "specimen",
+ "subtype": "saliva",
+ "version": "1.0",
+ "instance_prefix": "BNA",
+ "instance_polymorphic_identity": "content_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "description": "Buccal Swab",
+ "instantiation_layouts": [],
+ "cogs": {
+ "state": "active",
+ "cost": "0.00",
+ "cost_split_by_children": [
+ {
+ "*/*/*/*": {}
+ }
+ ],
+ "allocation_type": ""
+ },
+ "properties": {
+ "name": "Saliva Specimen",
+ "volume": "",
+ "volume_units": "",
+ "comments": "",
+ "lab_code": ""
+ },
+ "expected_inputs": [],
+ "singleton": "0",
+ "expected_outputs": [],
+ "actions": {},
+ "semantic_category": "content"
+ }
+ },
+ {
+ "name": "Sequencing Library Content",
+ "polymorphic_discriminator": "content_template",
+ "category": "BNQ",
+ "type": "sample",
+ "subtype": "sequencing-library",
+ "version": "1.0",
+ "instance_prefix": "BNQ",
+ "instance_polymorphic_identity": "content_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "description": "genomic DNA",
+ "properties": {
+ "name": "Sequencing Library Content",
+ "library_type": "",
+ "platform": "",
+ "volume": "",
+ "volume_units": "",
+ "comments": "",
+ "lab_code": ""
+ },
+ "expected_inputs": [],
+ "singleton": "0",
+ "expected_outputs": [],
+ "actions": {},
+ "instantiation_layouts": [],
+ "cogs": {
+ "state": "active",
+ "cost": "0.00",
+ "cost_split_by_children": [
+ {
+ "*/*/*/*": {}
+ }
+ ],
+ "allocation_type": ""
+ },
+ "semantic_category": "content"
+ }
+ },
+ {
+ "name": "Sequencing Library Pool Content",
+ "polymorphic_discriminator": "content_template",
+ "category": "BNP",
+ "type": "pool",
+ "subtype": "sequencing-library",
+ "version": "1.0",
+ "instance_prefix": "BNP",
+ "instance_polymorphic_identity": "content_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "description": "Pool of Contents",
+ "properties": {
+ "name": "Sequencing Library Pool Content",
+ "platform": "",
+ "pool_strategy": "",
+ "member_count": 0,
+ "comments": "",
+ "lab_code": ""
+ },
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "singleton": "0",
+ "actions": {},
+ "instantiation_layouts": [],
+ "cogs": {
+ "state": "active",
+ "cost": "0.00",
+ "cost_split_by_children": [
+ {
+ "*/*/*/*": {}
+ }
+ ],
+ "allocation_type": ""
+ },
+ "semantic_category": "content"
+ }
+ },
+ {
+ "name": "Sequencing Index Reagent Content",
+ "polymorphic_discriminator": "content_template",
+ "category": "BNX",
+ "type": "reagent",
+ "subtype": "sequencing-index",
+ "version": "1.0",
+ "instance_prefix": "BNX",
+ "instance_polymorphic_identity": "content_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "description": "Novaseq sequencing kit",
+ "singleton": "0",
+ "properties": {
+ "name": "Sequencing Index Reagent Content",
+ "index_name": "",
+ "index_sequence": "",
+ "index_set": "",
+ "well_name": "",
+ "plate_euid": "",
+ "volume": "",
+ "volume_units": "",
+ "comments": "",
+ "manufacturer": "",
+ "lot_number": "",
+ "expiration_date": "",
+ "received_date": "",
+ "storage_conditions": "",
+ "qualification_status": "",
+ "lab_code": ""
+ },
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "actions": {},
+ "instantiation_layouts": [],
+ "cogs": {
+ "state": "active",
+ "cost": "1.00",
+ "cost_split_by_children": [
+ {
+ "*/*/*/*": {}
+ }
+ ],
+ "allocation_type": ""
+ },
+ "semantic_category": "content"
+ }
+ },
+ {
+ "name": "gDNA Quantification Data",
+ "polymorphic_discriminator": "data_template",
+ "category": "BDQ",
+ "type": "quantification",
+ "subtype": "gdna",
+ "version": "1.0",
+ "instance_prefix": "BDQ",
+ "instance_polymorphic_identity": "data_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "action_groups": {},
+ "action_imports": {
+ "add_relationships": "BAC/core/add-relationships/1.0",
+ "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
+ "set_object_status": "BAC/core/set_object_status/1.0"
+ },
+ "description": "Generic data record",
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "instantiation_layouts": [],
+ "properties": {
+ "name": "gDNA Quantification Data",
+ "beta_kind": "gdna_quantification",
+ "target_euid": "",
+ "well_euid": "",
+ "well_name": "",
+ "method": "",
+ "concentration": null,
+ "concentration_units": "",
+ "total_yield": null,
+ "yield_units": "",
+ "passed": null,
+ "metadata": {},
+ "idempotency_key": ""
+ },
+ "singleton": "0",
+ "semantic_category": "data"
+ }
+ },
+ {
+ "name": "Extraction Run Evidence",
+ "polymorphic_discriminator": "data_template",
+ "category": "BDX",
+ "type": "operation",
+ "subtype": "extraction",
+ "version": "1.0",
+ "instance_prefix": "BDX",
+ "instance_polymorphic_identity": "data_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "action_groups": {},
+ "action_imports": {
+ "add_relationships": "BAC/core/add-relationships/1.0",
+ "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
+ "set_object_status": "BAC/core/set_object_status/1.0"
+ },
+ "description": "Generic data record",
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "instantiation_layouts": [],
+ "properties": {
+ "name": "Extraction Run Evidence",
+ "beta_kind": "extraction_run",
+ "operation_type": "extraction",
+ "source_specimen_euid": "",
+ "plate_euid": "",
+ "started_at": "",
+ "completed_at": "",
+ "reagent_euids": [],
+ "metadata": {},
+ "idempotency_key": ""
+ },
+ "singleton": "0",
+ "semantic_category": "data"
+ }
+ },
+ {
+ "name": "Extraction QC Run Evidence",
+ "polymorphic_discriminator": "data_template",
+ "category": "BDY",
+ "type": "operation",
+ "subtype": "extraction-qc",
+ "version": "1.0",
+ "instance_prefix": "BDY",
+ "instance_polymorphic_identity": "data_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "action_groups": {},
+ "action_imports": {
+ "add_relationships": "BAC/core/add-relationships/1.0",
+ "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
+ "set_object_status": "BAC/core/set_object_status/1.0"
+ },
+ "description": "Generic data record",
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "instantiation_layouts": [],
+ "properties": {
+ "name": "Extraction QC Run Evidence",
+ "beta_kind": "post_extract_qc_result",
+ "operation_type": "extraction_qc",
+ "extraction_output_euid": "",
+ "metrics": {},
+ "passed": null,
+ "metadata": {},
+ "idempotency_key": ""
+ },
+ "singleton": "0",
+ "semantic_category": "data"
+ }
+ },
+ {
+ "name": "Library Prep Run Evidence",
+ "polymorphic_discriminator": "data_template",
+ "category": "BDP",
+ "type": "operation",
+ "subtype": "library-prep",
+ "version": "1.0",
+ "instance_prefix": "BDP",
+ "instance_polymorphic_identity": "data_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "action_groups": {},
+ "action_imports": {
+ "add_relationships": "BAC/core/add-relationships/1.0",
+ "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
+ "set_object_status": "BAC/core/set_object_status/1.0"
+ },
+ "description": "Generic data record",
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "instantiation_layouts": [],
+ "properties": {
+ "name": "Library Prep Run Evidence",
+ "beta_kind": "library_prep_output",
+ "operation_type": "library_prep",
+ "platform": "",
+ "source_extraction_output_euid": "",
+ "reagent_euids": [],
+ "metadata": {},
+ "idempotency_key": ""
+ },
+ "singleton": "0",
+ "semantic_category": "data"
+ }
+ },
+ {
+ "name": "Pooling Run Evidence",
+ "polymorphic_discriminator": "data_template",
+ "category": "BDN",
+ "type": "operation",
+ "subtype": "pooling",
+ "version": "1.0",
+ "instance_prefix": "BDN",
+ "instance_polymorphic_identity": "data_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "action_groups": {},
+ "action_imports": {
+ "add_relationships": "BAC/core/add-relationships/1.0",
+ "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
+ "set_object_status": "BAC/core/set_object_status/1.0"
+ },
+ "description": "Generic data record",
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "instantiation_layouts": [],
+ "properties": {
+ "name": "Pooling Run Evidence",
+ "beta_kind": "pooling_run",
+ "operation_type": "pooling",
+ "platform": "",
+ "member_euids": [],
+ "pool_euid": "",
+ "metadata": {},
+ "idempotency_key": ""
+ },
+ "singleton": "0",
+ "semantic_category": "data"
+ }
+ },
+ {
+ "name": "Library Index Assignment Data",
+ "polymorphic_discriminator": "data_template",
+ "category": "BDA",
+ "type": "library-index-assignment",
+ "subtype": "sequencing-library",
+ "version": "1.0",
+ "instance_prefix": "BDA",
+ "instance_polymorphic_identity": "data_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "action_groups": {},
+ "action_imports": {
+ "add_relationships": "BAC/core/add-relationships/1.0",
+ "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
+ "set_object_status": "BAC/core/set_object_status/1.0"
+ },
+ "description": "Generic data record",
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "instantiation_layouts": [],
+ "properties": {
+ "name": "Library Index Assignment Data",
+ "beta_kind": "sequenced_library_assignment",
+ "flowcell_id": "",
+ "lane": "",
+ "library_barcode": "",
+ "library_prep_output_euid": "",
+ "library_material_euid": "",
+ "barcode_reagent_euid": "",
+ "metadata": {},
+ "idempotency_key": ""
+ },
+ "singleton": "0",
+ "semantic_category": "data"
+ }
+ },
+ {
+ "name": "Transfer Execution Data",
+ "polymorphic_discriminator": "data_template",
+ "category": "BDT",
+ "type": "execution",
+ "subtype": "transfer",
+ "version": "1.0",
+ "instance_prefix": "BDT",
+ "instance_polymorphic_identity": "data_instance",
+ "bstatus": "active",
+ "is_singleton": false,
+ "json_addl": {
+ "action_groups": {},
+ "action_imports": {
+ "add_relationships": "BAC/core/add-relationships/1.0",
+ "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
+ "set_object_status": "BAC/core/set_object_status/1.0"
+ },
+ "description": "Generic data record",
+ "expected_inputs": [],
+ "expected_outputs": [],
+ "instantiation_layouts": [],
+ "properties": {
+ "name": "Transfer Execution Data",
+ "beta_kind": "transfer_execution",
+ "source_euid": "",
+ "destination_euid": "",
+ "transfer_type": "",
+ "status": "",
+ "metadata": {},
+ "idempotency_key": ""
+ },
+ "singleton": "0",
+ "semantic_category": "data"
+ }
}
]
}
diff --git a/tests/test_bloom_prefix_taxonomy.py b/tests/test_bloom_prefix_taxonomy.py
new file mode 100644
index 0000000..119c60a
--- /dev/null
+++ b/tests/test_bloom_prefix_taxonomy.py
@@ -0,0 +1,162 @@
+"""Bloom prefix taxonomy and wet-lab template contract tests."""
+
+from __future__ import annotations
+
+import json
+from pathlib import Path
+
+import pytest
+
+from bloom_lims.core.validation import ValidationError, validate_euid
+
+
+PROJECT_ROOT = Path(__file__).resolve().parents[1]
+FORBIDDEN_PREFIX_CHARS = set("ILOU")
+
+
+def _template_pack() -> dict:
+ return json.loads(
+ (
+ PROJECT_ROOT / "config" / "tapdb_templates" / "bloom" / "templates.json"
+ ).read_text(encoding="utf-8")
+ )
+
+
+def _templates_by_code() -> dict[str, dict]:
+ templates: dict[str, dict] = {}
+ for template in _template_pack()["templates"]:
+ semantic_category = template["json_addl"].get("semantic_category")
+ code = (
+ f"{semantic_category}/{template['type']}/"
+ f"{template['subtype']}/{template['version']}"
+ )
+ templates[code] = template
+ return templates
+
+
+def test_wet_lab_templates_use_bloom_prefix_taxonomy() -> None:
+ templates = _templates_by_code()
+
+ expected_prefixes = {
+ "container/tube/tube-generic-10ml/1.0": "BCT",
+ "container/plate/fixed-plate-96/1.0": "BCP",
+ "container/plate/sequencing-library-plate-96/1.0": "BCP",
+ "container/plate/index-plate-96/1.0": "BCP",
+ "container/well/fixed-plate-well/1.0": "BCW",
+ "container/bottle/generic/1.0": "BCB",
+ "container/flowcell/generic/1.0": "BCF",
+ "container/flowcell_lane/generic/1.0": "BCE",
+ "content/specimen/blood-whole/1.0": "BNB",
+ "content/specimen/buccal-swab/1.0": "BNS",
+ "content/specimen/saliva/1.0": "BNA",
+ "content/sample/gdna/1.0": "BNG",
+ "content/sample/cfdna/1.0": "BNC",
+ "content/sample/sequencing-library/1.0": "BNQ",
+ "content/pool/sequencing-library/1.0": "BNP",
+ "content/reagent/sequencing-index/1.0": "BNX",
+ "data/generic/gdna-quantification/1.0": "BDQ",
+ "data/quantification/gdna/1.0": "BDQ",
+ "data/operation/extraction/1.0": "BDX",
+ "data/operation/extraction-qc/1.0": "BDY",
+ "data/operation/library-prep/1.0": "BDP",
+ "data/operation/pooling/1.0": "BDN",
+ "data/library-index-assignment/sequencing-library/1.0": "BDA",
+ "data/execution/transfer/1.0": "BDT",
+ "generic/generic/external_object_link/1.0": "BGX",
+ }
+
+ for code, expected_prefix in expected_prefixes.items():
+ template = templates[code]
+ assert template["category"] == expected_prefix
+ assert template["instance_prefix"] == expected_prefix
+
+
+def test_prefix_taxonomy_rejects_forbidden_letters_and_leading_zero_examples() -> None:
+ prefixes = {
+ template["instance_prefix"]
+ for template in _template_pack()["templates"]
+ if template.get("instance_prefix")
+ }
+ registry = json.loads(
+ (
+ PROJECT_ROOT / "bloom_lims" / "etc" / "prefix_ownership_registry.json"
+ ).read_text(encoding="utf-8")
+ )
+ prefixes.update(registry["ownership"]["Z"])
+
+ assert all(not (set(prefix) & FORBIDDEN_PREFIX_CHARS) for prefix in prefixes)
+ for bad_prefix in ("BCL", "BRI", "BRO", "BRU", "BNL", "BDL"):
+ assert bad_prefix not in prefixes
+
+ assert validate_euid("BCP1")
+ assert validate_euid("BD1")
+ with pytest.raises(ValidationError, match="No leading zeros"):
+ validate_euid("BCP01")
+
+
+def test_prefixes_are_declared_in_packaged_ownership_registry() -> None:
+ registry = json.loads(
+ (
+ PROJECT_ROOT / "bloom_lims" / "etc" / "prefix_ownership_registry.json"
+ ).read_text(encoding="utf-8")
+ )
+ claims = registry["ownership"]["Z"]
+
+ for prefix in {
+ "BC",
+ "BCT",
+ "BCP",
+ "BCW",
+ "BCB",
+ "BCF",
+ "BCE",
+ "BCR",
+ "BN",
+ "BNB",
+ "BNS",
+ "BNA",
+ "BNG",
+ "BNC",
+ "BNQ",
+ "BNP",
+ "BNR",
+ "BNX",
+ "BNK",
+ "BD",
+ "BDQ",
+ "BDX",
+ "BDY",
+ "BDP",
+ "BDN",
+ "BDA",
+ "BDT",
+ "BR",
+ "BRM",
+ "BRN",
+ "BRT",
+ "BRP",
+ "BRC",
+ "BG",
+ "BGX",
+ "BGM",
+ "BGP",
+ "BGV",
+ "BGR",
+ "BGS",
+ }:
+ assert claims[prefix]["issuer_app_code"] == "bloom"
+
+
+def test_readme_documents_taxonomy_and_historical_object_rule() -> None:
+ readme = (PROJECT_ROOT / "README.md").read_text(encoding="utf-8")
+
+ for snippet in (
+ "BC*` | Containers",
+ "BN*` | Contents, materials, and reagents",
+ "BD*` | Data and evidence objects",
+ "BR*` | Runs and executions",
+ "BG*` | Generic helpers and external-object mappings",
+ "Existing historical objects keep their already minted EUIDs",
+ "Prefixes are governance and display labels only",
+ ):
+ assert snippet in readme
diff --git a/tests/test_queue_flow.py b/tests/test_queue_flow.py
index 071959f..c5e508b 100644
--- a/tests/test_queue_flow.py
+++ b/tests/test_queue_flow.py
@@ -249,8 +249,8 @@ def test_beta_queue_flow_end_to_end():
extraction_body["atlas_test_fulfillment_item_euid"]
== atlas_context["fulfillment_items"][0]["atlas_test_fulfillment_item_euid"]
)
- _assert_domain_scoped_euid(extraction_body["extraction_batch_euid"], "BDT-")
- _assert_domain_scoped_euid(extraction_body["extraction_run_euid"], "BDT-")
+ _assert_domain_scoped_euid(extraction_body["extraction_batch_euid"], "BDX-")
+ _assert_domain_scoped_euid(extraction_body["extraction_run_euid"], "BDX-")
extraction_output_euid = extraction_body["extraction_output_euid"]
extraction_batch_euid = extraction_body["extraction_batch_euid"]
extraction_run_euid = extraction_body["extraction_run_euid"]
@@ -281,7 +281,7 @@ def test_beta_queue_flow_end_to_end():
qc_body = qc.json()
assert qc_body["current_queue"] == "ilmn_lib_prep"
assert qc_body["next_queue"] == "ilmn_lib_prep"
- _assert_domain_scoped_euid(qc_body["qc_record_euid"], "BDT-")
+ _assert_domain_scoped_euid(qc_body["qc_record_euid"], "BDY-")
ont_library_prep = client.post(
"/api/v1/external/atlas/beta/library-prep",
@@ -316,10 +316,10 @@ def test_beta_queue_flow_end_to_end():
library_container_euid = library_body["library_container_euid"]
library_plate_euid = library_body["library_plate_euid"]
library_well_euid = library_body["library_well_euid"]
- _assert_domain_scoped_euid(library_material_euid, "BCT-")
- _assert_domain_scoped_euid(library_container_euid, "BCN-")
- _assert_domain_scoped_euid(library_plate_euid, "BCN-")
- _assert_domain_scoped_euid(library_well_euid, "BCN-")
+ _assert_domain_scoped_euid(library_material_euid, "BNQ-")
+ _assert_domain_scoped_euid(library_container_euid, "BCP-")
+ _assert_domain_scoped_euid(library_plate_euid, "BCP-")
+ _assert_domain_scoped_euid(library_well_euid, "BCW-")
library_qc = client.post(
"/api/v1/external/atlas/beta/library-qc",
@@ -337,7 +337,7 @@ def test_beta_queue_flow_end_to_end():
assert library_qc_body["qc_passed"] is True
assert library_qc_body["next_queue"] == "ilmn_seq_pool"
assert library_qc_body["current_queue"] == "ilmn_seq_pool"
- _assert_domain_scoped_euid(library_qc_body["qc_record_euid"], "BDT-")
+ _assert_domain_scoped_euid(library_qc_body["qc_record_euid"], "BDP-")
pool = client.post(
"/api/v1/external/atlas/beta/pools",
@@ -367,7 +367,7 @@ def test_beta_queue_flow_end_to_end():
json={
"pool_euid": pool_euid,
"platform": "ILMN",
- "run_subtype": "novaseq",
+ "run_subtype": "illumina",
"flowcell_id": flowcell_id,
"run_name": "beta-ilmn-run",
"status": "completed",
@@ -402,7 +402,7 @@ def test_beta_queue_flow_end_to_end():
assert run_body["artifact_count"] == 1
assert run_body["assignment_count"] == 1
assert run_body["flowcell_id"] == flowcell_id
- assert run_body["run_subtype"] == "novaseq"
+ assert run_body["run_subtype"] == "illumina"
assert run_body["operator_start_datetime"] == "2026-05-20T06:00:00Z"
assert run_body["sequencing_end_datetime"] == "2026-05-20T14:30:00Z"
assert run_body["instrument_euid"] == instrument_euid
@@ -421,9 +421,9 @@ def test_beta_queue_flow_end_to_end():
)
run_props = (run_instance.json_addl or {}).get("properties", {})
assert run_instance.type == "sequencing_run"
- assert run_instance.subtype == "novaseq"
+ assert run_instance.subtype == "illumina"
assert run_props["beta_kind"] == "sequencing_run"
- assert run_props["run_subtype"] == "novaseq"
+ assert run_props["run_subtype"] == "illumina"
assert run_props["operator_start_datetime"] == "2026-05-20T06:00:00+00:00"
assert run_props["sequencing_end_datetime"] == "2026-05-20T14:30:00+00:00"
assert run_props["instrument_euid"] == instrument_euid
diff --git a/tests/test_sequencing_run_contract.py b/tests/test_sequencing_run_contract.py
index 14c04b4..cb6d1c2 100644
--- a/tests/test_sequencing_run_contract.py
+++ b/tests/test_sequencing_run_contract.py
@@ -16,7 +16,7 @@
def _minimal_run_payload(**overrides):
payload = {
- "pool_euid": "BCT-POOL-1",
+ "pool_euid": "BNP-POOL-1",
"platform": "ILMN",
"run_subtype": "illumina",
"flowcell_id": "FLOW-1",
@@ -26,7 +26,7 @@ def _minimal_run_payload(**overrides):
{
"lane": "1",
"library_barcode": "IDX-1",
- "library_prep_output_euid": "BDT-LIB-1",
+ "library_prep_output_euid": "BDP-LIB-1",
}
],
}
@@ -51,15 +51,21 @@ def test_sequencing_run_templates_are_shipped_for_tapdb_seed():
}
expected = {
- ("data", "sequencing_run", "illumina", "1.0"): "ILMN",
- ("data", "sequencing_run", "ont", "1.0"): "ONT",
- ("data", "sequencing_run", "novaseq", "1.0"): "ILMN",
+ ("data", "sequencing_run", "illumina", "1.0"): ("ILMN", "BRM"),
+ ("data", "sequencing_run", "ont", "1.0"): ("ONT", "BRN"),
+ ("data", "sequencing_run", "ultima", "1.0"): ("Ultima", "BRT"),
+ ("data", "sequencing_run", "completegenomics", "1.0"): (
+ "CompleteGenomics",
+ "BRC",
+ ),
+ ("data", "sequencing_run", "pacbio", "1.0"): ("PacBio", "BRP"),
}
- for template_key, platform in expected.items():
+ for template_key, (platform, instance_prefix) in expected.items():
template = templates[template_key]
props = template["json_addl"]["properties"]
- assert template["category"] == "BDT"
- assert template["instance_prefix"] == "BDT"
+ assert template["category"] == instance_prefix
+ assert template["instance_prefix"] == instance_prefix
+ assert template["json_addl"]["semantic_category"] == "data"
assert props["beta_kind"] == "sequencing_run"
assert props["platform"] == platform
assert props["run_subtype"] == template_key[2]
@@ -69,18 +75,24 @@ def test_sequencing_run_templates_are_shipped_for_tapdb_seed():
def test_run_schema_validates_subtype_platform_and_datetime_contract():
- novaseq = BetaRunCreateRequest.model_validate(
- _minimal_run_payload(run_subtype="novaseq")
- )
- assert novaseq.run_subtype == "novaseq"
-
- ont = BetaRunCreateRequest.model_validate(
- _minimal_run_payload(platform="ONT", run_subtype="ont")
- )
- assert ont.platform == "ONT"
+ expected = {
+ "ILMN": "illumina",
+ "ONT": "ont",
+ "Ultima": "ultima",
+ "PacBio": "pacbio",
+ "CompleteGenomics": "completegenomics",
+ }
+ for platform, run_subtype in expected.items():
+ run = BetaRunCreateRequest.model_validate(
+ _minimal_run_payload(platform=platform, run_subtype=run_subtype)
+ )
+ assert run.platform == platform
+ assert run.run_subtype == run_subtype
with pytest.raises(ValidationError, match="platform=ONT requires run_subtype=ont"):
- BetaRunCreateRequest.model_validate(_minimal_run_payload(platform="ONT"))
+ BetaRunCreateRequest.model_validate(
+ _minimal_run_payload(platform="ONT", run_subtype="illumina")
+ )
with pytest.raises(ValidationError, match="must include a timezone"):
BetaRunCreateRequest.model_validate(
From 3bfa5b5f7f4078cf25d92b12fbfbd29e31c27dcf Mon Sep 17 00:00:00 2001
From: John Major
Date: Tue, 2 Jun 2026 00:43:03 -0700
Subject: [PATCH 08/47] Repair Bloom EUID actions and retire queue GUI
---
bloom_lims/config/action/core.json | 58 +++++++++++++++++++--
bloom_lims/gui/actions.py | 39 +++++++++++++-
bloom_lims/gui/routes/operations.py | 23 ++++++--
templates/modern/base.html | 3 --
templates/modern/dashboard.html | 42 ---------------
templates/modern/euid_details.html | 44 +++++++---------
templates/modern/queue_retired.html | 28 ++++++++++
tests/test_action_button_template_safety.py | 7 +++
tests/test_action_schema_hydration.py | 54 +++++++++++++++++++
tests/test_gui_endpoints.py | 17 +++---
10 files changed, 229 insertions(+), 86 deletions(-)
create mode 100644 templates/modern/queue_retired.html
diff --git a/bloom_lims/config/action/core.json b/bloom_lims/config/action/core.json
index 5951321..dff7c65 100644
--- a/bloom_lims/config/action/core.json
+++ b/bloom_lims/config/action/core.json
@@ -47,7 +47,7 @@
"label_style": ""
},
"curr_user": "",
- "description": "Print Label2",
+ "description": "Print Label",
"ui_schema": {
"title": "Print Label",
"fields": []
@@ -78,7 +78,58 @@
"description": "Add Parent or Child Relationships (aka lineages).",
"ui_schema": {
"title": "Add Parent or Child Relationship(s)",
- "fields": []
+ "fields": [
+ {
+ "name": "lineage_type_to_create",
+ "label": "Create Relationship As",
+ "type": "select",
+ "required": true,
+ "options": [
+ {"value": "parent", "label": "parent"},
+ {"value": "child", "label": "child"}
+ ]
+ },
+ {
+ "name": "relationship_type",
+ "label": "Relationship Type",
+ "type": "select",
+ "required": true,
+ "options": [
+ {"value": "contains", "label": "contains"},
+ {"value": "derived_from", "label": "derived_from"},
+ {"value": "aliquot_of", "label": "aliquot_of"},
+ {"value": "prepared_from", "label": "prepared_from"},
+ {"value": "member_of", "label": "member_of"},
+ {"value": "has_external_reference", "label": "has_external_reference"},
+ {"value": "beta_extraction_batch_run", "label": "beta_extraction_batch_run"},
+ {"value": "beta_extraction_run_input", "label": "beta_extraction_run_input"},
+ {"value": "beta_extraction_plate", "label": "beta_extraction_plate"},
+ {"value": "beta_extraction_well", "label": "beta_extraction_well"},
+ {"value": "beta_extraction_output", "label": "beta_extraction_output"},
+ {"value": "beta_extraction_run_output", "label": "beta_extraction_run_output"},
+ {"value": "beta_post_extract_qc", "label": "beta_post_extract_qc"},
+ {"value": "beta_library_prep_output", "label": "beta_library_prep_output"},
+ {"value": "beta_library_material_output", "label": "beta_library_material_output"},
+ {"value": "beta_library_qc", "label": "beta_library_qc"},
+ {"value": "beta_pooling_run_output", "label": "beta_pooling_run_output"},
+ {"value": "beta_pool_member", "label": "beta_pool_member"},
+ {"value": "beta_pooling_run_input", "label": "beta_pooling_run_input"},
+ {"value": "beta_sequencing_run", "label": "beta_sequencing_run"},
+ {"value": "beta_sequenced_library_assignment", "label": "beta_sequenced_library_assignment"},
+ {"value": "beta_assignment_source", "label": "beta_assignment_source"},
+ {"value": "beta_assignment_library_material", "label": "beta_assignment_library_material"},
+ {"value": "beta_assignment_barcode_reagent", "label": "beta_assignment_barcode_reagent"},
+ {"value": "beta_run_artifact", "label": "beta_run_artifact"}
+ ]
+ },
+ {
+ "name": "euids",
+ "label": "EUIDs (one per line)",
+ "type": "textarea",
+ "required": true,
+ "rows": 6
+ }
+ ]
}
}
}
@@ -90,7 +141,8 @@
"method_name": "do_action_create_subject_and_anchor",
"action_executed": "0",
"max_executions": "-1",
- "action_enabled": "1",
+ "action_enabled": "0",
+ "action_visible": "0",
"capture_data": "yes",
"captured_data": {},
"deactivate_actions_when_executed": [],
diff --git a/bloom_lims/gui/actions.py b/bloom_lims/gui/actions.py
index 32d7cdb..a41d394 100644
--- a/bloom_lims/gui/actions.py
+++ b/bloom_lims/gui/actions.py
@@ -4,6 +4,34 @@
from bloom_lims.domain import BloomObj
+RELATIONSHIP_TYPE_OPTIONS = [
+ {"value": "contains", "label": "contains"},
+ {"value": "derived_from", "label": "derived_from"},
+ {"value": "aliquot_of", "label": "aliquot_of"},
+ {"value": "prepared_from", "label": "prepared_from"},
+ {"value": "member_of", "label": "member_of"},
+ {"value": "has_external_reference", "label": "has_external_reference"},
+ {"value": "beta_extraction_batch_run", "label": "beta_extraction_batch_run"},
+ {"value": "beta_extraction_run_input", "label": "beta_extraction_run_input"},
+ {"value": "beta_extraction_plate", "label": "beta_extraction_plate"},
+ {"value": "beta_extraction_well", "label": "beta_extraction_well"},
+ {"value": "beta_extraction_output", "label": "beta_extraction_output"},
+ {"value": "beta_extraction_run_output", "label": "beta_extraction_run_output"},
+ {"value": "beta_post_extract_qc", "label": "beta_post_extract_qc"},
+ {"value": "beta_library_prep_output", "label": "beta_library_prep_output"},
+ {"value": "beta_library_material_output", "label": "beta_library_material_output"},
+ {"value": "beta_library_qc", "label": "beta_library_qc"},
+ {"value": "beta_pooling_run_output", "label": "beta_pooling_run_output"},
+ {"value": "beta_pool_member", "label": "beta_pool_member"},
+ {"value": "beta_pooling_run_input", "label": "beta_pooling_run_input"},
+ {"value": "beta_sequencing_run", "label": "beta_sequencing_run"},
+ {"value": "beta_sequenced_library_assignment", "label": "beta_sequenced_library_assignment"},
+ {"value": "beta_assignment_source", "label": "beta_assignment_source"},
+ {"value": "beta_assignment_library_material", "label": "beta_assignment_library_material"},
+ {"value": "beta_assignment_barcode_reagent", "label": "beta_assignment_barcode_reagent"},
+ {"value": "beta_run_artifact", "label": "beta_run_artifact"},
+]
+
def _normalize_action_slug(action_data: dict) -> str:
method_name = str(action_data.get("method_name") or "").strip()
@@ -46,8 +74,9 @@ def _default_ui_fields_for_action(action_data: dict) -> list[dict]:
{
"name": "relationship_type",
"label": "Relationship Type",
- "type": "text",
+ "type": "select",
"required": True,
+ "options": RELATIONSHIP_TYPE_OPTIONS,
},
{
"name": "euids",
@@ -74,9 +103,15 @@ def hydrate_dynamic_action_groups(action_groups: dict, bobdb: BloomObj) -> dict:
actions = group_data.get("actions", {})
if not isinstance(actions, dict):
continue
- for action_data in actions.values():
+ for action_key, action_data in list(actions.items()):
if not isinstance(action_data, dict):
continue
+ if (
+ action_data.get("action_visible") == "0"
+ or _normalize_action_slug(action_data) == "create_subject_and_anchor"
+ ):
+ actions.pop(action_key, None)
+ continue
captured = action_data.get("captured_data")
if not isinstance(captured, dict):
captured = {}
diff --git a/bloom_lims/gui/routes/operations.py b/bloom_lims/gui/routes/operations.py
index 518e540..550124b 100644
--- a/bloom_lims/gui/routes/operations.py
+++ b/bloom_lims/gui/routes/operations.py
@@ -547,13 +547,30 @@ async def update_preference(request: Request, auth: dict = Depends(require_auth)
@router.get("/queue_details", response_class=HTMLResponse)
async def queue_details(
- request: Request, queue_euid, page=1, _auth=Depends(require_auth)
+ request: Request,
+ queue_euid: str | None = Query(default=None),
+ euid: str | None = Query(default=None),
+ page=1,
+ _auth=Depends(require_auth),
):
+ queue_euid = str(queue_euid or euid or "").strip()
+ user_data = request.session.get("user_data", {})
+ if not queue_euid:
+ template = templates.get_template("modern/queue_retired.html")
+ return HTMLResponse(
+ content=template.render(
+ {
+ "request": request,
+ "udat": user_data,
+ "queue_euid": "",
+ }
+ )
+ )
+
page = int(page)
if page < 1:
page = 1
per_page = 500
- user_logged_in = True if "user_data" in request.session else False
bobdb = BloomObj(BLOOMdb3(app_username=request.session["user_data"]["email"]))
queue = bobdb.get_by_euid(queue_euid)
qm = []
@@ -563,8 +580,6 @@ async def queue_details(
queue_details = queue.sort_by_euid(qm)
queue_details_list = queue_details[(page - 1) * per_page : page * per_page]
pagination = {"next": page + 1, "prev": page - 1, "euid": queue_euid}
- user_data = request.session.get("user_data", {})
-
queue.items = queue_details_list
template = templates.get_template("modern/queue_details.html")
diff --git a/templates/modern/base.html b/templates/modern/base.html
index f85249d..ecdb0da 100644
--- a/templates/modern/base.html
+++ b/templates/modern/base.html
@@ -63,9 +63,6 @@
Dashboard
-
- Queue Runtime
-
Equipment
diff --git a/templates/modern/dashboard.html b/templates/modern/dashboard.html
index 27ee403..dd56dc1 100644
--- a/templates/modern/dashboard.html
+++ b/templates/modern/dashboard.html
@@ -17,16 +17,6 @@ Dashboard
Set name
-
+
Member EUIDs
-
+
External member EUIDs/IDs
-
-
+
+
Create Set
@@ -177,12 +187,12 @@ Plate-Well Data
Plate EUID
-
+
Data template code
-
+
Data records
-
-
+
+
Associate Data To Wells
@@ -198,12 +208,12 @@ Spreadsheet Upload
Upload `.xlsx` or `.csv` sheets for Extraction Plate, Extraction QC, Seq Library Plate, Seq Pool,
Seq Run Set, Sets, or Plate Well Data. Bulk Create, Transfer, and Annotation sheets are parsed as previews.
-
+
-
+
Execute actions now
-
+
Upload Spreadsheet
@@ -215,22 +225,22 @@ Print EUID Barcodes
EUIDs to print
-
+
-
+
Print Selected EUIDs
@@ -242,7 +252,7 @@ Action Results
{% endblock %}
@@ -265,7 +275,8 @@ Action Results
links.appendChild(link(`/api/v1/lab-actions/plates/${payload.plate_euid}/mapping.csv`, 'Download plate CSV'));
}
if (payload.set_euid) {
- links.appendChild(link(`/api/v1/lab-actions/seq-runs/${payload.set_euid}/samplesheet`, 'Download ILMN sample sheet'));
+ const platform = payload.platform || document.getElementById('run-platform').value || 'sequencing';
+ links.appendChild(link(`/api/v1/lab-actions/seq-runs/${payload.set_euid}/samplesheet`, `Download ${platform} sample sheet`));
}
const euids = [];
['new_container_euids', 'created_euids'].forEach((key) => {
@@ -325,6 +336,17 @@ Action Results
return data;
}
+ function keyValueData(pairs) {
+ const data = {};
+ pairs.forEach((pair) => {
+ const [key, value] = pair.split('=');
+ if (key && value !== undefined) {
+ data[key.trim()] = value.trim();
+ }
+ });
+ return data;
+ }
+
function assignmentRows(textareaId) {
return document.getElementById(textareaId).value
.split(/\r?\n/)
@@ -333,19 +355,33 @@ Action Results
.map((line) => {
const [position, status, ...pairs] = line.split(',').map((value) => value.trim());
const match = position.match(/^([A-Ha-h])(\d{1,2})$/);
- const data = {};
- pairs.forEach((pair) => {
- const [key, value] = pair.split('=');
- if (key && value !== undefined) {
- data[key.trim()] = value.trim();
- }
- });
return {
row: match ? match[1].toUpperCase() : null,
col: match ? Number(match[2]) : null,
status: status || null,
result: status || null,
- data,
+ data: keyValueData(pairs),
+ };
+ });
+ }
+
+ function libraryAssignmentRows(textareaId) {
+ return document.getElementById(textareaId).value
+ .split(/\r?\n/)
+ .map((line) => line.trim())
+ .filter(Boolean)
+ .map((line) => {
+ const [sourceWellEuid, position, indexBarcode, indexEuid, ...pairs] = line
+ .split(',')
+ .map((value) => value.trim());
+ const match = (position || '').match(/^([A-Ha-h])(\d{1,2})$/);
+ return {
+ source_well_euid: sourceWellEuid,
+ row: match ? match[1].toUpperCase() : null,
+ col: match ? Number(match[2]) : null,
+ index_barcode: indexBarcode || null,
+ index_euid: indexEuid || null,
+ data: keyValueData(pairs),
};
});
}
@@ -376,11 +412,21 @@ Action Results
plate_name: document.getElementById('extract-name').value || 'extraction plate',
create_run_set: document.getElementById('extract-run-set').checked,
}),
- 'create-library': async () => postJson('/api/v1/lab-actions/seq-library-plates', {
- mode: 'plate_1_to_1',
- source_plate_euid: document.getElementById('library-source-plate').value.trim(),
- plate_name: document.getElementById('library-name').value || 'seq library plate',
- }),
+ 'create-library': async () => {
+ const assignments = libraryAssignmentRows('library-assignments');
+ if (assignments.length) {
+ return postJson('/api/v1/lab-actions/seq-library-plates', {
+ mode: 'directed',
+ assignments,
+ plate_name: document.getElementById('library-name').value || 'seq library plate',
+ });
+ }
+ return postJson('/api/v1/lab-actions/seq-library-plates', {
+ mode: 'plate_1_to_1',
+ source_plate_euid: document.getElementById('library-source-plate').value.trim(),
+ plate_name: document.getElementById('library-name').value || 'seq library plate',
+ });
+ },
'create-qc': async () => postJson('/api/v1/lab-actions/extraction-qc-plates', {
source_plate_euid: document.getElementById('qc-source-plate').value.trim(),
qc_plate_name: document.getElementById('qc-name').value || 'extraction QC plate',
@@ -394,7 +440,7 @@ Action Results
'create-run': async () => postJson('/api/v1/lab-actions/seq-runs', {
pool_tube_euid: document.getElementById('run-pool-tube').value.trim(),
pool_content_euid: document.getElementById('run-pool-content').value.trim() || null,
- platform: 'ILMN',
+ platform: document.getElementById('run-platform').value,
flowcell_barcode: document.getElementById('run-flowcell').value.trim(),
operator: document.getElementById('run-operator').value.trim(),
status: 'created',
diff --git a/tests/test_lab_actions_api.py b/tests/test_lab_actions_api.py
index 0e3f23f..8a1b081 100644
--- a/tests/test_lab_actions_api.py
+++ b/tests/test_lab_actions_api.py
@@ -213,7 +213,7 @@ def test_lab_actions_full_ilmn_flow_and_csv_export() -> None:
assert library_content in sample_sheet.text
-def test_lab_actions_validation_and_non_ilmn_samplesheet_rejection() -> None:
+def test_lab_actions_validation_and_ont_samplesheet_download() -> None:
client = _client()
invalid = client.post(
"/api/v1/lab-actions/extraction-plates",
@@ -247,8 +247,12 @@ def test_lab_actions_validation_and_non_ilmn_samplesheet_rejection() -> None:
sample_sheet = client.get(
f"/api/v1/lab-actions/seq-runs/{run.json()['set_euid']}/samplesheet"
)
- assert sample_sheet.status_code == 400
- assert "only implemented for ILMN" in sample_sheet.json()["detail"]
+ assert sample_sheet.status_code == 200, sample_sheet.text
+ assert sample_sheet.headers["content-type"].startswith("text/tab-separated-values")
+ assert "_ONT_manifest.tsv" in sample_sheet.headers["content-disposition"]
+ assert "sample_id\talias\tbarcode\trun_set_euid" in sample_sheet.text
+ assert run.json()["set_euid"] in sample_sheet.text
+ assert "ONT-FLOWCELL" in sample_sheet.text
def test_object_creation_count_and_print_euid_mock() -> None:
@@ -310,6 +314,10 @@ def test_lab_actions_gui_renders_wizard() -> None:
assert "Sequencing Pool Tube" in html
assert "Sequencing Run Set" in html
assert "/api/v1/lab-actions/extraction-plates" in html
+ assert 'data-testid="bloom-lab-library-assignments"' in html
+ assert 'data-testid="bloom-lab-run-platform"' in html
+ assert "mode: 'directed'" in html
+ assert "Download ${platform} sample sheet" in html
def test_directed_extraction_into_existing_plate_with_quant_and_reuse_guard() -> None:
From 5861cb33d2b2159d66c4e000bb72b10fe2aa46f5 Mon Sep 17 00:00:00 2001
From: John Major
Date: Thu, 18 Jun 2026 15:54:26 -0700
Subject: [PATCH 40/47] Complete Bloom lab-action live proof support
---
bloom_lims/domain/lab_actions.py | 81 ++++++++++++++++++++++++++++++-
bloom_lims/schemas/lab_actions.py | 1 +
templates/modern/lab_actions.html | 5 ++
tests/test_lab_actions_api.py | 10 +++-
4 files changed, 93 insertions(+), 4 deletions(-)
diff --git a/bloom_lims/domain/lab_actions.py b/bloom_lims/domain/lab_actions.py
index 9c55789..1b1fc6c 100644
--- a/bloom_lims/domain/lab_actions.py
+++ b/bloom_lims/domain/lab_actions.py
@@ -46,6 +46,9 @@
POOL_CONTENT_TEMPLATE_CODE = "content/pool/sequencing-library/1.0/"
GDNA_QUANT_TEMPLATE_CODE = "data/quantification/gdna/1.0/"
EXTRACTION_QC_TEMPLATE_CODE = "data/operation/extraction-qc/1.0/"
+SEQUENCED_LIBRARY_ASSIGNMENT_TEMPLATE_CODE = (
+ "data/library-index-assignment/sequencing-library/1.0/"
+)
def re_split_multi(value: str) -> list[str]:
@@ -795,6 +798,11 @@ def create_seq_run_set(self, request: SeqRunSetRequest) -> dict[str, Any]:
self._create_lineage(run_set.euid, request.instrument_euid, "run_uses_instrument")
for reagent_euid in request.reagent_euids:
self._create_lineage(run_set.euid, reagent_euid, "run_uses_reagent")
+ assignments = self._create_sequenced_library_assignments(
+ run_set=run_set,
+ pool_content=pool_content,
+ flowcell_barcode=request.flowcell_barcode,
+ )
self.bdb.session.commit()
return {
"set_euid": run_set.euid,
@@ -802,8 +810,65 @@ def create_seq_run_set(self, request: SeqRunSetRequest) -> dict[str, Any]:
"platform": request.platform,
"pool_tube_euid": pool_tube.euid,
"pool_content_euid": pool_content.euid,
+ "assignments": assignments,
}
+ def _create_sequenced_library_assignments(
+ self,
+ *,
+ run_set,
+ pool_content,
+ flowcell_barcode: str,
+ ) -> list[dict[str, str]]:
+ assignments: list[dict[str, str]] = []
+ source_libraries = [
+ lineage.parent_instance
+ for lineage in self._lineages_to_child(pool_content, "DERIVED_FROM")
+ ]
+ for index, library in enumerate(source_libraries, start=1):
+ props = self._props(library)
+ barcode = str(props.get("index_barcode") or "").strip()
+ lane = str(props.get("lane") or props.get("lane_index") or "1").strip()
+ assignment = self._create_by_code(
+ SEQUENCED_LIBRARY_ASSIGNMENT_TEMPLATE_CODE,
+ name=f"{run_set.euid}:{lane}:{barcode or library.euid}",
+ properties={
+ "flowcell_id": flowcell_barcode,
+ "lane": lane,
+ "library_barcode": barcode,
+ "library_prep_output_euid": library.euid,
+ "library_material_euid": library.euid,
+ "barcode_reagent_euid": str(props.get("index_euid") or "").strip(),
+ "metadata": {
+ "created_by": "bloom_lab_actions",
+ "pool_content_euid": pool_content.euid,
+ },
+ },
+ )
+ self._create_lineage(
+ run_set.euid,
+ assignment.euid,
+ "beta_sequenced_library_assignment",
+ )
+ self._create_lineage(
+ library.euid,
+ assignment.euid,
+ "beta_assignment_source",
+ edge_type="RUN_CONSUMED",
+ source_role="sequencing_run_set",
+ target_role="library_material",
+ )
+ assignments.append(
+ {
+ "assignment_euid": assignment.euid,
+ "library_content_euid": library.euid,
+ "flowcell_id": flowcell_barcode,
+ "lane": lane,
+ "library_barcode": barcode,
+ }
+ )
+ return assignments
+
def plate_mapping_rows(self, plate_euid: str) -> list[dict[str, str]]:
plate = self._require(plate_euid)
wells = self._plate_wells(plate)
@@ -1302,10 +1367,22 @@ def import_spreadsheet(
return {"filename": filename, "dry_run": dry_run, "actions": actions}
def print_euids(self, request: PrintEuidRequest) -> dict[str, Any]:
- service = ZebraDayService()
results = []
for euid in request.euids:
self._require(euid)
+ if request.dry_run:
+ results.append(
+ {
+ "dry_run": True,
+ "lab": request.lab,
+ "printer_id": request.printer_id,
+ "label_zpl_style": request.label_zpl_style,
+ "euid": euid,
+ "copies": request.copies,
+ }
+ )
+ continue
+ service = ZebraDayService()
results.append(
service.submit_print_job(
lab=request.lab,
@@ -1315,4 +1392,4 @@ def print_euids(self, request: PrintEuidRequest) -> dict[str, Any]:
print_n=request.copies,
)
)
- return {"printed": len(results), "results": results}
+ return {"printed": 0 if request.dry_run else len(results), "dry_run": request.dry_run, "results": results}
diff --git a/bloom_lims/schemas/lab_actions.py b/bloom_lims/schemas/lab_actions.py
index 73c281c..9757601 100644
--- a/bloom_lims/schemas/lab_actions.py
+++ b/bloom_lims/schemas/lab_actions.py
@@ -260,6 +260,7 @@ class PrintEuidRequest(BaseModel):
printer_id: str
label_zpl_style: str
copies: int = Field(default=1, ge=1, le=20)
+ dry_run: bool = False
@field_validator("euids")
@classmethod
diff --git a/templates/modern/lab_actions.html b/templates/modern/lab_actions.html
index 71f4c2c..729f562 100644
--- a/templates/modern/lab_actions.html
+++ b/templates/modern/lab_actions.html
@@ -240,6 +240,10 @@ Print EUID Barcodes
+
+
+ Preview only; do not send to printer
+
Print Selected EUIDs
@@ -468,6 +472,7 @@ Action Results
printer_id: document.getElementById('print-printer').value.trim(),
label_zpl_style: document.getElementById('print-style').value.trim(),
copies: 1,
+ dry_run: document.getElementById('print-dry-run').checked,
}),
};
diff --git a/tests/test_lab_actions_api.py b/tests/test_lab_actions_api.py
index 8a1b081..764a4d0 100644
--- a/tests/test_lab_actions_api.py
+++ b/tests/test_lab_actions_api.py
@@ -201,6 +201,9 @@ def test_lab_actions_full_ilmn_flow_and_csv_export() -> None:
assert seq_run.status_code == 200, seq_run.text
run_payload = seq_run.json()
assert run_payload["set_euid"]
+ assert run_payload["assignments"]
+ assert run_payload["assignments"][0]["flowcell_id"] == "PYTEST-FLOWCELL"
+ assert run_payload["assignments"][0]["lane"] == "1"
sample_sheet = client.get(
f"/api/v1/lab-actions/seq-runs/{run_payload['set_euid']}/samplesheet"
@@ -282,11 +285,14 @@ def test_object_creation_count_and_print_euid_mock() -> None:
"printer_id": "pytest-printer",
"label_zpl_style": "euid",
"copies": 1,
+ "dry_run": True,
},
)
assert response.status_code == 200, response.text
- assert response.json()["printed"] == 3
- assert service.submit_print_job.call_count == 3
+ assert response.json()["printed"] == 0
+ assert response.json()["dry_run"] is True
+ assert service.submit_print_job.call_count == 0
+ assert len(response.json()["results"]) == 3
recursive_batch = client.post(
"/api/v1/object-creation/create",
From 56d2961da56859b3b77e521f1e68c107e5c32472 Mon Sep 17 00:00:00 2001
From: John Major
Date: Thu, 18 Jun 2026 16:51:54 -0700
Subject: [PATCH 41/47] Return plate identifiers from lab-action data attach
---
bloom_lims/domain/lab_actions.py | 7 +++++++
tests/test_lab_actions_api.py | 6 +++++-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/bloom_lims/domain/lab_actions.py b/bloom_lims/domain/lab_actions.py
index 1b1fc6c..99fcbdc 100644
--- a/bloom_lims/domain/lab_actions.py
+++ b/bloom_lims/domain/lab_actions.py
@@ -476,8 +476,11 @@ def fill_extraction_qc_plate(
def attach_plate_well_data(self, request: PlateWellDataRequest) -> dict[str, Any]:
mappings: list[dict[str, Any]] = []
+ plate_euids: set[str] = set()
for record in request.records:
well = self._well_for_data_record(record)
+ if record.plate_euid:
+ plate_euids.add(record.plate_euid)
target = well if record.target == "well" else self._well_content(well)
data = self._create_by_code(
request.data_template_code,
@@ -493,6 +496,7 @@ def attach_plate_well_data(self, request: PlateWellDataRequest) -> dict[str, Any
mappings.append(
{
"well_euid": well.euid,
+ "plate_euid": record.plate_euid,
"target_euid": target.euid,
"data_euid": data.euid,
"relationship_type": request.relationship_type,
@@ -505,7 +509,10 @@ def attach_plate_well_data(self, request: PlateWellDataRequest) -> dict[str, Any
member_euids=[item["data_euid"] for item in mappings],
)
self.bdb.session.commit()
+ sorted_plate_euids = sorted(plate_euids)
return {
+ "plate_euid": sorted_plate_euids[0] if len(sorted_plate_euids) == 1 else None,
+ "plate_euids": sorted_plate_euids,
"run_set_euid": run_set.euid if run_set is not None else None,
"mappings": mappings,
}
diff --git a/tests/test_lab_actions_api.py b/tests/test_lab_actions_api.py
index 764a4d0..011a05b 100644
--- a/tests/test_lab_actions_api.py
+++ b/tests/test_lab_actions_api.py
@@ -642,7 +642,11 @@ def test_qc_plate_data_sets_and_pool_from_well_and_tube() -> None:
},
)
assert data.status_code == 200, data.text
- assert data.json()["mappings"][0]["data_euid"]
+ data_payload = data.json()
+ assert data_payload["plate_euid"] == extraction_payload["plate_euid"]
+ assert data_payload["plate_euids"] == [extraction_payload["plate_euid"]]
+ assert data_payload["mappings"][0]["plate_euid"] == extraction_payload["plate_euid"]
+ assert data_payload["mappings"][0]["data_euid"]
lab_set = client.post(
"/api/v1/lab-actions/sets",
From 2d330b9726a51cbd64152590031c889aaf78fb5d Mon Sep 17 00:00:00 2001
From: John Major
Date: Thu, 18 Jun 2026 17:32:40 -0700
Subject: [PATCH 42/47] Record live lab action E2E proof
---
...18T000000Z_bloom_lab_action_flow_ledger.md | 33 +++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/docs/plans/20260618T000000Z_bloom_lab_action_flow_ledger.md b/docs/plans/20260618T000000Z_bloom_lab_action_flow_ledger.md
index 8144825..a2befa9 100644
--- a/docs/plans/20260618T000000Z_bloom_lab_action_flow_ledger.md
+++ b/docs/plans/20260618T000000Z_bloom_lab_action_flow_ledger.md
@@ -81,3 +81,36 @@ Build a Bloom-owned lab actions layer for extraction plates, sequencing library
- No real Zebra Day print job was sent.
- Bloom release, Dayhoff pin update, and Dayhoff double-release are tracked in `dayhoff/docs/plans/20260618T131619Z_bloom_lab_actions_release_train_ledger.md`.
- No live `jemdev5` refresh was performed in this pass.
+
+## 2026-06-19 Live `jemdev5` Proof
+
+The lab-action flow was released as Bloom `7.0.19`, pinned by Dayhoff `7.0.74`,
+self-pinned by Dayhoff `7.0.75`, and exercised in the live `jemdev5`
+greenfield hybrid GUI E2E run.
+
+| Surface | Live evidence |
+|---|---|
+| Deploy verification | `/Users/jmajor/projects/mega_dayhoff/dayhoff/output/jemdev5_verify_7_0_75_final/deploy-verify.md` |
+| GUI E2E screenshot pack | `/Users/jmajor/projects/mega_dayhoff/dayhoff/output/playwright/hybrid_order_to_delivery/hybrid_order_to_delivery/codex-hybrid-e2e-20260619T002814Z/` |
+| Tracked evidence guide | `/Users/jmajor/projects/mega_dayhoff/dayhoff/docs/evidence/hybrid_order_to_delivery_gui_e2e.md` |
+| Pytest result | `1 passed in 149.11s` |
+
+Live Bloom lab-action EUIDs from the passing run:
+
+| Role | EUID |
+|---|---|
+| Patient biospecimen tube | `Z-BCT-2AM` |
+| Extraction plate | `Z-BCP-19Z` |
+| Extraction well | `Z-BCW-3EN3` |
+| Extraction gDNA content | `Z-BNG-FX` |
+| ILMN prep set | `Z-BGS-15X` |
+| ONT prep set | `Z-BGS-16V` |
+| ILMN library plate | `Z-BCP-1AX` |
+| ONT library plate | `Z-BCP-1BV` |
+| ILMN pool tube | `Z-BCT-2BJ` |
+| ONT pool tube | `Z-BCT-2CG` |
+| ILMN seq-run set | `Z-BGS-17S` |
+| ONT seq-run set | `Z-BGS-18Q` |
+
+All Bloom lab-action rows are source-tested, release-pinned, deployed to
+`jemdev5`, and live-proven. Final status: `100%`.
From 94f0898f750d3d068eeb6d809bfe921fff23878c Mon Sep 17 00:00:00 2001
From: John Major
Date: Fri, 19 Jun 2026 04:08:45 -0700
Subject: [PATCH 43/47] Fix TapDB semantic template categories
---
README.md | 4 +-
bloom_lims/anomalies.py | 2 +-
bloom_lims/auth/repositories/tapdb/groups.py | 4 +-
.../repositories/tapdb/user_api_tokens.py | 4 +-
bloom_lims/cli/db.py | 20 +-
bloom_lims/config/container/tube.json | 8 +-
bloom_lims/config/container/well.json | 2 +-
bloom_lims/config/workflow_step/analysis.json | 16 +-
.../workflow_step/extraction-steps.json | 56 +-
bloom_lims/domain/beta_lab.py | 8 +-
bloom_lims/domain/execution_queue.py | 32 +-
bloom_lims/domain/lab_actions.py | 6 +-
bloom_lims/schemas/beta_lab.py | 2 +-
bloom_lims/schemas/external_specimens.py | 2 +-
config/tapdb_templates/bloom/templates.json | 1342 ++++++++---------
docs/apis.md | 2 +-
docs/lab_actions.md | 12 +-
docs/old_docs/ATLAS_BLOOM_CONTRACT_TESTS.md | 2 +-
docs/old_docs/TAPDB_SPECIFICATION.md | 2 +-
...520T064952Z_bloom_sequencing_run_ledger.md | 4 +-
...18T000000Z_bloom_lab_action_flow_ledger.md | 28 +-
pyproject.toml | 2 +-
tests/test_atlas_workflow_contract.py | 8 +-
tests/test_bloom_prefix_taxonomy.py | 33 +-
tests/test_cli_db_command_paths.py | 33 +-
tests/test_core_validation.py | 2 +-
tests/test_packaging_metadata.py | 2 +-
tests/test_sequencing_run_contract.py | 2 +-
uv.lock | 6 +-
29 files changed, 833 insertions(+), 813 deletions(-)
diff --git a/README.md b/README.md
index b337713..24a494e 100644
--- a/README.md
+++ b/README.md
@@ -21,10 +21,12 @@
Bloom is the LSMC internal material and container graph service. It owns laboratory containers, materials/content, equipment, lineage, recursive template creation, search, and graph views. Atlas owns orders and customer-facing accession context; Bloom owns the physical/material execution graph.
-Current Dayhoff pin: `7.0.16`. Current TapDB dependency: `daylily-tapdb @ ...@9.0.5`.
+Current Dayhoff pin: `7.0.20`. Current TapDB dependency: `daylily-tapdb @ ...@9.0.6`.
Bloom is internal-only in Dayhoff exposure policy. It must be reachable only through approved LSMC networks and Dayhoff-generated service credentials.
+TapDB template identity is semantic. Categories are names like `container`, `material`, `data`, `equipment`, `set`, and `workflow`; prefixes such as `BC*`, `BN*`, `BD*`, `BR*`, and `BG*` are issuance and governance labels only. Existing historical objects keep their already minted EUIDs, but new and active template definitions must not use a Meridian/EUID prefix as the category name.
+
## What It Does
- Owns Bloom containers, materials/content, equipment, recursive templates, lineages, search, and graph views.
diff --git a/bloom_lims/anomalies.py b/bloom_lims/anomalies.py
index 9ee96d0..9684423 100644
--- a/bloom_lims/anomalies.py
+++ b/bloom_lims/anomalies.py
@@ -15,7 +15,7 @@
from bloom_lims.config import get_settings
from bloom_lims.observability import ProjectionMetadata
-ANOMALY_TEMPLATE_CODE = "BAN/ops/anomaly-record/1.0/"
+ANOMALY_TEMPLATE_CODE = "ops/anomaly-record/generic/1.0/"
ANOMALY_PREFIX = "BAN"
diff --git a/bloom_lims/auth/repositories/tapdb/groups.py b/bloom_lims/auth/repositories/tapdb/groups.py
index 19a87dd..2c30f5b 100644
--- a/bloom_lims/auth/repositories/tapdb/groups.py
+++ b/bloom_lims/auth/repositories/tapdb/groups.py
@@ -22,8 +22,8 @@
)
from bloom_lims.config import get_settings
-GROUP_TEMPLATE_CODE = "BBX/auth/user-group/1.0/"
-GROUP_MEMBERSHIP_TEMPLATE_CODE = "BBX/auth/user-group-membership/1.0/"
+GROUP_TEMPLATE_CODE = "auth/user-group/generic/1.0/"
+GROUP_MEMBERSHIP_TEMPLATE_CODE = "auth/user-group-membership/generic/1.0/"
GROUP_PREFIX = "BBX"
GROUP_MEMBERSHIP_PREFIX = "BBX"
diff --git a/bloom_lims/auth/repositories/tapdb/user_api_tokens.py b/bloom_lims/auth/repositories/tapdb/user_api_tokens.py
index d59d853..49df31f 100644
--- a/bloom_lims/auth/repositories/tapdb/user_api_tokens.py
+++ b/bloom_lims/auth/repositories/tapdb/user_api_tokens.py
@@ -22,8 +22,8 @@
)
from bloom_lims.config import get_settings
-TOKEN_TEMPLATE_CODE = "BBX/auth/user-api-token/1.0/"
-TOKEN_USAGE_LOG_TEMPLATE_CODE = "BBX/auth/user-api-token-usage-log/1.0/"
+TOKEN_TEMPLATE_CODE = "auth/user-api-token/generic/1.0/"
+TOKEN_USAGE_LOG_TEMPLATE_CODE = "auth/user-api-token-usage-log/generic/1.0/"
TOKEN_PREFIX = "BBX"
TOKEN_USAGE_PREFIX = "BBX"
diff --git a/bloom_lims/cli/db.py b/bloom_lims/cli/db.py
index 5d3107d..dd8859a 100644
--- a/bloom_lims/cli/db.py
+++ b/bloom_lims/cli/db.py
@@ -383,7 +383,12 @@ def _retire_obsolete_template_variants(
domain_code: str,
) -> int:
current = _active_template_categories_by_semantic_key(templates)
- if not current:
+ current_prefixes = {
+ str(template.get("instance_prefix") or "").strip().upper()
+ for template in templates
+ if str(template.get("instance_prefix") or "").strip()
+ }
+ if not current and not current_prefixes:
return 0
rows = (
@@ -405,9 +410,20 @@ def _retire_obsolete_template_variants(
str(row.version or "").strip(),
)
expected_category = current.get(key)
+ actual_category = str(row.category or "").strip().upper()
+ semantic_category = template_semantic_category(row).strip().upper()
+ if semantic_category and actual_category != semantic_category:
+ row.is_deleted = True
+ row.bstatus = "retired"
+ retired += 1
+ continue
+ if actual_category in current_prefixes:
+ row.is_deleted = True
+ row.bstatus = "retired"
+ retired += 1
+ continue
if expected_category is None:
continue
- actual_category = str(row.category or "").strip().upper()
if actual_category == expected_category:
continue
row.is_deleted = True
diff --git a/bloom_lims/config/container/tube.json b/bloom_lims/config/container/tube.json
index 7b7fdc4..d38a26b 100644
--- a/bloom_lims/config/container/tube.json
+++ b/bloom_lims/config/container/tube.json
@@ -39,7 +39,7 @@
"name": "10ml glass tube"
},
"valid_content": [
- "content/.*"
+ "material/.*"
],
"valid_parents": []
}
@@ -84,7 +84,7 @@
"name": "1.5ml eppi tube"
},
"valid_content": [
- "content/.*"
+ "material/.*"
],
"valid_parents": []
}
@@ -129,7 +129,7 @@
"name": "10ml tube generic"
},
"valid_content": [
- "content/.*"
+ "material/.*"
],
"valid_parents": []
}
@@ -175,7 +175,7 @@
},
"singleton": "0",
"valid_content": [
- "content/.*"
+ "material/.*"
],
"valid_parents": []
}
diff --git a/bloom_lims/config/container/well.json b/bloom_lims/config/container/well.json
index a9d6e1b..77e7f58 100644
--- a/bloom_lims/config/container/well.json
+++ b/bloom_lims/config/container/well.json
@@ -36,7 +36,7 @@
},
"singleton": "0",
"valid_content": [
- "content/.*"
+ "material/.*"
],
"valid_parents": [
"container/plate/fixed-plate.*?/.*?"
diff --git a/bloom_lims/config/workflow_step/analysis.json b/bloom_lims/config/workflow_step/analysis.json
index d815f0c..44973f7 100644
--- a/bloom_lims/config/workflow_step/analysis.json
+++ b/bloom_lims/config/workflow_step/analysis.json
@@ -22,44 +22,44 @@
"expected_inputs": [
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
}
],
"expected_outputs": [
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
}
],
diff --git a/bloom_lims/config/workflow_step/extraction-steps.json b/bloom_lims/config/workflow_step/extraction-steps.json
index 925c5e6..ff54b1d 100644
--- a/bloom_lims/config/workflow_step/extraction-steps.json
+++ b/bloom_lims/config/workflow_step/extraction-steps.json
@@ -24,22 +24,22 @@
[
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
}
]
@@ -51,7 +51,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/cfdna/*"
+ "holds_content": "material/sample/cfdna/*"
}
}
]
@@ -62,7 +62,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/cfdna/*"
+ "holds_content": "material/sample/cfdna/*"
}
}
]
@@ -73,7 +73,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/cfdna/*"
+ "holds_content": "material/sample/cfdna/*"
}
}
]
@@ -84,7 +84,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/cfdna/*"
+ "holds_content": "material/sample/cfdna/*"
}
}
]
@@ -133,22 +133,22 @@
"expected_inputs": [
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
}
],
@@ -159,7 +159,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/gdna/*"
+ "holds_content": "material/sample/gdna/*"
}
}
]
@@ -170,7 +170,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/gdna/*"
+ "holds_content": "material/sample/gdna/*"
}
}
]
@@ -181,7 +181,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/gdna/*"
+ "holds_content": "material/sample/gdna/*"
}
}
]
@@ -192,7 +192,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/gdna/*"
+ "holds_content": "material/sample/gdna/*"
}
}
]
@@ -241,22 +241,22 @@
"expected_inputs": [
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
}
],
@@ -302,44 +302,44 @@
"expected_inputs": [
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
}
],
"expected_outputs": [
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
}
],
diff --git a/bloom_lims/domain/beta_lab.py b/bloom_lims/domain/beta_lab.py
index 1c1a4b4..3a377ce 100644
--- a/bloom_lims/domain/beta_lab.py
+++ b/bloom_lims/domain/beta_lab.py
@@ -60,10 +60,10 @@ class BetaLabService(
REL_MATERIAL_CONSUMPTION = "beta_material_consumption"
REL_USED_INSTRUMENT = "beta_used_instrument"
REL_USED_REAGENT = "beta_used_reagent"
- POOL_TEMPLATE_CODE = "content/pool/sequencing-library/1.0"
+ POOL_TEMPLATE_CODE = "material/pool/sequencing-library/1.0"
POOL_CONTAINER_TEMPLATE_CODE = "container/tube/tube-generic-10ml/1.0"
LIBRARY_PREP_OUTPUT_TEMPLATE_CODE = "data/operation/library-prep/1.0"
- LIBRARY_MATERIAL_TEMPLATE_CODE = "content/sample/sequencing-library/1.0"
+ LIBRARY_MATERIAL_TEMPLATE_CODE = "material/sample/sequencing-library/1.0"
SEQUENCING_RUN_TEMPLATE_BY_SUBTYPE = {
"illumina": "data/sequencing_run/illumina/1.0",
"ont": "data/sequencing_run/ont/1.0",
@@ -73,8 +73,8 @@ class BetaLabService(
}
LIBRARY_PLATE_TEMPLATE_CODE = "container/plate/sequencing-library-plate-96/1.0"
EXTRACTION_TEMPLATE_BY_TYPE = {
- "cfdna": "content/sample/cfdna/1.0",
- "gdna": "content/sample/gdna/1.0",
+ "cfdna": "material/sample/cfdna/1.0",
+ "gdna": "material/sample/gdna/1.0",
}
LIB_PREP_QUEUE_BY_PLATFORM = {
"ILMN": "ilmn_lib_prep",
diff --git a/bloom_lims/domain/execution_queue.py b/bloom_lims/domain/execution_queue.py
index 499603c..bdf0f6e 100644
--- a/bloom_lims/domain/execution_queue.py
+++ b/bloom_lims/domain/execution_queue.py
@@ -130,7 +130,7 @@ class ExecutionQueueService:
"dispatch_priority": 100,
"subject_template_codes": [
"container/tube/tube-generic-10ml/1.0",
- "content/specimen/blood-whole/1.0",
+ "material/specimen/blood-whole/1.0",
],
"required_worker_capabilities": ["wetlab.extraction"],
},
@@ -139,7 +139,7 @@ class ExecutionQueueService:
"dispatch_priority": 90,
"subject_template_codes": [
"container/tube/tube-generic-10ml/1.0",
- "content/specimen/blood-whole/1.0",
+ "material/specimen/blood-whole/1.0",
],
"required_worker_capabilities": ["wetlab.extraction"],
},
@@ -147,8 +147,8 @@ class ExecutionQueueService:
"display_name": "Post-Extract QC",
"dispatch_priority": 100,
"subject_template_codes": [
- "content/sample/cfdna/1.0",
- "content/sample/gdna/1.0",
+ "material/sample/cfdna/1.0",
+ "material/sample/gdna/1.0",
],
"required_worker_capabilities": ["wetlab.post_extract_qc"],
},
@@ -156,8 +156,8 @@ class ExecutionQueueService:
"display_name": "Illumina Library Prep",
"dispatch_priority": 100,
"subject_template_codes": [
- "content/sample/cfdna/1.0",
- "content/sample/gdna/1.0",
+ "material/sample/cfdna/1.0",
+ "material/sample/gdna/1.0",
],
"required_worker_capabilities": ["wetlab.library_prep", "platform.ILMN"],
},
@@ -165,7 +165,7 @@ class ExecutionQueueService:
"display_name": "Illumina Library QC",
"dispatch_priority": 100,
"subject_template_codes": [
- "content/sample/sequencing-library/1.0",
+ "material/sample/sequencing-library/1.0",
],
"required_worker_capabilities": ["wetlab.library_qc", "platform.ILMN"],
},
@@ -173,8 +173,8 @@ class ExecutionQueueService:
"display_name": "ONT Library Prep",
"dispatch_priority": 100,
"subject_template_codes": [
- "content/sample/cfdna/1.0",
- "content/sample/gdna/1.0",
+ "material/sample/cfdna/1.0",
+ "material/sample/gdna/1.0",
],
"required_worker_capabilities": ["wetlab.library_prep", "platform.ONT"],
},
@@ -183,7 +183,7 @@ class ExecutionQueueService:
"dispatch_priority": 100,
"subject_template_codes": [
"data/operation/library-prep/1.0",
- "content/sample/sequencing-library/1.0",
+ "material/sample/sequencing-library/1.0",
],
"required_worker_capabilities": ["wetlab.pooling", "platform.ILMN"],
},
@@ -192,28 +192,28 @@ class ExecutionQueueService:
"dispatch_priority": 100,
"subject_template_codes": [
"data/operation/library-prep/1.0",
- "content/sample/sequencing-library/1.0",
+ "material/sample/sequencing-library/1.0",
],
"required_worker_capabilities": ["wetlab.pooling", "platform.ONT"],
},
"ilmn_start_seq_run": {
"display_name": "Illumina Start Run",
"dispatch_priority": 100,
- "subject_template_codes": ["content/pool/sequencing-library/1.0"],
+ "subject_template_codes": ["material/pool/sequencing-library/1.0"],
"required_worker_capabilities": ["wetlab.run_start", "platform.ILMN"],
},
"ont_start_seq_run": {
"display_name": "ONT Start Run",
"dispatch_priority": 100,
- "subject_template_codes": ["content/pool/sequencing-library/1.0"],
+ "subject_template_codes": ["material/pool/sequencing-library/1.0"],
"required_worker_capabilities": ["wetlab.run_start", "platform.ONT"],
},
"post_extract_exception": {
"display_name": "Post-Extract QC Exception",
"dispatch_priority": 10,
"subject_template_codes": [
- "content/sample/cfdna/1.0",
- "content/sample/gdna/1.0",
+ "material/sample/cfdna/1.0",
+ "material/sample/gdna/1.0",
],
"required_worker_capabilities": ["wetlab.exception_review"],
},
@@ -221,7 +221,7 @@ class ExecutionQueueService:
"display_name": "Illumina Library QC Exception",
"dispatch_priority": 10,
"subject_template_codes": [
- "content/sample/sequencing-library/1.0",
+ "material/sample/sequencing-library/1.0",
],
"required_worker_capabilities": [
"wetlab.exception_review",
diff --git a/bloom_lims/domain/lab_actions.py b/bloom_lims/domain/lab_actions.py
index 99fcbdc..6adb276 100644
--- a/bloom_lims/domain/lab_actions.py
+++ b/bloom_lims/domain/lab_actions.py
@@ -40,10 +40,10 @@
RUN_SET_TEMPLATE_CODE = "set/run-set/generic/1.01/"
EXTRACTION_PLATE_TEMPLATE_CODE = "container/plate/fixed-plate-96/1.0/"
LIBRARY_PLATE_TEMPLATE_CODE = "container/plate/sequencing-library-plate-96/1.0/"
-GDNA_TEMPLATE_CODE = "content/sample/gdna/1.0/"
-LIBRARY_CONTENT_TEMPLATE_CODE = "content/sample/sequencing-library/1.0/"
+GDNA_TEMPLATE_CODE = "material/sample/gdna/1.0/"
+LIBRARY_CONTENT_TEMPLATE_CODE = "material/sample/sequencing-library/1.0/"
POOL_TUBE_TEMPLATE_CODE = "container/tube/tube-generic-10ml/1.0/"
-POOL_CONTENT_TEMPLATE_CODE = "content/pool/sequencing-library/1.0/"
+POOL_CONTENT_TEMPLATE_CODE = "material/pool/sequencing-library/1.0/"
GDNA_QUANT_TEMPLATE_CODE = "data/quantification/gdna/1.0/"
EXTRACTION_QC_TEMPLATE_CODE = "data/operation/extraction-qc/1.0/"
SEQUENCED_LIBRARY_ASSIGNMENT_TEMPLATE_CODE = (
diff --git a/bloom_lims/schemas/beta_lab.py b/bloom_lims/schemas/beta_lab.py
index cf123ae..1e855ea 100644
--- a/bloom_lims/schemas/beta_lab.py
+++ b/bloom_lims/schemas/beta_lab.py
@@ -174,7 +174,7 @@ def validate_context(self) -> "AtlasFulfillmentContext":
class BetaAcceptedMaterialCreateRequest(BaseModel):
- specimen_template_code: str = Field(default="content/specimen/blood-whole/1.0")
+ specimen_template_code: str = Field(default="material/specimen/blood-whole/1.0")
specimen_name: str | None = None
container_euid: str | None = None
container_template_code: str = Field(default="container/tube/tube-generic-10ml/1.0")
diff --git a/bloom_lims/schemas/external_specimens.py b/bloom_lims/schemas/external_specimens.py
index df3a009..041c7be 100644
--- a/bloom_lims/schemas/external_specimens.py
+++ b/bloom_lims/schemas/external_specimens.py
@@ -20,7 +20,7 @@ class AtlasReferences(BaseModel):
class ExternalSpecimenCreateRequest(BaseModel):
- specimen_template_code: str = Field(default="content/specimen/generic/1.0")
+ specimen_template_code: str = Field(default="material/specimen/generic/1.0")
specimen_name: str | None = None
container_euid: str | None = None
container_template_code: str = Field(default="container/tube/generic/1.0")
diff --git a/config/tapdb_templates/bloom/templates.json b/config/tapdb_templates/bloom/templates.json
index be5aabf..77d6319 100644
--- a/config/tapdb_templates/bloom/templates.json
+++ b/config/tapdb_templates/bloom/templates.json
@@ -4,7 +4,7 @@
{
"name": "Claim Material In Queue",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "claim_material_in_queue",
"version": "1.0",
@@ -27,7 +27,7 @@
{
"name": "Consume Material",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "consume_material",
"version": "1.0",
@@ -50,7 +50,7 @@
{
"name": "Create Empty Tube",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "create_empty_tube",
"version": "1.0",
@@ -73,7 +73,7 @@
{
"name": "Create Extraction",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "create_extraction",
"version": "1.0",
@@ -96,7 +96,7 @@
{
"name": "Create Library Prep",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "create_library_prep",
"version": "1.0",
@@ -119,7 +119,7 @@
{
"name": "Create Pool",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "create_pool",
"version": "1.0",
@@ -142,7 +142,7 @@
{
"name": "Record Library QC",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "record_library_qc",
"version": "1.0",
@@ -165,7 +165,7 @@
{
"name": "Create Run",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "create_run",
"version": "1.0",
@@ -188,7 +188,7 @@
{
"name": "Move Material To Queue",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "move_material_to_queue",
"version": "1.0",
@@ -211,7 +211,7 @@
{
"name": "Record Post Extract QC",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "record_post_extract_qc",
"version": "1.0",
@@ -234,7 +234,7 @@
{
"name": "Register Accepted Material",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "register_accepted_material",
"version": "1.0",
@@ -257,7 +257,7 @@
{
"name": "Release Claim",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "release_claim",
"version": "1.0",
@@ -280,7 +280,7 @@
{
"name": "Release Reservation",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "release_reservation",
"version": "1.0",
@@ -303,7 +303,7 @@
{
"name": "Reserve Material",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "reserve_material",
"version": "1.0",
@@ -326,7 +326,7 @@
{
"name": "Update Specimen",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "update_specimen",
"version": "1.0",
@@ -349,7 +349,7 @@
{
"name": "Update Tube",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "update_tube",
"version": "1.0",
@@ -372,7 +372,7 @@
{
"name": "action/core/add-relationships/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "core",
"subtype": "add-relationships",
"version": "1.0",
@@ -408,7 +408,7 @@
{
"name": "action/core/create-subject-and-anchor/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "core",
"subtype": "create-subject-and-anchor",
"version": "1.0",
@@ -444,7 +444,7 @@
{
"name": "action/core/print_barcode_label/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "core",
"subtype": "print_barcode_label",
"version": "1.0",
@@ -488,7 +488,7 @@
{
"name": "action/core/set_object_status/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "core",
"subtype": "set_object_status",
"version": "1.0",
@@ -528,7 +528,7 @@
{
"name": "action/data/log-temperature/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "data",
"subtype": "log-temperature",
"version": "1.0",
@@ -571,7 +571,7 @@
{
"name": "action/data/record_cfdna_quant_outcome/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "data",
"subtype": "record_cfdna_quant_outcome",
"version": "1.0",
@@ -614,7 +614,7 @@
{
"name": "action/equipment/add-container-to/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "equipment",
"subtype": "add-container-to",
"version": "1.0",
@@ -661,7 +661,7 @@
{
"name": "action/equipment/download-inventory-tsv/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "equipment",
"subtype": "download-inventory-tsv",
"version": "1.0",
@@ -707,7 +707,7 @@
{
"name": "action/equipment/log-temperature/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "equipment",
"subtype": "log-temperature",
"version": "1.0",
@@ -760,7 +760,7 @@
{
"name": "action/equipment/remove-container-from/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "equipment",
"subtype": "remove-container-from",
"version": "1.0",
@@ -806,7 +806,7 @@
{
"name": "Cancel Subject Execution",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "execution_queue",
"subtype": "cancel_subject_execution",
"version": "1.0",
@@ -829,7 +829,7 @@
{
"name": "Claim Queue Item",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "execution_queue",
"subtype": "claim_queue_item",
"version": "1.0",
@@ -852,7 +852,7 @@
{
"name": "Complete Queue Execution",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "execution_queue",
"subtype": "complete_queue_execution",
"version": "1.0",
@@ -875,7 +875,7 @@
{
"name": "Expire Queue Lease",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "execution_queue",
"subtype": "expire_queue_lease",
"version": "1.0",
@@ -898,7 +898,7 @@
{
"name": "Fail Queue Execution",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "execution_queue",
"subtype": "fail_queue_execution",
"version": "1.0",
@@ -921,7 +921,7 @@
{
"name": "Heartbeat Worker",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "execution_queue",
"subtype": "heartbeat_worker",
"version": "1.0",
@@ -944,7 +944,7 @@
{
"name": "Place Execution Hold",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "execution_queue",
"subtype": "place_execution_hold",
"version": "1.0",
@@ -967,7 +967,7 @@
{
"name": "Register Worker",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "execution_queue",
"subtype": "register_worker",
"version": "1.0",
@@ -990,7 +990,7 @@
{
"name": "Release Execution Hold",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "execution_queue",
"subtype": "release_execution_hold",
"version": "1.0",
@@ -1013,7 +1013,7 @@
{
"name": "Release Queue Lease",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "execution_queue",
"subtype": "release_queue_lease",
"version": "1.0",
@@ -1036,7 +1036,7 @@
{
"name": "Renew Queue Lease",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "execution_queue",
"subtype": "renew_queue_lease",
"version": "1.0",
@@ -1059,7 +1059,7 @@
{
"name": "Requeue Subject",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "execution_queue",
"subtype": "requeue_subject",
"version": "1.0",
@@ -1082,7 +1082,7 @@
{
"name": "action/file/download_file/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "file",
"subtype": "download_file",
"version": "1.0",
@@ -1118,7 +1118,7 @@
{
"name": "action/move-queues/move-among-ay-top-queues/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "move-queues",
"subtype": "move-among-ay-top-queues",
"version": "1.0",
@@ -1162,7 +1162,7 @@
{
"name": "action/object/set-child-object/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "object",
"subtype": "set-child-object",
"version": "1.0",
@@ -1210,7 +1210,7 @@
{
"name": "action/plate/download_plate_map/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "plate",
"subtype": "download_plate_map",
"version": "1.0",
@@ -1255,7 +1255,7 @@
{
"name": "action/plate/stamp_plates_into_plate/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "plate",
"subtype": "stamp_plates_into_plate",
"version": "1.0",
@@ -1313,7 +1313,7 @@
{
"name": "action/plate/stamp_plates_into_plate__extraction_plate_filled/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "plate",
"subtype": "stamp_plates_into_plate__extraction_plate_filled",
"version": "1.0",
@@ -1371,7 +1371,7 @@
{
"name": "action/pool/create-pool-from-containers/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "pool",
"subtype": "create-pool-from-containers",
"version": "1.0",
@@ -1438,7 +1438,7 @@
{
"name": "action/pool/create_pool_from_containers__extraction_plate_filled/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "pool",
"subtype": "create_pool_from_containers__extraction_plate_filled",
"version": "1.0",
@@ -1505,7 +1505,7 @@
{
"name": "action/workflow/destroy_specimen_containers/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow",
"subtype": "destroy_specimen_containers",
"version": "1.0",
@@ -1559,7 +1559,7 @@
{
"name": "action/workflow_step_analysis/download_quant_data/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_analysis",
"subtype": "download_quant_data",
"version": "1.0",
@@ -1605,7 +1605,7 @@
{
"name": "action/workflow_step_destroy/complete_specimen_destroy/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_destroy",
"subtype": "complete_specimen_destroy",
"version": "1.0",
@@ -1649,7 +1649,7 @@
{
"name": "action/workflow_step_extraction/cfdna_post_extraction_quant/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_extraction",
"subtype": "cfdna_post_extraction_quant",
"version": "1.0",
@@ -1711,7 +1711,7 @@
{
"name": "action/workflow_step_plate_operations/cfdna_quant/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_plate_operations",
"subtype": "cfdna_quant",
"version": "1.0",
@@ -1773,7 +1773,7 @@
{
"name": "action/workflow_step_plate_operations/stamp_copy_plate/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_plate_operations",
"subtype": "stamp_copy_plate",
"version": "1.0",
@@ -1826,7 +1826,7 @@
{
"name": "action/workflow_step_queue/add-gdna-to-gdna-normalization-queue/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_queue",
"subtype": "add-gdna-to-gdna-normalization-queue",
"version": "1.0",
@@ -1869,7 +1869,7 @@
{
"name": "action/workflow_step_queue/add-to-blood-gdna-extraction-queue/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_queue",
"subtype": "add-to-blood-gdna-extraction-queue",
"version": "1.0",
@@ -1912,7 +1912,7 @@
{
"name": "action/workflow_step_queue/add-to-buccal-gdna-extraction-queue/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_queue",
"subtype": "add-to-buccal-gdna-extraction-queue",
"version": "1.0",
@@ -1955,7 +1955,7 @@
{
"name": "action/workflow_step_queue/create_test_req_and_link_child_workflow_step/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_queue",
"subtype": "create_test_req_and_link_child_workflow_step",
"version": "1.0",
@@ -2019,7 +2019,7 @@
{
"name": "action/workflow_step_queue/existing-plate-fill-auto/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_queue",
"subtype": "existing-plate-fill-auto",
"version": "1.0",
@@ -2061,7 +2061,7 @@
{
"name": "action/workflow_step_queue/existing-plate-fill-directed/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_queue",
"subtype": "existing-plate-fill-directed",
"version": "1.0",
@@ -2103,7 +2103,7 @@
{
"name": "action/workflow_step_queue/fill_plate_directed/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_queue",
"subtype": "fill_plate_directed",
"version": "1.0",
@@ -2152,7 +2152,7 @@
{
"name": "action/workflow_step_queue/fill_plate_undirected/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_queue",
"subtype": "fill_plate_undirected",
"version": "1.0",
@@ -2205,7 +2205,7 @@
{
"name": "action/workflow_step_queue/link_tubes_auto/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_queue",
"subtype": "link_tubes_auto",
"version": "1.0",
@@ -2276,7 +2276,7 @@
{
"name": "action/workflow_step_queue/plate-create-fill-auto/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_queue",
"subtype": "plate-create-fill-auto",
"version": "1.0",
@@ -2318,7 +2318,7 @@
{
"name": "action/workflow_step_queue/plate-create-fill-directed/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_queue",
"subtype": "plate-create-fill-directed",
"version": "1.0",
@@ -2360,7 +2360,7 @@
{
"name": "action/workflow_step_queue/save-quant-data/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_queue",
"subtype": "save-quant-data",
"version": "1.0",
@@ -2402,7 +2402,7 @@
{
"name": "action/workflow_step_queue/ycreate_test_req_and_link_child_workflow_step/1.0",
"polymorphic_discriminator": "action_template",
- "category": "BAC",
+ "category": "action",
"type": "workflow_step_queue",
"subtype": "ycreate_test_req_and_link_child_workflow_step",
"version": "1.0",
@@ -2464,7 +2464,7 @@
{
"name": "Bloom Authenticated User",
"polymorphic_discriminator": "actor_template",
- "category": "BAR",
+ "category": "actor",
"type": "generic",
"subtype": "bloom-user",
"version": "1.0",
@@ -2475,10 +2475,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Bloom Authenticated User",
"expected_inputs": [],
@@ -2497,7 +2497,7 @@
{
"name": "Patient",
"polymorphic_discriminator": "actor_template",
- "category": "BAR",
+ "category": "actor",
"type": "generic",
"subtype": "patient",
"version": "1.0",
@@ -2508,10 +2508,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Patient",
"expected_inputs": [],
@@ -2534,7 +2534,7 @@
{
"name": "Clinician",
"polymorphic_discriminator": "actor_template",
- "category": "BAR",
+ "category": "actor",
"type": "generic",
"subtype": "physician",
"version": "1.0",
@@ -2545,10 +2545,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -2581,7 +2581,7 @@
{
"name": "Execution System Worker",
"polymorphic_discriminator": "actor_template",
- "category": "BAR",
+ "category": "actor",
"type": "system",
"subtype": "worker",
"version": "1.0",
@@ -2592,9 +2592,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Execution System Worker",
"expected_inputs": [],
@@ -2628,7 +2628,7 @@
{
"name": "Bloom User",
"polymorphic_discriminator": "generic_template",
- "category": "BAR",
+ "category": "actor",
"type": "user",
"subtype": "bloom-user",
"version": "1.0",
@@ -2653,10 +2653,10 @@
"group_order": "1",
"group_name": "Core Actions",
"actions": {
- "BAC/core/add-relationships/1.0": {},
- "BAC/core/create-subject-and-anchor/1.0": {},
- "BAC/core/print_barcode_label/1.0": {},
- "BAC/core/set_object_status/1.0": {}
+ "action/core/add-relationships/1.0": {},
+ "action/core/create-subject-and-anchor/1.0": {},
+ "action/core/print_barcode_label/1.0": {},
+ "action/core/set_object_status/1.0": {}
}
}
},
@@ -2667,9 +2667,9 @@
{
"name": "Bloom User API Token Usage Log",
"polymorphic_discriminator": "generic_template",
- "category": "BBX",
- "type": "auth",
- "subtype": "user-api-token-usage-log",
+ "category": "auth",
+ "type": "user-api-token-usage-log",
+ "subtype": "generic",
"version": "1.0",
"instance_prefix": "BBX",
"instance_polymorphic_identity": "generic_instance",
@@ -2684,9 +2684,9 @@
{
"name": "Bloom User API Token",
"polymorphic_discriminator": "generic_template",
- "category": "BBX",
- "type": "auth",
- "subtype": "user-api-token",
+ "category": "auth",
+ "type": "user-api-token",
+ "subtype": "generic",
"version": "1.0",
"instance_prefix": "BBX",
"instance_polymorphic_identity": "generic_instance",
@@ -2701,7 +2701,7 @@
{
"name": "Generic External Object Link",
"polymorphic_discriminator": "generic_template",
- "category": "BGX",
+ "category": "generic",
"type": "generic",
"subtype": "external_object_link",
"version": "1.0",
@@ -2725,9 +2725,9 @@
{
"name": "Bloom User Group Membership",
"polymorphic_discriminator": "generic_template",
- "category": "BBX",
- "type": "auth",
- "subtype": "user-group-membership",
+ "category": "auth",
+ "type": "user-group-membership",
+ "subtype": "generic",
"version": "1.0",
"instance_prefix": "BBX",
"instance_polymorphic_identity": "generic_instance",
@@ -2742,9 +2742,9 @@
{
"name": "Bloom User Group",
"polymorphic_discriminator": "generic_template",
- "category": "BBX",
- "type": "auth",
- "subtype": "user-group",
+ "category": "auth",
+ "type": "user-group",
+ "subtype": "generic",
"version": "1.0",
"instance_prefix": "BBX",
"instance_polymorphic_identity": "generic_instance",
@@ -2759,7 +2759,7 @@
{
"name": "24 fixed well plate",
"polymorphic_discriminator": "container_template",
- "category": "BCP",
+ "category": "container",
"type": "plate",
"subtype": "fixed-plate-24",
"version": "1.0",
@@ -2770,12 +2770,12 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "download_plate_map": "BAC/plate/download_plate_map/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0",
- "stamp_plates_into_plate": "BAC/plate/stamp_plates_into_plate/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "download_plate_map": "action/plate/download_plate_map/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0",
+ "stamp_plates_into_plate": "action/plate/stamp_plates_into_plate/1.0"
},
"cogs": {
"allocation_type": "",
@@ -3300,7 +3300,7 @@
{
"name": "96 well fixed plate",
"polymorphic_discriminator": "container_template",
- "category": "BCP",
+ "category": "container",
"type": "plate",
"subtype": "fixed-plate-96",
"version": "1.0",
@@ -3311,12 +3311,12 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "download_plate_map": "BAC/plate/download_plate_map/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0",
- "stamp_plates_into_plate": "BAC/plate/stamp_plates_into_plate/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "download_plate_map": "action/plate/download_plate_map/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0",
+ "stamp_plates_into_plate": "action/plate/stamp_plates_into_plate/1.0"
},
"cogs": {
"allocation_type": "",
@@ -4934,7 +4934,7 @@
{
"name": "4 position Rack",
"polymorphic_discriminator": "container_template",
- "category": "BCR",
+ "category": "container",
"type": "rack",
"subtype": "tube-rack-4-empty",
"version": "1.0",
@@ -4945,10 +4945,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -4987,7 +4987,7 @@
{
"name": "4 position Rack",
"polymorphic_discriminator": "container_template",
- "category": "BCR",
+ "category": "container",
"type": "rack",
"subtype": "tube-rack-generic",
"version": "1.0",
@@ -4998,10 +4998,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -5094,7 +5094,7 @@
{
"name": "Shelf",
"polymorphic_discriminator": "container_template",
- "category": "BCR",
+ "category": "container",
"type": "shelf",
"subtype": "generic",
"version": "1.0",
@@ -5105,11 +5105,11 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_container_to": "BAC/equipment/add-container-to/1.0",
- "download_inventory_tsv": "BAC/equipment/download-inventory-tsv/1.0",
- "log_temperature": "BAC/equipment/log-temperature/1.0",
- "remove_container_from": "BAC/equipment/remove-container-from/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_container_to": "action/equipment/add-container-to/1.0",
+ "download_inventory_tsv": "action/equipment/download-inventory-tsv/1.0",
+ "log_temperature": "action/equipment/log-temperature/1.0",
+ "remove_container_from": "action/equipment/remove-container-from/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -5150,7 +5150,7 @@
{
"name": "10ml glass tube",
"polymorphic_discriminator": "container_template",
- "category": "BCT",
+ "category": "container",
"type": "tube",
"subtype": "tube-10ml-glass",
"version": "1.0",
@@ -5161,10 +5161,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -5197,7 +5197,7 @@
"name": "10ml glass tube"
},
"valid_content": [
- "content/.*"
+ "material/.*"
],
"valid_parents": [],
"semantic_category": "container"
@@ -5206,7 +5206,7 @@
{
"name": "1.5ml eppi tube",
"polymorphic_discriminator": "container_template",
- "category": "BCT",
+ "category": "container",
"type": "tube",
"subtype": "tube-eppi-1.5ml",
"version": "1.0",
@@ -5217,10 +5217,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -5253,7 +5253,7 @@
"name": "1.5ml eppi tube"
},
"valid_content": [
- "content/.*"
+ "material/.*"
],
"valid_parents": [],
"semantic_category": "container"
@@ -5262,7 +5262,7 @@
{
"name": "Generic 10ml tube",
"polymorphic_discriminator": "container_template",
- "category": "BCT",
+ "category": "container",
"type": "tube",
"subtype": "tube-generic-10ml",
"version": "1.0",
@@ -5273,10 +5273,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -5309,7 +5309,7 @@
"name": "10ml tube generic"
},
"valid_content": [
- "content/.*"
+ "material/.*"
],
"valid_parents": [],
"semantic_category": "container"
@@ -5318,7 +5318,7 @@
{
"name": "strek 10ml",
"polymorphic_discriminator": "container_template",
- "category": "BCT",
+ "category": "container",
"type": "tube",
"subtype": "tube-strek-10ml",
"version": "1.0",
@@ -5329,10 +5329,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -5366,7 +5366,7 @@
},
"singleton": "0",
"valid_content": [
- "content/.*"
+ "material/.*"
],
"valid_parents": [],
"semantic_category": "container"
@@ -5375,7 +5375,7 @@
{
"name": "Mawi DNA Technologies - ISD-T-250 - iSWAB DNA Collection Tube - Buccal",
"polymorphic_discriminator": "container_template",
- "category": "BCT",
+ "category": "container",
"type": "tube",
"subtype": "mawi-isd-t-250-iswab-dna-collection-tube-buccal",
"version": "1.0",
@@ -5386,10 +5386,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -5426,7 +5426,7 @@
},
"singleton": "0",
"valid_content": [
- "content/.*"
+ "material/.*"
],
"valid_parents": [],
"semantic_category": "container"
@@ -5435,7 +5435,7 @@
{
"name": "plate well - fixed",
"polymorphic_discriminator": "container_template",
- "category": "BCW",
+ "category": "container",
"type": "well",
"subtype": "fixed-plate-well",
"version": "1.0",
@@ -5446,7 +5446,7 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -5479,7 +5479,7 @@
},
"singleton": "0",
"valid_content": [
- "content/.*"
+ "material/.*"
],
"valid_parents": [
"container/plate/fixed-plate.*?/.*?"
@@ -5490,7 +5490,7 @@
{
"name": "giab NA12878",
"polymorphic_discriminator": "content_template",
- "category": "BNK",
+ "category": "material",
"type": "control",
"subtype": "giab-HG001",
"version": "1.0",
@@ -5501,10 +5501,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -5534,7 +5534,7 @@
{
"name": "giab NA24385",
"polymorphic_discriminator": "content_template",
- "category": "BNK",
+ "category": "material",
"type": "control",
"subtype": "giab-HG002",
"version": "1.0",
@@ -5545,10 +5545,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -5578,7 +5578,7 @@
{
"name": "synthetic-cfdna",
"polymorphic_discriminator": "content_template",
- "category": "BNK",
+ "category": "material",
"type": "control",
"subtype": "synthetic-cfdna",
"version": "1.0",
@@ -5589,10 +5589,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -5622,7 +5622,7 @@
{
"name": "NTC - water",
"polymorphic_discriminator": "content_template",
- "category": "BNK",
+ "category": "material",
"type": "control",
"subtype": "water-ntc",
"version": "1.0",
@@ -5633,10 +5633,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -5666,7 +5666,7 @@
{
"name": "Pool of Contents",
"polymorphic_discriminator": "content_template",
- "category": "BNP",
+ "category": "material",
"type": "pool",
"subtype": "generic",
"version": "1.0",
@@ -5702,7 +5702,7 @@
{
"name": "Novaseq sequencing kit",
"polymorphic_discriminator": "content_template",
- "category": "BNR",
+ "category": "material",
"type": "reagent",
"subtype": "ILMN-nova-seq-kit",
"version": "1.0",
@@ -5745,7 +5745,7 @@
{
"name": "idt probes for rare mendelian disease, v1.0",
"polymorphic_discriminator": "content_template",
- "category": "BNR",
+ "category": "material",
"type": "reagent",
"subtype": "idt-probes-rare-mendelian",
"version": "1.0",
@@ -5788,7 +5788,7 @@
{
"name": "NaOH",
"polymorphic_discriminator": "content_template",
- "category": "BNR",
+ "category": "material",
"type": "reagent",
"subtype": "naoh",
"version": "1.0",
@@ -5832,7 +5832,7 @@
{
"name": "plasma (whole blood)",
"polymorphic_discriminator": "content_template",
- "category": "BNB",
+ "category": "material",
"type": "sample",
"subtype": "blood-plasma",
"version": "1.0",
@@ -5870,7 +5870,7 @@
{
"name": "cell free DNA ",
"polymorphic_discriminator": "content_template",
- "category": "BNC",
+ "category": "material",
"type": "sample",
"subtype": "cfdna",
"version": "1.0",
@@ -5908,7 +5908,7 @@
{
"name": "genomic DNA",
"polymorphic_discriminator": "content_template",
- "category": "BNG",
+ "category": "material",
"type": "sample",
"subtype": "gdna",
"version": "1.0",
@@ -5946,7 +5946,7 @@
{
"name": "Whole Blood",
"polymorphic_discriminator": "content_template",
- "category": "BNB",
+ "category": "material",
"type": "specimen",
"subtype": "blood-whole",
"version": "1.0",
@@ -5984,7 +5984,7 @@
{
"name": "Buccal Swab",
"polymorphic_discriminator": "content_template",
- "category": "BNS",
+ "category": "material",
"type": "specimen",
"subtype": "buccal-swab",
"version": "1.0",
@@ -6022,7 +6022,7 @@
{
"name": "FFPE Block",
"polymorphic_discriminator": "content_template",
- "category": "BNF",
+ "category": "material",
"type": "specimen",
"subtype": "ffpe-block",
"version": "1.0",
@@ -6060,7 +6060,7 @@
{
"name": "FFPE Slides",
"polymorphic_discriminator": "content_template",
- "category": "BNF",
+ "category": "material",
"type": "specimen",
"subtype": "ffpe-slice",
"version": "1.0",
@@ -6098,7 +6098,7 @@
{
"name": "Execution Dead Letter Record",
"polymorphic_discriminator": "data_template",
- "category": "BDT",
+ "category": "data",
"type": "execution",
"subtype": "dead_letter",
"version": "1.0",
@@ -6109,9 +6109,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Execution Dead Letter Record",
"expected_inputs": [],
@@ -6137,7 +6137,7 @@
{
"name": "Execution Attempt Record",
"polymorphic_discriminator": "data_template",
- "category": "BDT",
+ "category": "data",
"type": "execution",
"subtype": "execution_record",
"version": "1.0",
@@ -6148,9 +6148,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Execution Attempt Record",
"expected_inputs": [],
@@ -6190,7 +6190,7 @@
{
"name": "Execution Hold",
"polymorphic_discriminator": "data_template",
- "category": "BDT",
+ "category": "data",
"type": "execution",
"subtype": "hold",
"version": "1.0",
@@ -6201,9 +6201,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Execution Hold",
"expected_inputs": [],
@@ -6227,7 +6227,7 @@
{
"name": "Execution Queue Definition",
"polymorphic_discriminator": "data_template",
- "category": "BDT",
+ "category": "data",
"type": "execution",
"subtype": "queue",
"version": "1.0",
@@ -6238,10 +6238,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Execution Queue Definition",
"expected_inputs": [],
@@ -6291,7 +6291,7 @@
{
"name": "Execution Queue Lease",
"polymorphic_discriminator": "data_template",
- "category": "BDT",
+ "category": "data",
"type": "execution",
"subtype": "queue_lease",
"version": "1.0",
@@ -6302,9 +6302,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Execution Queue Lease",
"expected_inputs": [],
@@ -6335,7 +6335,7 @@
{
"name": "Generic Data Record",
"polymorphic_discriminator": "data_template",
- "category": "BD",
+ "category": "data",
"type": "generic",
"subtype": "generic",
"version": "1.0",
@@ -6346,9 +6346,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Generic data record",
"expected_inputs": [],
@@ -6365,7 +6365,7 @@
{
"name": "DNA Quant Data",
"polymorphic_discriminator": "data_template",
- "category": "BDQ",
+ "category": "data",
"type": "generic",
"subtype": "gdna-quantification",
"version": "1.0",
@@ -6376,11 +6376,11 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "record_cfdna_quant_outcome": "BAC/data/record_cfdna_quant_outcome/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "record_cfdna_quant_outcome": "action/data/record_cfdna_quant_outcome/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -6408,7 +6408,7 @@
{
"name": "Temperature Log Data",
"polymorphic_discriminator": "data_template",
- "category": "BDC",
+ "category": "data",
"type": "generic",
"subtype": "temperature-log",
"version": "1.0",
@@ -6445,7 +6445,7 @@
{
"name": "Wet-Lab Library Prep Output",
"polymorphic_discriminator": "data_template",
- "category": "BDP",
+ "category": "data",
"type": "wetlab",
"subtype": "library_prep_output",
"version": "1.0",
@@ -6456,10 +6456,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Wet-Lab Library Prep Output",
"expected_inputs": [],
@@ -6478,7 +6478,7 @@
{
"name": "Illumina Sequencing Run",
"polymorphic_discriminator": "data_template",
- "category": "BRM",
+ "category": "data",
"type": "sequencing_run",
"subtype": "illumina",
"version": "1.0",
@@ -6489,9 +6489,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Sequencing run executed on an Illumina instrument.",
"expected_inputs": [],
@@ -6516,7 +6516,7 @@
{
"name": "ONT Sequencing Run",
"polymorphic_discriminator": "data_template",
- "category": "BRN",
+ "category": "data",
"type": "sequencing_run",
"subtype": "ont",
"version": "1.0",
@@ -6527,9 +6527,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Sequencing run executed on an Oxford Nanopore instrument.",
"expected_inputs": [],
@@ -6554,7 +6554,7 @@
{
"name": "Ultima Sequencing Run",
"polymorphic_discriminator": "data_template",
- "category": "BRT",
+ "category": "data",
"type": "sequencing_run",
"subtype": "ultima",
"version": "1.0",
@@ -6565,9 +6565,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Sequencing run executed on an Ultima instrument.",
"expected_inputs": [],
@@ -6592,7 +6592,7 @@
{
"name": "CompleteGenomics Sequencing Run",
"polymorphic_discriminator": "data_template",
- "category": "BRC",
+ "category": "data",
"type": "sequencing_run",
"subtype": "completegenomics",
"version": "1.0",
@@ -6603,9 +6603,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Sequencing run executed on a Complete Genomics instrument.",
"expected_inputs": [],
@@ -6630,7 +6630,7 @@
{
"name": "PacBio Sequencing Run",
"polymorphic_discriminator": "data_template",
- "category": "BRP",
+ "category": "data",
"type": "sequencing_run",
"subtype": "pacbio",
"version": "1.0",
@@ -6641,9 +6641,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Sequencing run executed on a PacBio instrument.",
"expected_inputs": [],
@@ -6668,7 +6668,7 @@
{
"name": "-20C Freezer",
"polymorphic_discriminator": "equipment_template",
- "category": "BEQ",
+ "category": "equipment",
"type": "freezer",
"subtype": "freezer-m20c",
"version": "1.0",
@@ -6679,14 +6679,14 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_container_to": "BAC/equipment/add-container-to/1.0",
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "download_inventory_tsv": "BAC/equipment/download-inventory-tsv/1.0",
- "log_temperature": "BAC/equipment/log-temperature/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "remove_container_from": "BAC/equipment/remove-container-from/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_container_to": "action/equipment/add-container-to/1.0",
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "download_inventory_tsv": "action/equipment/download-inventory-tsv/1.0",
+ "log_temperature": "action/equipment/log-temperature/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "remove_container_from": "action/equipment/remove-container-from/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -6706,7 +6706,7 @@
"relationship_type": "contains",
"child_templates": [
{
- "template_code": "BCR/shelf/generic/1.0",
+ "template_code": "container/shelf/generic/1.0",
"json_addl": {
"cont_address": {
"capacity": "10",
@@ -6719,7 +6719,7 @@
}
},
{
- "template_code": "BCR/shelf/generic/1.0",
+ "template_code": "container/shelf/generic/1.0",
"json_addl": {
"cont_address": {
"capacity": "10",
@@ -6750,7 +6750,7 @@
{
"name": "-80C Freezer.",
"polymorphic_discriminator": "equipment_template",
- "category": "BEQ",
+ "category": "equipment",
"type": "freezer",
"subtype": "freezer-m80c",
"version": "1.0",
@@ -6761,14 +6761,14 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_container_to": "BAC/equipment/add-container-to/1.0",
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "download_inventory_tsv": "BAC/equipment/download-inventory-tsv/1.0",
- "log_temperature": "BAC/equipment/log-temperature/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "remove_container_from": "BAC/equipment/remove-container-from/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_container_to": "action/equipment/add-container-to/1.0",
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "download_inventory_tsv": "action/equipment/download-inventory-tsv/1.0",
+ "log_temperature": "action/equipment/log-temperature/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "remove_container_from": "action/equipment/remove-container-from/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -6788,7 +6788,7 @@
"relationship_type": "contains",
"child_templates": [
{
- "template_code": "BCR/shelf/generic/1.0",
+ "template_code": "container/shelf/generic/1.0",
"json_addl": {
"cont_address": {
"capacity": "10",
@@ -6801,7 +6801,7 @@
}
},
{
- "template_code": "BCR/shelf/generic/1.0",
+ "template_code": "container/shelf/generic/1.0",
"json_addl": {
"cont_address": {
"capacity": "10",
@@ -6814,7 +6814,7 @@
}
},
{
- "template_code": "BCR/shelf/generic/1.0",
+ "template_code": "container/shelf/generic/1.0",
"json_addl": {
"cont_address": {
"capacity": "10",
@@ -6827,7 +6827,7 @@
}
},
{
- "template_code": "BCR/shelf/generic/1.0",
+ "template_code": "container/shelf/generic/1.0",
"json_addl": {
"cont_address": {
"capacity": "10",
@@ -6858,7 +6858,7 @@
{
"name": "Bravo Liquid Handler",
"polymorphic_discriminator": "equipment_template",
- "category": "BEQ",
+ "category": "equipment",
"type": "liquid_handler",
"subtype": "bravo",
"version": "1.0",
@@ -6869,10 +6869,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -6904,7 +6904,7 @@
{
"name": "Illumnina MiSeq y",
"polymorphic_discriminator": "equipment_template",
- "category": "BEQ",
+ "category": "equipment",
"type": "sequencers",
"subtype": "miseq-y",
"version": "1.0",
@@ -6915,10 +6915,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -6950,7 +6950,7 @@
{
"name": "Illumnina Novaseq 6000",
"polymorphic_discriminator": "equipment_template",
- "category": "BEQ",
+ "category": "equipment",
"type": "sequencers",
"subtype": "novaseq-6000",
"version": "1.0",
@@ -6961,10 +6961,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -6996,7 +6996,7 @@
{
"name": "ONT MinION",
"polymorphic_discriminator": "equipment_template",
- "category": "BEQ",
+ "category": "equipment",
"type": "sequencers",
"subtype": "ont-minion",
"version": "1.0",
@@ -7007,10 +7007,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -7042,7 +7042,7 @@
{
"name": "Generic File",
"polymorphic_discriminator": "file_template",
- "category": "BFX",
+ "category": "file",
"type": "file",
"subtype": "generic",
"version": "1.0",
@@ -7053,11 +7053,11 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "download_file": "BAC/file/download_file/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "download_file": "action/file/download_file/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"arbitrary_association_strings": [],
"cogs": {
@@ -7375,7 +7375,7 @@
{
"name": "Generic File Set",
"polymorphic_discriminator": "file_template",
- "category": "BFX",
+ "category": "file",
"type": "file_set",
"subtype": "generic",
"version": "1.0",
@@ -7386,10 +7386,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -7469,7 +7469,7 @@
{
"name": "Generic Run Set",
"polymorphic_discriminator": "generic_template",
- "category": "BGS",
+ "category": "set",
"type": "run-set",
"subtype": "generic",
"version": "1.01",
@@ -7480,8 +7480,8 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"controlled_properties": {},
"description": "Generic run set for temporary Bloom lab batch and sequencing-run grouping.",
@@ -7570,7 +7570,7 @@
{
"name": "Generic File Reference",
"polymorphic_discriminator": "file_template",
- "category": "BFX",
+ "category": "file",
"type": "shared_ref",
"subtype": "generic",
"version": "1.0",
@@ -7581,10 +7581,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"arbitrary_association_strings": [],
"cogs": {
@@ -7656,7 +7656,7 @@
{
"name": "Generic Health Event",
"polymorphic_discriminator": "health_event_template",
- "category": "BHE",
+ "category": "health",
"type": "generic",
"subtype": "health-event",
"version": "1.0",
@@ -7667,10 +7667,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -7698,7 +7698,7 @@
{
"name": "Decision scope for an accession (ACC / TRX / intake bundle).",
"polymorphic_discriminator": "subject_template",
- "category": "BSJ",
+ "category": "subject",
"type": "generic",
"subtype": "accession-subject",
"version": "1.0",
@@ -7709,10 +7709,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -7797,7 +7797,7 @@
{
"name": "Decision scope for analysis result bundles.",
"polymorphic_discriminator": "subject_template",
- "category": "BSJ",
+ "category": "subject",
"type": "generic",
"subtype": "analysis-bundle-subject",
"version": "1.0",
@@ -7808,10 +7808,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -7896,7 +7896,7 @@
{
"name": "Fallback decision scope for custom use cases.",
"polymorphic_discriminator": "subject_template",
- "category": "BSJ",
+ "category": "subject",
"type": "generic",
"subtype": "generic-subject",
"version": "1.0",
@@ -7907,10 +7907,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -7998,7 +7998,7 @@
{
"name": "Decision scope for clinical reportable units.",
"polymorphic_discriminator": "subject_template",
- "category": "BSJ",
+ "category": "subject",
"type": "generic",
"subtype": "report-subject",
"version": "1.0",
@@ -8009,10 +8009,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -8097,7 +8097,7 @@
{
"name": "Workset grouping workflow steps and objects created during an accessioning transaction.",
"polymorphic_discriminator": "subject_template",
- "category": "BSJ",
+ "category": "subject",
"type": "workset",
"subtype": "accession",
"version": "1.0",
@@ -8108,10 +8108,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -8226,7 +8226,7 @@
{
"name": "Workset grouping workflow steps and objects created during an extraction batch.",
"polymorphic_discriminator": "subject_template",
- "category": "BSJ",
+ "category": "subject",
"type": "workset",
"subtype": "extraction",
"version": "1.0",
@@ -8237,10 +8237,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -8355,7 +8355,7 @@
{
"name": "Workset grouping workflow steps and objects created during a sequencing run.",
"polymorphic_discriminator": "subject_template",
- "category": "BSJ",
+ "category": "subject",
"type": "workset",
"subtype": "sequencing",
"version": "1.0",
@@ -8366,10 +8366,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -8484,7 +8484,7 @@
{
"name": "Workset for carrier-screen 3.9",
"polymorphic_discriminator": "workflow_template",
- "category": "BWF",
+ "category": "workflow",
"type": "assay-workset",
"subtype": "carrier-screen",
"version": "3.9",
@@ -8495,11 +8495,11 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "move_among_ay_top_queues": "BAC/move-queues/move-among-ay-top-queues/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "move_among_ay_top_queues": "action/move-queues/move-among-ay-top-queues/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -8519,7 +8519,7 @@
"relationship_type": "contains",
"child_templates": [
{
- "template_code": "BWS/queue/plasma-isolation-queue-available/1.0",
+ "template_code": "workflow_step/queue/plasma-isolation-queue-available/1.0",
"json_addl": {
"properties": {
"comments": "",
@@ -8528,7 +8528,7 @@
}
},
{
- "template_code": "BWS/queue/plasma-isolation-queue-removed/1.0",
+ "template_code": "workflow_step/queue/plasma-isolation-queue-removed/1.0",
"json_addl": {
"properties": {
"comments": "",
@@ -8537,7 +8537,7 @@
}
},
{
- "template_code": "BWS/queue/plasma-isolation-queue-exception/1.0",
+ "template_code": "workflow_step/queue/plasma-isolation-queue-exception/1.0",
"json_addl": {
"properties": {
"comments": "",
@@ -8565,7 +8565,7 @@
{
"name": "Workset for hla-typing 1.2",
"polymorphic_discriminator": "workflow_template",
- "category": "BWF",
+ "category": "workflow",
"type": "assay-workset",
"subtype": "hla-typing",
"version": "1.2",
@@ -8576,11 +8576,11 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "move_among_ay_top_queues": "BAC/move-queues/move-among-ay-top-queues/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "move_among_ay_top_queues": "action/move-queues/move-among-ay-top-queues/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -8618,7 +8618,7 @@
{
"name": "Carrier Screen 3.9",
"polymorphic_discriminator": "workflow_template",
- "category": "BWF",
+ "category": "workflow",
"type": "assay",
"subtype": "carrier-screen",
"version": "3.9",
@@ -8629,10 +8629,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"assay_type": "assay",
"cogs": {
@@ -8653,7 +8653,7 @@
"relationship_type": "contains",
"child_templates": [
{
- "template_code": "BWS/queue/extraction-batch-eligible/1.0",
+ "template_code": "workflow_step/queue/extraction-batch-eligible/1.0",
"json_addl": {
"description": "Extraction Batch Eligible",
"properties": {
@@ -8666,7 +8666,7 @@
"name_pattern": "Extraction Batch Eligible"
},
{
- "template_code": "BWS/queue/blood-to-gdna-extraction-eligible/1.0",
+ "template_code": "workflow_step/queue/blood-to-gdna-extraction-eligible/1.0",
"json_addl": {
"description": "Blood To gDNA Extraction Eligible",
"properties": {
@@ -8679,7 +8679,7 @@
"name_pattern": "Blood To gDNA Extraction Eligible"
},
{
- "template_code": "BWS/queue/buccal-to-gdna-extraction-eligible/1.0",
+ "template_code": "workflow_step/queue/buccal-to-gdna-extraction-eligible/1.0",
"json_addl": {
"description": "Buccal To gDNA Extraction Eligible",
"properties": {
@@ -8692,7 +8692,7 @@
"name_pattern": "Buccal To gDNA Extraction Eligible"
},
{
- "template_code": "BWS/queue/input-gdna-normalization-eligible/1.0",
+ "template_code": "workflow_step/queue/input-gdna-normalization-eligible/1.0",
"json_addl": {
"description": "Input gDNA Normalization Eligible",
"properties": {
@@ -8705,7 +8705,7 @@
"name_pattern": "Input gDNA Normalization Eligible"
},
{
- "template_code": "BWS/queue/illumina-novaseq-libprep-eligible/1.0",
+ "template_code": "workflow_step/queue/illumina-novaseq-libprep-eligible/1.0",
"json_addl": {
"description": "Illumina Novaseq LibPrep Eligible",
"properties": {
@@ -8718,7 +8718,7 @@
"name_pattern": "Illumina Novaseq LibPrep Eligible"
},
{
- "template_code": "BWS/queue/ont-libprep-eligible/1.0",
+ "template_code": "workflow_step/queue/ont-libprep-eligible/1.0",
"json_addl": {
"description": "ONT LibPrep Eligible",
"properties": {
@@ -8749,7 +8749,7 @@
{
"name": "HLA Typing v1.2",
"polymorphic_discriminator": "workflow_template",
- "category": "BWF",
+ "category": "workflow",
"type": "assay",
"subtype": "hla-typing",
"version": "1.2",
@@ -8760,10 +8760,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"assay_type": "assay",
"cogs": {
@@ -8784,7 +8784,7 @@
"relationship_type": "contains",
"child_templates": [
{
- "template_code": "BWS/queue/extraction-batch-eligible/1.0",
+ "template_code": "workflow_step/queue/extraction-batch-eligible/1.0",
"json_addl": {
"description": "Extraction Batch Eligible",
"properties": {
@@ -8797,7 +8797,7 @@
"name_pattern": "Extraction Batch Eligible"
},
{
- "template_code": "BWS/queue/blood-to-gdna-extraction-eligible/1.0",
+ "template_code": "workflow_step/queue/blood-to-gdna-extraction-eligible/1.0",
"json_addl": {
"description": "Blood To gDNA Extraction Eligible",
"properties": {
@@ -8810,7 +8810,7 @@
"name_pattern": "Blood To gDNA Extraction Eligible"
},
{
- "template_code": "BWS/queue/buccal-to-gdna-extraction-eligible/1.0",
+ "template_code": "workflow_step/queue/buccal-to-gdna-extraction-eligible/1.0",
"json_addl": {
"description": "Buccal To gDNA Extraction Eligible",
"properties": {
@@ -8823,7 +8823,7 @@
"name_pattern": "Buccal To gDNA Extraction Eligible"
},
{
- "template_code": "BWS/queue/input-gdna-normalization-eligible/1.0",
+ "template_code": "workflow_step/queue/input-gdna-normalization-eligible/1.0",
"json_addl": {
"description": "Input gDNA Normalization Eligible",
"properties": {
@@ -8836,7 +8836,7 @@
"name_pattern": "Input gDNA Normalization Eligible"
},
{
- "template_code": "BWS/queue/illumina-novaseq-libprep-eligible/1.0",
+ "template_code": "workflow_step/queue/illumina-novaseq-libprep-eligible/1.0",
"json_addl": {
"description": "Illumina Novaseq LibPrep Eligible",
"properties": {
@@ -8849,7 +8849,7 @@
"name_pattern": "Illumina Novaseq LibPrep Eligible"
},
{
- "template_code": "BWS/queue/ont-libprep-eligible/1.0",
+ "template_code": "workflow_step/queue/ont-libprep-eligible/1.0",
"json_addl": {
"description": "ONT LibPrep Eligible",
"properties": {
@@ -8880,7 +8880,7 @@
{
"name": "Destroy Specimen Containers",
"polymorphic_discriminator": "workflow_template",
- "category": "BWF",
+ "category": "workflow",
"type": "destroy",
"subtype": "specimen-containers",
"version": "1.0",
@@ -8891,11 +8891,11 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "destroy_specimen_containers": "BAC/workflow/destroy_specimen_containers/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "destroy_specimen_containers": "action/workflow/destroy_specimen_containers/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -8922,7 +8922,7 @@
{
"name": "DNA extraction from blood-whole in tube-strek-10ml tubes to a fixed-plate-96 with gdna in each well.",
"polymorphic_discriminator": "workflow_template",
- "category": "BWF",
+ "category": "workflow",
"type": "extraction",
"subtype": "blood-whole-to-gdna",
"version": "1.0",
@@ -8933,10 +8933,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -8968,7 +8968,7 @@
{
"name": "DNA extraction from blood-whole in tube-strek-10ml tubes to a fixed-plate-96 with gdna in each well.",
"polymorphic_discriminator": "workflow_template",
- "category": "BWF",
+ "category": "workflow",
"type": "extraction",
"subtype": "blood-whole-to-plasma-to-cfdna",
"version": "1.0",
@@ -8979,10 +8979,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9014,7 +9014,7 @@
{
"name": "DNA QUANTIFIED",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "analysis",
"subtype": "gdna-quantified",
"version": "1.0",
@@ -9025,10 +9025,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9044,44 +9044,44 @@
"expected_inputs": [
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
}
],
"expected_outputs": [
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
}
],
@@ -9107,7 +9107,7 @@
{
"name": "Plasma QUANT",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "analysis",
"subtype": "plasma-quantification",
"version": "1.0",
@@ -9118,11 +9118,11 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "download_quant_data": "BAC/workflow_step_analysis/download_quant_data/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "download_quant_data": "action/workflow_step_analysis/download_quant_data/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9159,7 +9159,7 @@
{
"name": "Specimens Destroyed",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "destroy-steps",
"subtype": "specimen-containers-destroyed",
"version": "1.0",
@@ -9170,11 +9170,11 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "complete_specimen_destroy": "BAC/workflow_step_destroy/complete_specimen_destroy/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "complete_specimen_destroy": "action/workflow_step_destroy/complete_specimen_destroy/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9211,7 +9211,7 @@
{
"name": "Destroyed Containers Exceptions",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "exception",
"subtype": "specimen-containers-destroyed",
"version": "1.0",
@@ -9222,10 +9222,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9262,7 +9262,7 @@
{
"name": "cfDNA Extraction Plate ",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "extraction-steps",
"subtype": "cfdna-extracted",
"version": "1.0",
@@ -9273,11 +9273,11 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "cfdna_post_extraction_quant": "BAC/workflow_step_extraction/cfdna_post_extraction_quant/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "cfdna_post_extraction_quant": "action/workflow_step_extraction/cfdna_post_extraction_quant/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9294,22 +9294,22 @@
[
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
}
]
@@ -9321,7 +9321,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/cfdna/*"
+ "holds_content": "material/sample/cfdna/*"
}
}
]
@@ -9332,7 +9332,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/cfdna/*"
+ "holds_content": "material/sample/cfdna/*"
}
}
]
@@ -9343,7 +9343,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/cfdna/*"
+ "holds_content": "material/sample/cfdna/*"
}
}
]
@@ -9354,7 +9354,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/cfdna/*"
+ "holds_content": "material/sample/cfdna/*"
}
}
]
@@ -9384,7 +9384,7 @@
{
"name": "Extracting gdna from blood-whole in tubes to wells in a fixed-plate-96.",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "extraction-steps",
"subtype": "gdna-extraction",
"version": "1.0",
@@ -9395,10 +9395,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9414,22 +9414,22 @@
"expected_inputs": [
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
}
],
@@ -9440,7 +9440,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/gdna/*"
+ "holds_content": "material/sample/gdna/*"
}
}
]
@@ -9451,7 +9451,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/gdna/*"
+ "holds_content": "material/sample/gdna/*"
}
}
]
@@ -9462,7 +9462,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/gdna/*"
+ "holds_content": "material/sample/gdna/*"
}
}
]
@@ -9473,7 +9473,7 @@
"child_of_lineages": [
{
"container/well/fixed-plate-well/*/": {
- "holds_content": "content/sample/gdna/*"
+ "holds_content": "material/sample/gdna/*"
}
}
]
@@ -9503,7 +9503,7 @@
{
"name": "Loading blood-whole in tube-strek-10ml tubes.",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "extraction-steps",
"subtype": "loading",
"version": "1.0",
@@ -9514,10 +9514,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9533,22 +9533,22 @@
"expected_inputs": [
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
}
],
@@ -9575,7 +9575,7 @@
{
"name": "plasma isolation",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "extraction-steps",
"subtype": "plasma-isolated",
"version": "1.0",
@@ -9586,10 +9586,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9605,44 +9605,44 @@
"expected_inputs": [
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
},
{
"container/tube/tube-strek-10ml/*/": {
- "holds_content": "content/specimen/blood-whole/*"
+ "holds_content": "material/specimen/blood-whole/*"
}
}
],
"expected_outputs": [
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
},
{
"container/tube/tube-generic-10ml/*/": {
- "holds_content": "content/sample/blood-plasma/*"
+ "holds_content": "material/sample/blood-plasma/*"
}
}
],
@@ -9668,7 +9668,7 @@
{
"name": "Filled Extraction Plate",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "plate-operations",
"subtype": "extraction-plate-filled",
"version": "1.0",
@@ -9679,15 +9679,15 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "cfdna_quant": "BAC/workflow_step_plate_operations/cfdna_quant/1.0",
- "create_pool_from_containers": "BAC/pool/create_pool_from_containers__extraction_plate_filled/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_child_object": "BAC/object/set-child-object/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0",
- "stamp_copy_plate": "BAC/workflow_step_plate_operations/stamp_copy_plate/1.0",
- "stamp_plates_into_plate": "BAC/plate/stamp_plates_into_plate__extraction_plate_filled/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "cfdna_quant": "action/workflow_step_plate_operations/cfdna_quant/1.0",
+ "create_pool_from_containers": "action/pool/create_pool_from_containers__extraction_plate_filled/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_child_object": "action/object/set-child-object/1.0",
+ "set_object_status": "action/core/set_object_status/1.0",
+ "stamp_copy_plate": "action/workflow_step_plate_operations/stamp_copy_plate/1.0",
+ "stamp_plates_into_plate": "action/plate/stamp_plates_into_plate__extraction_plate_filled/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9731,7 +9731,7 @@
{
"name": "Heatseal Plate",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "plate-operations",
"subtype": "heat-seal",
"version": "1.0",
@@ -9742,10 +9742,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9790,7 +9790,7 @@
{
"name": "Existing plate, had 1+ plates merged into it.",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "plate-operations",
"subtype": "plate-added-to",
"version": "1.0",
@@ -9801,12 +9801,12 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "cfdna_quant": "BAC/workflow_step_plate_operations/cfdna_quant/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0",
- "stamp_copy_plate": "BAC/workflow_step_plate_operations/stamp_copy_plate/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "cfdna_quant": "action/workflow_step_plate_operations/cfdna_quant/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0",
+ "stamp_copy_plate": "action/workflow_step_plate_operations/stamp_copy_plate/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9843,7 +9843,7 @@
{
"name": "Stamp Copy Plate",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "plate-operations",
"subtype": "stamp-copy-plate",
"version": "1.0",
@@ -9854,12 +9854,12 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "cfdna_quant": "BAC/workflow_step_plate_operations/cfdna_quant/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0",
- "stamp_copy_plate": "BAC/workflow_step_plate_operations/stamp_copy_plate/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "cfdna_quant": "action/workflow_step_plate_operations/cfdna_quant/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0",
+ "stamp_copy_plate": "action/workflow_step_plate_operations/stamp_copy_plate/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9896,7 +9896,7 @@
{
"name": "pool",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "pool",
"subtype": "generic",
"version": "1.0",
@@ -9907,10 +9907,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9947,7 +9947,7 @@
{
"name": "OVERRIDEME",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "queue",
"subtype": "all-purpose",
"version": "1.0",
@@ -9958,10 +9958,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -9998,7 +9998,7 @@
{
"name": "Blood To gDNA Extraction Eligible",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "queue",
"subtype": "blood-to-gdna-extraction-eligible",
"version": "1.0",
@@ -10009,15 +10009,15 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_gdna_to_gdna_normalization_queue": "BAC/workflow_step_queue/add-gdna-to-gdna-normalization-queue/1.0",
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "existing_plate_fill_auto": "BAC/workflow_step_queue/existing-plate-fill-auto/1.0",
- "existing_plate_fill_directed": "BAC/workflow_step_queue/existing-plate-fill-directed/1.0",
- "plate_create_fill_auto": "BAC/workflow_step_queue/plate-create-fill-auto/1.0",
- "plate_create_fill_directed": "BAC/workflow_step_queue/plate-create-fill-directed/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_gdna_to_gdna_normalization_queue": "action/workflow_step_queue/add-gdna-to-gdna-normalization-queue/1.0",
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "existing_plate_fill_auto": "action/workflow_step_queue/existing-plate-fill-auto/1.0",
+ "existing_plate_fill_directed": "action/workflow_step_queue/existing-plate-fill-directed/1.0",
+ "plate_create_fill_auto": "action/workflow_step_queue/plate-create-fill-auto/1.0",
+ "plate_create_fill_directed": "action/workflow_step_queue/plate-create-fill-directed/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -10054,7 +10054,7 @@
{
"name": "Buccal To gDNA Extraction Eligible",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "queue",
"subtype": "buccal-to-gdna-extraction-eligible",
"version": "1.0",
@@ -10065,15 +10065,15 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_gdna_to_gdna_normalization_queue": "BAC/workflow_step_queue/add-gdna-to-gdna-normalization-queue/1.0",
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "existing_plate_fill_auto": "BAC/workflow_step_queue/existing-plate-fill-auto/1.0",
- "existing_plate_fill_directed": "BAC/workflow_step_queue/existing-plate-fill-directed/1.0",
- "plate_create_fill_auto": "BAC/workflow_step_queue/plate-create-fill-auto/1.0",
- "plate_create_fill_directed": "BAC/workflow_step_queue/plate-create-fill-directed/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_gdna_to_gdna_normalization_queue": "action/workflow_step_queue/add-gdna-to-gdna-normalization-queue/1.0",
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "existing_plate_fill_auto": "action/workflow_step_queue/existing-plate-fill-auto/1.0",
+ "existing_plate_fill_directed": "action/workflow_step_queue/existing-plate-fill-directed/1.0",
+ "plate_create_fill_auto": "action/workflow_step_queue/plate-create-fill-auto/1.0",
+ "plate_create_fill_directed": "action/workflow_step_queue/plate-create-fill-directed/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -10110,7 +10110,7 @@
{
"name": "Extraction Batch Eligible",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "queue",
"subtype": "extraction-batch-eligible",
"version": "1.0",
@@ -10121,12 +10121,12 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "add_to_blood_gdna_extraction_queue": "BAC/workflow_step_queue/add-to-blood-gdna-extraction-queue/1.0",
- "add_to_buccal_gdna_extraction_queue": "BAC/workflow_step_queue/add-to-buccal-gdna-extraction-queue/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "add_to_blood_gdna_extraction_queue": "action/workflow_step_queue/add-to-blood-gdna-extraction-queue/1.0",
+ "add_to_buccal_gdna_extraction_queue": "action/workflow_step_queue/add-to-buccal-gdna-extraction-queue/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -10163,7 +10163,7 @@
{
"name": "Plasma To Plates For Extraction",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "queue",
"subtype": "extraction-queue-available",
"version": "1.0",
@@ -10174,12 +10174,12 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "fill_plate_directed": "BAC/workflow_step_queue/fill_plate_directed/1.0",
- "fill_plate_undirected": "BAC/workflow_step_queue/fill_plate_undirected/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "fill_plate_directed": "action/workflow_step_queue/fill_plate_directed/1.0",
+ "fill_plate_undirected": "action/workflow_step_queue/fill_plate_undirected/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -10216,7 +10216,7 @@
{
"name": "Illumina Novaseq LibPrep Eligible",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "queue",
"subtype": "illumina-novaseq-libprep-eligible",
"version": "1.0",
@@ -10227,14 +10227,14 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "existing_plate_fill_auto": "BAC/workflow_step_queue/existing-plate-fill-auto/1.0",
- "existing_plate_fill_directed": "BAC/workflow_step_queue/existing-plate-fill-directed/1.0",
- "plate_create_fill_auto": "BAC/workflow_step_queue/plate-create-fill-auto/1.0",
- "plate_create_fill_directed": "BAC/workflow_step_queue/plate-create-fill-directed/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "existing_plate_fill_auto": "action/workflow_step_queue/existing-plate-fill-auto/1.0",
+ "existing_plate_fill_directed": "action/workflow_step_queue/existing-plate-fill-directed/1.0",
+ "plate_create_fill_auto": "action/workflow_step_queue/plate-create-fill-auto/1.0",
+ "plate_create_fill_directed": "action/workflow_step_queue/plate-create-fill-directed/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -10271,7 +10271,7 @@
{
"name": "Input gDNA Normalization Eligible",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "queue",
"subtype": "input-gdna-normalization-eligible",
"version": "1.0",
@@ -10282,15 +10282,15 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "existing_plate_fill_auto": "BAC/workflow_step_queue/existing-plate-fill-auto/1.0",
- "existing_plate_fill_directed": "BAC/workflow_step_queue/existing-plate-fill-directed/1.0",
- "plate_create_fill_auto": "BAC/workflow_step_queue/plate-create-fill-auto/1.0",
- "plate_create_fill_directed": "BAC/workflow_step_queue/plate-create-fill-directed/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "save_quant_data": "BAC/workflow_step_queue/save-quant-data/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "existing_plate_fill_auto": "action/workflow_step_queue/existing-plate-fill-auto/1.0",
+ "existing_plate_fill_directed": "action/workflow_step_queue/existing-plate-fill-directed/1.0",
+ "plate_create_fill_auto": "action/workflow_step_queue/plate-create-fill-auto/1.0",
+ "plate_create_fill_directed": "action/workflow_step_queue/plate-create-fill-directed/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "save_quant_data": "action/workflow_step_queue/save-quant-data/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -10327,7 +10327,7 @@
{
"name": "ONT LibPrep Eligible",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "queue",
"subtype": "ont-libprep-eligible",
"version": "1.0",
@@ -10338,14 +10338,14 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "existing_plate_fill_auto": "BAC/workflow_step_queue/existing-plate-fill-auto/1.0",
- "existing_plate_fill_directed": "BAC/workflow_step_queue/existing-plate-fill-directed/1.0",
- "plate_create_fill_auto": "BAC/workflow_step_queue/plate-create-fill-auto/1.0",
- "plate_create_fill_directed": "BAC/workflow_step_queue/plate-create-fill-directed/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "existing_plate_fill_auto": "action/workflow_step_queue/existing-plate-fill-auto/1.0",
+ "existing_plate_fill_directed": "action/workflow_step_queue/existing-plate-fill-directed/1.0",
+ "plate_create_fill_auto": "action/workflow_step_queue/plate-create-fill-auto/1.0",
+ "plate_create_fill_directed": "action/workflow_step_queue/plate-create-fill-directed/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -10382,7 +10382,7 @@
{
"name": "Containers available for plasma isolation in this queue.",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "queue",
"subtype": "plasma-isolation-queue-available",
"version": "1.0",
@@ -10393,11 +10393,11 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "link_tubes_auto": "BAC/workflow_step_queue/link_tubes_auto/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "link_tubes_auto": "action/workflow_step_queue/link_tubes_auto/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -10434,7 +10434,7 @@
{
"name": "Plasma Isolation Exception Queue",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "queue",
"subtype": "plasma-isolation-queue-exception",
"version": "1.0",
@@ -10445,12 +10445,12 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "link_tubes_auto": "BAC/workflow_step_queue/link_tubes_auto/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0",
- "ycreate_test_req_and_link_child_workflow_step": "BAC/workflow_step_queue/ycreate_test_req_and_link_child_workflow_step/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "link_tubes_auto": "action/workflow_step_queue/link_tubes_auto/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0",
+ "ycreate_test_req_and_link_child_workflow_step": "action/workflow_step_queue/ycreate_test_req_and_link_child_workflow_step/1.0"
},
"cogs": {
"allocation_type": "",
@@ -10501,7 +10501,7 @@
{
"name": "Containers Removed From Queue",
"polymorphic_discriminator": "workflow_step_template",
- "category": "BWS",
+ "category": "workflow_step",
"type": "queue",
"subtype": "plasma-isolation-queue-removed",
"version": "1.0",
@@ -10512,10 +10512,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -10563,7 +10563,7 @@
{
"name": "Sequencing Library Plate 96",
"polymorphic_discriminator": "container_template",
- "category": "BCP",
+ "category": "container",
"type": "plate",
"subtype": "sequencing-library-plate-96",
"version": "1.0",
@@ -10574,12 +10574,12 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "download_plate_map": "BAC/plate/download_plate_map/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0",
- "stamp_plates_into_plate": "BAC/plate/stamp_plates_into_plate/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "download_plate_map": "action/plate/download_plate_map/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0",
+ "stamp_plates_into_plate": "action/plate/stamp_plates_into_plate/1.0"
},
"cogs": {
"allocation_type": "",
@@ -12198,7 +12198,7 @@
{
"name": "Sequencing Index Plate 96",
"polymorphic_discriminator": "container_template",
- "category": "BCP",
+ "category": "container",
"type": "plate",
"subtype": "index-plate-96",
"version": "1.0",
@@ -12209,12 +12209,12 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "download_plate_map": "BAC/plate/download_plate_map/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0",
- "stamp_plates_into_plate": "BAC/plate/stamp_plates_into_plate/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "download_plate_map": "action/plate/download_plate_map/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0",
+ "stamp_plates_into_plate": "action/plate/stamp_plates_into_plate/1.0"
},
"cogs": {
"allocation_type": "",
@@ -13833,7 +13833,7 @@
{
"name": "Generic Reagent Bottle",
"polymorphic_discriminator": "container_template",
- "category": "BCB",
+ "category": "container",
"type": "bottle",
"subtype": "generic",
"version": "1.0",
@@ -13844,10 +13844,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -13881,7 +13881,7 @@
"container_role": "bottle"
},
"valid_content": [
- "content/.*"
+ "material/.*"
],
"valid_parents": [],
"semantic_category": "container"
@@ -13890,7 +13890,7 @@
{
"name": "Flowcell",
"polymorphic_discriminator": "container_template",
- "category": "BCF",
+ "category": "container",
"type": "flowcell",
"subtype": "generic",
"version": "1.0",
@@ -13901,10 +13901,10 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "print_barcode_label": "BAC/core/print_barcode_label/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "print_barcode_label": "action/core/print_barcode_label/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -13937,7 +13937,7 @@
"lab_code": ""
},
"valid_content": [
- "content/.*"
+ "material/.*"
],
"valid_parents": [],
"semantic_category": "container"
@@ -13946,7 +13946,7 @@
{
"name": "Flowcell Lane",
"polymorphic_discriminator": "container_template",
- "category": "BCE",
+ "category": "container",
"type": "flowcell_lane",
"subtype": "generic",
"version": "1.0",
@@ -13957,7 +13957,7 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "set_object_status": "action/core/set_object_status/1.0"
},
"cogs": {
"allocation_type": "",
@@ -13989,7 +13989,7 @@
},
"singleton": "0",
"valid_content": [
- "content/.*"
+ "material/.*"
],
"valid_parents": [
"container/plate/fixed-plate.*?/.*?"
@@ -14000,7 +14000,7 @@
{
"name": "Saliva Specimen",
"polymorphic_discriminator": "content_template",
- "category": "BNA",
+ "category": "material",
"type": "specimen",
"subtype": "saliva",
"version": "1.0",
@@ -14038,7 +14038,7 @@
{
"name": "Sequencing Library Content",
"polymorphic_discriminator": "content_template",
- "category": "BNQ",
+ "category": "material",
"type": "sample",
"subtype": "sequencing-library",
"version": "1.0",
@@ -14078,7 +14078,7 @@
{
"name": "Sequencing Library Pool Content",
"polymorphic_discriminator": "content_template",
- "category": "BNP",
+ "category": "material",
"type": "pool",
"subtype": "sequencing-library",
"version": "1.0",
@@ -14117,7 +14117,7 @@
{
"name": "Sequencing Index Reagent Content",
"polymorphic_discriminator": "content_template",
- "category": "BNX",
+ "category": "material",
"type": "reagent",
"subtype": "sequencing-index",
"version": "1.0",
@@ -14166,7 +14166,7 @@
{
"name": "gDNA Quantification Data",
"polymorphic_discriminator": "data_template",
- "category": "BDQ",
+ "category": "data",
"type": "quantification",
"subtype": "gdna",
"version": "1.0",
@@ -14177,9 +14177,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Generic data record",
"expected_inputs": [],
@@ -14207,7 +14207,7 @@
{
"name": "Extraction Run Evidence",
"polymorphic_discriminator": "data_template",
- "category": "BDX",
+ "category": "data",
"type": "operation",
"subtype": "extraction",
"version": "1.0",
@@ -14218,9 +14218,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Generic data record",
"expected_inputs": [],
@@ -14245,7 +14245,7 @@
{
"name": "Extraction QC Run Evidence",
"polymorphic_discriminator": "data_template",
- "category": "BDY",
+ "category": "data",
"type": "operation",
"subtype": "extraction-qc",
"version": "1.0",
@@ -14256,9 +14256,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Generic data record",
"expected_inputs": [],
@@ -14281,7 +14281,7 @@
{
"name": "Library Prep Run Evidence",
"polymorphic_discriminator": "data_template",
- "category": "BDP",
+ "category": "data",
"type": "operation",
"subtype": "library-prep",
"version": "1.0",
@@ -14292,9 +14292,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Generic data record",
"expected_inputs": [],
@@ -14317,7 +14317,7 @@
{
"name": "Pooling Run Evidence",
"polymorphic_discriminator": "data_template",
- "category": "BDN",
+ "category": "data",
"type": "operation",
"subtype": "pooling",
"version": "1.0",
@@ -14328,9 +14328,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Generic data record",
"expected_inputs": [],
@@ -14353,7 +14353,7 @@
{
"name": "Library Index Assignment Data",
"polymorphic_discriminator": "data_template",
- "category": "BDA",
+ "category": "data",
"type": "library-index-assignment",
"subtype": "sequencing-library",
"version": "1.0",
@@ -14364,9 +14364,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Generic data record",
"expected_inputs": [],
@@ -14391,7 +14391,7 @@
{
"name": "Transfer Execution Data",
"polymorphic_discriminator": "data_template",
- "category": "BDT",
+ "category": "data",
"type": "execution",
"subtype": "transfer",
"version": "1.0",
@@ -14402,9 +14402,9 @@
"json_addl": {
"action_groups": {},
"action_imports": {
- "add_relationships": "BAC/core/add-relationships/1.0",
- "create_subject_and_anchor": "BAC/core/create-subject-and-anchor/1.0",
- "set_object_status": "BAC/core/set_object_status/1.0"
+ "add_relationships": "action/core/add-relationships/1.0",
+ "create_subject_and_anchor": "action/core/create-subject-and-anchor/1.0",
+ "set_object_status": "action/core/set_object_status/1.0"
},
"description": "Generic data record",
"expected_inputs": [],
@@ -14427,9 +14427,9 @@
{
"name": "Bloom Anomaly Record",
"polymorphic_discriminator": "generic_template",
- "category": "BAN",
- "type": "ops",
- "subtype": "anomaly-record",
+ "category": "ops",
+ "type": "anomaly-record",
+ "subtype": "generic",
"version": "1.0",
"instance_prefix": "BAN",
"instance_polymorphic_identity": "generic_instance",
diff --git a/docs/apis.md b/docs/apis.md
index f283ea6..1f942d3 100644
--- a/docs/apis.md
+++ b/docs/apis.md
@@ -287,7 +287,7 @@ curl -k https://localhost:8912/api/v1/external/specimens \
-H "Idempotency-Key: atlas-specimen-001" \
-H "Content-Type: application/json" \
-d '{
- "specimen_template_code": "content/specimen/blood-whole/1.0",
+ "specimen_template_code": "material/specimen/blood-whole/1.0",
"specimen_name": "specimen-demo",
"status": "active",
"container_template_code": "container/tube/tube-generic-10ml/1.0",
diff --git a/docs/lab_actions.md b/docs/lab_actions.md
index 3b5ec61..f3d0031 100644
--- a/docs/lab_actions.md
+++ b/docs/lab_actions.md
@@ -19,16 +19,16 @@ The current flow uses the existing Bloom template pack plus one new generic run-
| Purpose | Semantic template path | Instance prefix | Notes |
|---|---|---:|---|
-| Generic run/set object | `set/run-set/generic/1.01` | `BGS` | New template. Seeded as `category=BGS`, `type=run-set`, `subtype=generic`, `version=1.01`. Holds named sets, run metadata, members, external members, status, and arbitrary metadata. |
+| Generic run/set object | `set/run-set/generic/1.01` | `BGS` | New template. Seeded as `category=set`, `type=run-set`, `subtype=generic`, `version=1.01`. Holds named sets, run metadata, members, external members, status, and arbitrary metadata. |
| Extraction plate | `container/plate/fixed-plate-96/1.0` | `BCP` | Existing recursive 96-well plate template. Creates linked well containers. |
| Sequencing-library plate | `container/plate/sequencing-library-plate-96/1.0` | `BCP` | Existing recursive 96-well plate template. Creates linked well containers. |
| Plate well | `container/well/fixed-plate-well/1.0` | `BCW` | Created by recursive plate templates. |
| Pool tube | `container/tube/tube-generic-10ml/1.0` | `BCT` | Existing generic tube template. More specific pool-tube templates can be added later if needed. |
-| Incoming specimen contents | `content/specimen/{blood-whole,buccal-swab,saliva}/1.0` | `BNB`, `BNS`, `BNA` | Existing whole-blood, buccal-swab, and saliva specimen templates. Incoming tubes must already hold one content object unless the caller creates/fills the tube first. |
-| Extraction well gDNA | `content/sample/gdna/1.0` | `BNG` | Created during extraction mapping. |
-| Sequencing-library content | `content/sample/sequencing-library/1.0` | `BNQ` | Created during library plate mapping. |
-| Sequencing-library pool content | `content/pool/sequencing-library/1.0` | `BNP` | Created when filling the pool tube. |
-| Sequencing index reagent | `content/reagent/sequencing-index/1.0` | `BNX` | Optional; callers may also store an index barcode string directly. |
+| Incoming specimen contents | `material/specimen/{blood-whole,buccal-swab,saliva}/1.0` | `BNB`, `BNS`, `BNA` | Existing whole-blood, buccal-swab, and saliva specimen templates. Incoming tubes must already hold one material object unless the caller creates/fills the tube first. |
+| Extraction well gDNA | `material/sample/gdna/1.0` | `BNG` | Created during extraction mapping. |
+| Sequencing-library content | `material/sample/sequencing-library/1.0` | `BNQ` | Created during library plate mapping. |
+| Sequencing-library pool content | `material/pool/sequencing-library/1.0` | `BNP` | Created when filling the pool tube. |
+| Sequencing index reagent | `material/reagent/sequencing-index/1.0` | `BNX` | Optional; callers may also store an index barcode string directly. |
| gDNA quant data | `data/quantification/gdna/1.0` | `BDQ` | Optional per-well extraction output data. |
No additional templates are required for the current implementation. The semantic paths above are the operator-facing shorthand used by the API and docs; the seed file stores Bloom's actual prefix-backed template identity in `category`, `type`, `subtype`, `version`, and `instance_prefix`. If production operators need separate EUID prefixes or stricter metadata for pool tubes, flowcells, reagent sets, or run kits, add those templates as a separate versioned template-pack change and update this matrix before production rollout.
diff --git a/docs/old_docs/ATLAS_BLOOM_CONTRACT_TESTS.md b/docs/old_docs/ATLAS_BLOOM_CONTRACT_TESTS.md
index 790482e..c77dc64 100644
--- a/docs/old_docs/ATLAS_BLOOM_CONTRACT_TESTS.md
+++ b/docs/old_docs/ATLAS_BLOOM_CONTRACT_TESTS.md
@@ -36,7 +36,7 @@ def test_create_container_contract(client):
```python
def test_specimen_crud_contract(client, container_euid):
create_payload = {
- "specimen_template_code": "content/specimen/blood-whole/1.0",
+ "specimen_template_code": "material/specimen/blood-whole/1.0",
"container_euid": container_euid,
"atlas_refs": {"trf_euid": "TRF-1", "patient_id": "PAT-1", "kit_barcode": "KIT-1"},
"properties": {"source": "atlas"},
diff --git a/docs/old_docs/TAPDB_SPECIFICATION.md b/docs/old_docs/TAPDB_SPECIFICATION.md
index b796a6d..4901180 100644
--- a/docs/old_docs/TAPDB_SPECIFICATION.md
+++ b/docs/old_docs/TAPDB_SPECIFICATION.md
@@ -998,7 +998,7 @@ Templates are identified by a **template code string** with the format:
**Examples:**
- `container/plate/fixed-plate-96/1.0/`
- `workflow/assay/ngs-library-prep/2.1/`
-- `content/sample/blood-specimen/1.0/`
+- `material/sample/blood-specimen/1.0/`
- `equipment/instrument/sequencer/1.0/`
### 4.2 Template JSON Structure
diff --git a/docs/plans/20260520T064952Z_bloom_sequencing_run_ledger.md b/docs/plans/20260520T064952Z_bloom_sequencing_run_ledger.md
index e7be661..9cb8007 100644
--- a/docs/plans/20260520T064952Z_bloom_sequencing_run_ledger.md
+++ b/docs/plans/20260520T064952Z_bloom_sequencing_run_ledger.md
@@ -15,7 +15,7 @@ Add a first-class Bloom sequencing run concept for the Dayhoff-deployed Bloom se
| Repo state | `git status --short --branch -> ## main...origin/main` |
| Instructions read | `/Users/jmajor/projects/mega_dayhoff/repos_work/bloom/AGENTS.md`, `/Users/jmajor/projects/mega_dayhoff/dayhoff/AGENTS.md`, `/Users/jmajor/.agents/AGENTS.md`, `/Users/jmajor/.agents/AGENTS.md~`, `/Users/jmajor/.codex/docs/plan-ledger-workflow.md`, `/Users/jmajor/projects/mega_dayhoff/repos_work/bloom/.augment/RULES.md` |
| Existing pool/run surface | `bloom_lims/api/v1/beta_lab.py` already exposes `POST /api/v1/external/atlas/beta/pools`, `POST /api/v1/external/atlas/beta/runs`, and `GET /api/v1/external/atlas/beta/runs/{run_euid}/resolve` |
-| Existing pool implementation | `bloom_lims/domain/beta_lab_stages.py::create_pool` already creates `content/pool/generic/1.0`, a pool tube, `contains` lineage, and `beta_pool_member` edges |
+| Existing pool implementation | `bloom_lims/domain/beta_lab_stages.py::create_pool` already creates `material/pool/generic/1.0`, a pool tube, `contains` lineage, and `beta_pool_member` edges |
| Existing run gap | `create_run` stores runs as `data/generic/generic/1.0` with `beta_kind=sequencing_run`; `BetaRunCreateRequest.platform` is `Literal["ILMN"]`; run properties do not have explicit `operator_start_datetime`, `sequencing_end_datetime`, `instrument_euid`, or run subtype |
| Template gap | `config/tapdb_templates/bloom/templates.json` has `data/wetlab/library_prep_output/1.0` and equipment sequencer templates, but no `data/sequencing_run/*/1.0` templates |
| Atlas boundary | Bloom `.augment/RULES.md` requires Bloom and Atlas to interact only through published APIs; this change will preserve existing external-reference lineage and not read/write Atlas DBs |
@@ -29,7 +29,7 @@ Add a first-class Bloom sequencing run concept for the Dayhoff-deployed Bloom se
| BSR-001 | Template pack | Add first-class sequencing run templates with subtypes for Illumina, ONT, and NovaSeq. | SUCCESS | feature_implementation | Gate 3 | orchestrator | `config/tapdb_templates/bloom/templates.json`; live seed verified `BDT/sequencing_run/{illumina,novaseq,ont}/1.0` with EUIDs `Z-TPX-50P`, `Z-TPX-52J`, `Z-TPX-51M` | Missing template-backed sequencing-run data records; runs were generic data rows. | Added and seeded three Bloom-owned sequencing run templates. |
| BSR-002 | API schema | Extend beta run create/response schema with run subtype, operator start datetime, sequencing end datetime, and instrument linkage while preserving explicit validation. | SUCCESS | feature_implementation | Gate 3 | orchestrator | `bloom_lims/schemas/beta_lab.py`; public `https://bloom.dev.lsmc.life/openapi.json` exposes `platform` enum `ILMN,ONT`, `run_subtype`, `operator_start_datetime`, `sequencing_end_datetime`, and `instrument_euid` | Existing beta run schema only modeled ILMN flowcell runs. | Schema accepts Illumina, ONT, NovaSeq subtype contract and rejects mismatched platform/subtype and naive/out-of-order datetimes. |
| BSR-003 | Domain persistence | Store sequencing runs using the subtype-specific sequencing run template, link optional instrument via existing `beta_used_instrument`, and preserve pool/library/assignment lineage. | SUCCESS | feature_implementation | Gate 3 | orchestrator | `bloom_lims/domain/beta_lab.py`, `bloom_lims/domain/beta_lab_store.py`, `bloom_lims/domain/beta_lab_stages.py`; local DB-backed `tests/test_queue_flow.py::test_beta_queue_flow_end_to_end` verifies run instance `type=sequencing_run`, `subtype=novaseq`, persisted timing fields, and `beta_used_instrument` lineage | Persistence always created `data/generic/generic/1.0` rows for sequencing runs. | Run creation now chooses `data/sequencing_run/{illumina,ont,novaseq}/1.0` and still keeps pool, library assignment, artifact, and Atlas fulfillment lineage. |
-| BSR-004 | Pool assessment | Verify whether pooled sequencing library already exists and avoid adding a duplicate concept if current `content/pool/generic/1.0` plus pool tube/member lineage satisfies the request. | SUCCESS | feature_implementation | Gate 3 | orchestrator | Existing `create_pool` creates `content/pool/generic/1.0`, pool tube, `contains`, and `beta_pool_member` edges; `tests/test_queue_flow.py::test_beta_queue_flow_end_to_end` exercises that pool before creating the run | Pool concept was uncertain, but not absent. | No duplicate pool model added; existing pool content plus container/member lineage satisfies the request. |
+| BSR-004 | Pool assessment | Verify whether pooled sequencing library already exists and avoid adding a duplicate concept if current `material/pool/generic/1.0` plus pool tube/member lineage satisfies the request. | SUCCESS | feature_implementation | Gate 3 | orchestrator | Existing `create_pool` creates `material/pool/generic/1.0`, pool tube, `contains`, and `beta_pool_member` edges; `tests/test_queue_flow.py::test_beta_queue_flow_end_to_end` exercises that pool before creating the run | Pool concept was uncertain, but not absent. | No duplicate pool model added; existing pool content plus container/member lineage satisfies the request. |
| BSR-005 | Tests | Add focused tests for sequencing run templates, schema validation, persisted run fields, instrument linkage, and existing pool lineage. | SUCCESS | contract_test | Gate 5 | orchestrator | `pytest tests/test_sequencing_run_contract.py tests/test_queue_flow.py::test_beta_queue_flow_end_to_end tests/test_run_resolver.py::test_run_resolver_returns_404_for_unknown_index -q --no-cov` -> `4 passed`; `jq empty config/tapdb_templates/bloom/templates.json`; `git diff --check` | Contract needed coverage for template loadability and first-class run persistence. | Focused local tests pass. |
| BSR-006 | Live deploy | Patch AWS-deployed Bloom, seed any new Bloom-owned templates, restart only Bloom, and verify public/auth/readiness behavior. | SUCCESS | contract_test | Gate 5 | orchestrator | Live target `i-09126000eb19643b0`, repo `/home/ubuntu/.cache/dayhoff/local/lsmcok1/repos/bloom`, config `/home/ubuntu/.config/bloom-lsmcok1/bloom-config-lsmcok1.yaml`; `bloom --config ... db seed` -> `seed=ok`; old Bloom PID `238229`, new Bloom PID `264810`; `https://bloom.dev.lsmc.life/readyz` -> `ready=true`, DB `status=ok` | AWS Bloom needed the same template/schema/domain patch and live TapDB seed. | AWS Bloom patched, templates seeded, and only Bloom restarted. |
diff --git a/docs/plans/20260618T000000Z_bloom_lab_action_flow_ledger.md b/docs/plans/20260618T000000Z_bloom_lab_action_flow_ledger.md
index a2befa9..b9d5ade 100644
--- a/docs/plans/20260618T000000Z_bloom_lab_action_flow_ledger.md
+++ b/docs/plans/20260618T000000Z_bloom_lab_action_flow_ledger.md
@@ -15,7 +15,7 @@ Build a Bloom-owned lab actions layer for extraction plates, sequencing library
- Existing primitives found:
- recursive template create in `BloomObj.create_instances`
- `container/plate/fixed-plate-96/1.0`, `container/plate/sequencing-library-plate-96/1.0`, `container/well/fixed-plate-well/1.0`
- - `content/sample/gdna/1.0`, `content/sample/sequencing-library/1.0`, `content/pool/sequencing-library/1.0`, `content/reagent/sequencing-index/1.0`
+ - `material/sample/gdna/1.0`, `material/sample/sequencing-library/1.0`, `material/pool/sequencing-library/1.0`, `material/reagent/sequencing-index/1.0`
- `data/quantification/gdna/1.0`, `data/sequencing_run/*/1.0`
- Zebra Day service wrapper for print dispatch
@@ -57,19 +57,19 @@ Build a Bloom-owned lab actions layer for extraction plates, sequencing library
- `source ./activate dev && python -m pytest tests/test_lab_actions_api.py tests/test_bloom_prefix_taxonomy.py::test_wet_lab_templates_use_bloom_prefix_taxonomy tests/test_route_coverage_gaps_api.py::test_object_creation_plate_creates_96_linked_wells tests/test_template_instantiation_recursion.py tests/test_api_v1.py::TestObjectCreationAPI tests/test_api_v1.py::TestObjectCreationPathTraversal -q --cov-reset --cov=bloom_lims.api.v1.lab_actions --cov=bloom_lims.domain.lab_actions --cov=bloom_lims.schemas.lab_actions --cov=bloom_lims.api.v1.object_creation --cov=bloom_lims.schemas.objects --cov-report=term-missing --cov-report=json:coverage-lab-actions.json --cov-fail-under=81` -> 30 passed; total changed-surface coverage 83.81%.
- Full repo test collection is not clean in the local Bloom env: `tests/test_beta_cross_repo_smoke.py` imports Ursa and requires `daylily-ephemeral-cluster`; broad non-E2E collection also stalled before progress in local subprocess handling. These are not lab-action source failures.
- Template inventory from `config/tapdb_templates/bloom/templates.json` confirmed these seeded records for the lab-action flow:
- - `BGS/run-set/generic/1.01`
- - `BCP/plate/fixed-plate-96/1.0`
- - `BCP/plate/sequencing-library-plate-96/1.0`
- - `BCW/well/fixed-plate-well/1.0`
- - `BCT/tube/tube-generic-10ml/1.0`
- - `BNB/specimen/blood-whole/1.0`
- - `BNS/specimen/buccal-swab/1.0`
- - `BNA/specimen/saliva/1.0`
- - `BNG/sample/gdna/1.0`
- - `BNQ/sample/sequencing-library/1.0`
- - `BNP/pool/sequencing-library/1.0`
- - `BNX/reagent/sequencing-index/1.0`
- - `BDQ/quantification/gdna/1.0`
+ - `set/run-set/generic/1.01`
+ - `container/plate/fixed-plate-96/1.0`
+ - `container/plate/sequencing-library-plate-96/1.0`
+ - `container/well/fixed-plate-well/1.0`
+ - `container/tube/tube-generic-10ml/1.0`
+ - `material/specimen/blood-whole/1.0`
+ - `material/specimen/buccal-swab/1.0`
+ - `material/specimen/saliva/1.0`
+ - `material/sample/gdna/1.0`
+ - `material/sample/sequencing-library/1.0`
+ - `material/pool/sequencing-library/1.0`
+ - `material/reagent/sequencing-index/1.0`
+ - `data/quantification/gdna/1.0`
- Local browser proof used repo test-runtime config plus `BLOOM_OAUTH=no`; Playwright captured `/lab-actions` at `output/playwright/bloom_lab_actions/lab_actions_wizard_local.png`.
- Local browser console still shows the pre-existing `/api/v1/me/preferences` 503 under test-runtime config; `/lab-actions` itself returned 200 and static assets loaded.
- Docs pass added `docs/lab_actions.md` and linked it from `README.md`, `docs/apis.md`, `docs/gui.md`, and `docs/architecture.md`.
diff --git a/pyproject.toml b/pyproject.toml
index 0c96472..f6171e5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -28,7 +28,7 @@ license = {text = "MIT"}
requires-python = ">=3.12"
dependencies = [
"cli-core-yo==2.1.1",
- "daylily-tapdb @ git+https://github.com/Daylily-Informatics/daylily-tapdb.git@9.0.5",
+ "daylily-tapdb @ git+https://github.com/Daylily-Informatics/daylily-tapdb.git@9.0.6",
"daylily-auth-cognito==2.1.5",
"IPython>=8.18.1",
"bandit[toml]>=1.8.0",
diff --git a/tests/test_atlas_workflow_contract.py b/tests/test_atlas_workflow_contract.py
index 3d2eb6d..070cf54 100644
--- a/tests/test_atlas_workflow_contract.py
+++ b/tests/test_atlas_workflow_contract.py
@@ -142,7 +142,7 @@ def _create_specimen_payload(
container_euid: str | None = None,
) -> dict:
payload = {
- "specimen_template_code": "content/specimen/blood-whole/1.0",
+ "specimen_template_code": "material/specimen/blood-whole/1.0",
"specimen_name": f"specimen-{_suffix()}",
"status": "active",
"properties": {"source": "atlas-contract-test"},
@@ -260,7 +260,7 @@ def get_container_trf_context(
"/api/v1/external/specimens",
headers={"Idempotency-Key": _opaque("idem", 16)},
json={
- "specimen_template_code": "content/specimen/blood-whole/1.0",
+ "specimen_template_code": "material/specimen/blood-whole/1.0",
"specimen_name": "context-mismatch",
"container_euid": container["euid"],
"status": "active",
@@ -315,7 +315,7 @@ def get_container_trf_context(
created = _create_specimen(
client,
payload={
- "specimen_template_code": "content/specimen/blood-whole/1.0",
+ "specimen_template_code": "material/specimen/blood-whole/1.0",
"specimen_name": "context-match",
"container_euid": container["euid"],
"status": "active",
@@ -408,7 +408,7 @@ def test_unsupported_template_returns_validation_error(monkeypatch):
response = client.post(
"/api/v1/external/specimens",
json={
- "specimen_template_code": "content/specimen/saliva/1.0",
+ "specimen_template_code": "material/specimen/saliva/1.0",
"specimen_name": "unsupported-template",
"status": "active",
"atlas_refs": {"patient_id": f"PAT-{_suffix()}"},
diff --git a/tests/test_bloom_prefix_taxonomy.py b/tests/test_bloom_prefix_taxonomy.py
index 12b3181..901f31d 100644
--- a/tests/test_bloom_prefix_taxonomy.py
+++ b/tests/test_bloom_prefix_taxonomy.py
@@ -24,9 +24,8 @@ def _template_pack() -> dict:
def _templates_by_code() -> dict[str, dict]:
templates: dict[str, dict] = {}
for template in _template_pack()["templates"]:
- semantic_category = template["json_addl"].get("semantic_category")
code = (
- f"{semantic_category}/{template['type']}/"
+ f"{template['category']}/{template['type']}/"
f"{template['subtype']}/{template['version']}"
)
templates[code] = template
@@ -45,14 +44,14 @@ def test_wet_lab_templates_use_bloom_prefix_taxonomy() -> None:
"container/bottle/generic/1.0": "BCB",
"container/flowcell/generic/1.0": "BCF",
"container/flowcell_lane/generic/1.0": "BCE",
- "content/specimen/blood-whole/1.0": "BNB",
- "content/specimen/buccal-swab/1.0": "BNS",
- "content/specimen/saliva/1.0": "BNA",
- "content/sample/gdna/1.0": "BNG",
- "content/sample/cfdna/1.0": "BNC",
- "content/sample/sequencing-library/1.0": "BNQ",
- "content/pool/sequencing-library/1.0": "BNP",
- "content/reagent/sequencing-index/1.0": "BNX",
+ "material/specimen/blood-whole/1.0": "BNB",
+ "material/specimen/buccal-swab/1.0": "BNS",
+ "material/specimen/saliva/1.0": "BNA",
+ "material/sample/gdna/1.0": "BNG",
+ "material/sample/cfdna/1.0": "BNC",
+ "material/sample/sequencing-library/1.0": "BNQ",
+ "material/pool/sequencing-library/1.0": "BNP",
+ "material/reagent/sequencing-index/1.0": "BNX",
"data/generic/gdna-quantification/1.0": "BDQ",
"data/quantification/gdna/1.0": "BDQ",
"data/operation/extraction/1.0": "BDX",
@@ -67,7 +66,7 @@ def test_wet_lab_templates_use_bloom_prefix_taxonomy() -> None:
for code, expected_prefix in expected_prefixes.items():
template = templates[code]
- assert template["category"] == expected_prefix
+ assert template["category"] != expected_prefix
assert template["instance_prefix"] == expected_prefix
@@ -82,7 +81,7 @@ def test_anomaly_template_is_packaged_for_observability() -> None:
template["subtype"],
template["version"],
)
- == ("BAN", "ops", "anomaly-record", "1.0")
+ == ("ops", "anomaly-record", "generic", "1.0")
)
assert anomaly["instance_prefix"] == "BAN"
@@ -171,12 +170,10 @@ def test_readme_documents_taxonomy_and_historical_object_rule() -> None:
readme = (PROJECT_ROOT / "README.md").read_text(encoding="utf-8")
for snippet in (
- "BC*` | Containers",
- "BN*` | Contents, materials, and reagents",
- "BD*` | Data and evidence objects",
- "BR*` | Runs and executions",
- "BG*` | Generic helpers and external-object mappings",
+ "Bloom models physical/material execution",
+ "containers, materials/content, equipment",
+ "recursive template creation",
"Existing historical objects keep their already minted EUIDs",
- "Prefixes are governance and display labels only",
+ "issuance and governance labels only",
):
assert snippet in readme
diff --git a/tests/test_cli_db_command_paths.py b/tests/test_cli_db_command_paths.py
index ff04b28..d9aba92 100644
--- a/tests/test_cli_db_command_paths.py
+++ b/tests/test_cli_db_command_paths.py
@@ -489,23 +489,23 @@ def test_seed_templates_split_core_and_client_ownership(
lambda _dirs, strict: (
[
{
- "category": "SYS",
- "type": "system",
- "subtype": "config",
+ "category": "actor",
+ "type": "user",
+ "subtype": "system",
"version": "1.0",
"instance_prefix": "SYS",
"_source_file": str(core_template_path),
},
{
- "category": "XRF",
- "type": "reference",
- "subtype": "external_object",
+ "category": "reference",
+ "type": "external_identifier",
+ "subtype": "tapdb_object",
"version": "1.0",
"instance_prefix": "XRF",
"_source_file": str(core_template_path),
},
{
- "category": "BAC",
+ "category": "action",
"type": "beta_lab",
"subtype": "claim_material_in_queue",
"version": "1.0",
@@ -615,31 +615,34 @@ def dispose(self):
def test_retire_obsolete_template_variants_only_deletes_stale_prefixes() -> None:
templates = [
{
- "category": "BRM",
+ "category": "data",
"type": "sequencing_run",
"subtype": "illumina",
"version": "1.0",
+ "instance_prefix": "BRM",
"json_addl": {"semantic_category": "data"},
},
{
- "category": "BRN",
+ "category": "data",
"type": "sequencing_run",
"subtype": "ont",
"version": "1.0",
+ "instance_prefix": "BRN",
"json_addl": {"semantic_category": "data"},
},
{
- "category": "BCT",
+ "category": "container",
"type": "tube",
"subtype": "tube-generic-10ml",
"version": "1.0",
+ "instance_prefix": "BCN",
"json_addl": {"semantic_category": "container"},
},
]
current = SimpleNamespace(
domain_code="Z",
type="sequencing_run",
- category="BRM",
+ category="data",
subtype="illumina",
version="1.0",
is_deleted=False,
@@ -728,14 +731,16 @@ def flush(self):
domain_code="Z",
)
- assert retired == 2
+ assert retired == 4
assert current.is_deleted is False
assert stale_prefix.is_deleted is True
assert stale_prefix.bstatus == "retired"
- assert stale_subtype.is_deleted is False
+ assert stale_subtype.is_deleted is True
+ assert stale_subtype.bstatus == "retired"
assert stale_container_prefix.is_deleted is True
assert stale_container_prefix.bstatus == "retired"
- assert non_data.is_deleted is False
+ assert non_data.is_deleted is True
+ assert non_data.bstatus == "retired"
assert fake_session.flushed == 1
diff --git a/tests/test_core_validation.py b/tests/test_core_validation.py
index 0301f3d..388e728 100644
--- a/tests/test_core_validation.py
+++ b/tests/test_core_validation.py
@@ -224,7 +224,7 @@ def test_valid_reference_pattern(self):
# Valid patterns
assert validator._is_valid_reference("action/generic/test/1.0")
assert validator._is_valid_reference("workflow/dna_extraction/v1/1.0")
- assert validator._is_valid_reference("content/sample/blood/*/")
+ assert validator._is_valid_reference("material/sample/blood/*/")
# Invalid patterns
assert not validator._is_valid_reference("invalid")
diff --git a/tests/test_packaging_metadata.py b/tests/test_packaging_metadata.py
index 0aa2123..63c5e79 100644
--- a/tests/test_packaging_metadata.py
+++ b/tests/test_packaging_metadata.py
@@ -15,7 +15,7 @@ def test_project_dependencies_pin_release_train_versions() -> None:
assert "cli-core-yo==2.1.1" in dependencies
assert "daylily-auth-cognito==2.1.5" in dependencies
- assert "daylily-tapdb @ git+https://github.com/Daylily-Informatics/daylily-tapdb.git@9.0.4" in dependencies
+ assert "daylily-tapdb @ git+https://github.com/Daylily-Informatics/daylily-tapdb.git@9.0.6" in dependencies
assert "IPython>=8.18.1" in dependencies
assert "psycopg2-binary==2.9.12" in dependencies
assert not any(str(dep).startswith("zebra-day") for dep in dependencies)
diff --git a/tests/test_sequencing_run_contract.py b/tests/test_sequencing_run_contract.py
index cb6d1c2..d689d84 100644
--- a/tests/test_sequencing_run_contract.py
+++ b/tests/test_sequencing_run_contract.py
@@ -63,7 +63,7 @@ def test_sequencing_run_templates_are_shipped_for_tapdb_seed():
for template_key, (platform, instance_prefix) in expected.items():
template = templates[template_key]
props = template["json_addl"]["properties"]
- assert template["category"] == instance_prefix
+ assert template["category"] == "data"
assert template["instance_prefix"] == instance_prefix
assert template["json_addl"]["semantic_category"] == "data"
assert props["beta_kind"] == "sequencing_run"
diff --git a/uv.lock b/uv.lock
index 335c05a..74ffb0e 100644
--- a/uv.lock
+++ b/uv.lock
@@ -200,7 +200,7 @@ requires-dist = [
{ name = "cli-core-yo", specifier = "==2.1.1" },
{ name = "daylily-auth-cognito", specifier = "==2.1.5" },
{ name = "daylily-carrier-tracking", specifier = "==0.5.1" },
- { name = "daylily-tapdb", git = "https://github.com/Daylily-Informatics/daylily-tapdb.git?rev=9.0.5" },
+ { name = "daylily-tapdb", git = "https://github.com/Daylily-Informatics/daylily-tapdb.git?rev=9.0.6" },
{ name = "djlint" },
{ name = "fastapi", specifier = ">=0.110.0" },
{ name = "httpx", specifier = ">=0.27.2" },
@@ -704,8 +704,8 @@ wheels = [
[[package]]
name = "daylily-tapdb"
-version = "9.0.5"
-source = { git = "https://github.com/Daylily-Informatics/daylily-tapdb.git?rev=9.0.5#0230d3c9bc8e3ef49e948ce3f8a7169b8e90a0be" }
+version = "9.0.6"
+source = { git = "https://github.com/Daylily-Informatics/daylily-tapdb.git?rev=9.0.6#ea195137638d1cc49b4499c9bf778c57b6d70d9b" }
dependencies = [
{ name = "cli-core-yo" },
{ name = "jsonschema" },
From af6b81bbf69e8096f538018e5771220451a01abb Mon Sep 17 00:00:00 2001
From: John Major
Date: Fri, 19 Jun 2026 09:50:38 -0700
Subject: [PATCH 44/47] Add Bloom container action API and GUI
---
bloom_lims/api/v1/__init__.py | 3 +
bloom_lims/api/v1/container_actions.py | 248 ++++++++++++++++++++++++
bloom_lims/gui/routes/modern.py | 13 ++
templates/modern/base.html | 3 +
templates/modern/container_actions.html | 155 +++++++++++++++
tests/test_lab_actions_api.py | 108 +++++++++++
6 files changed, 530 insertions(+)
create mode 100644 bloom_lims/api/v1/container_actions.py
create mode 100644 templates/modern/container_actions.html
diff --git a/bloom_lims/api/v1/__init__.py b/bloom_lims/api/v1/__init__.py
index 0c03ab7..7fd8888 100644
--- a/bloom_lims/api/v1/__init__.py
+++ b/bloom_lims/api/v1/__init__.py
@@ -21,6 +21,7 @@
from .batch import router as batch_router
from .beta_lab import router as beta_lab_router
from .containers import router as containers_router
+from .container_actions import router as container_actions_router
from .content import router as content_router
from .equipment import router as equipment_router
from .execution_queue import router as execution_queue_router
@@ -45,6 +46,7 @@
router.include_router(auth_router)
router.include_router(preferences_router)
router.include_router(containers_router)
+router.include_router(container_actions_router)
router.include_router(content_router)
router.include_router(equipment_router)
router.include_router(execution_queue_router)
@@ -77,6 +79,7 @@ async def api_v1_info():
"objects": "/api/v1/objects",
"auth": "/api/v1/auth",
"containers": "/api/v1/containers",
+ "container_actions": "/api/v1/container-actions",
"content": "/api/v1/content",
"equipment": "/api/v1/equipment",
"execution": "/api/v1/execution",
diff --git a/bloom_lims/api/v1/container_actions.py b/bloom_lims/api/v1/container_actions.py
new file mode 100644
index 0000000..440324f
--- /dev/null
+++ b/bloom_lims/api/v1/container_actions.py
@@ -0,0 +1,248 @@
+"""Generic Bloom container-action validation facade."""
+
+from __future__ import annotations
+
+import csv
+from io import StringIO
+from typing import Any, Literal
+
+from fastapi import APIRouter, Depends, HTTPException
+from pydantic import BaseModel, Field, ValidationError
+from sqlalchemy import select
+
+from bloom_lims.tapdb_adapter import BLOOMdb3, generic_instance
+from bloom_lims.domain.lab_actions import LabActionsService
+from bloom_lims.schemas.lab_actions import (
+ ExtractionPlateRequest,
+ ExtractionQcPlateRequest,
+ LabSetRequest,
+ PlateWellDataRequest,
+ PrintEuidRequest,
+ SeqLibraryPlateRequest,
+ SeqLibraryPoolRequest,
+ SeqRunSetRequest,
+)
+
+from .dependencies import APIUser, require_write
+
+router = APIRouter(prefix="/container-actions", tags=["Container Actions"])
+
+
+class ContainerActionScanRequest(BaseModel):
+ rows: str | None = None
+ records: list[dict[str, Any]] = Field(default_factory=list)
+ default_target: str | None = None
+ child_name: str | None = None
+ child_description: str | None = None
+ child_content_type: str | None = None
+
+
+ContainerActionOperation = Literal[
+ "extraction_plate",
+ "extraction_qc_plate",
+ "plate_well_data",
+ "seq_library_plate",
+ "seq_library_pool",
+ "seq_run_set",
+ "lab_set",
+ "print_euids",
+]
+
+
+class ContainerActionExecuteRequest(ContainerActionScanRequest):
+ operation_type: ContainerActionOperation | None = None
+ operation_payload: dict[str, Any] | None = None
+
+
+def _service_for_user(user: APIUser) -> LabActionsService:
+ return LabActionsService(
+ BLOOMdb3(app_username=user.email),
+ user_id=user.user_id,
+ email=user.email,
+ )
+
+
+def _split_source(value: str) -> tuple[str, str | None]:
+ source = str(value or "").strip()
+ if not source:
+ raise ValueError("source EUID is required")
+ if "." not in source:
+ return source, None
+ euid, well = source.rsplit(".", 1)
+ euid = euid.strip()
+ well = well.strip().upper()
+ if not euid or not well:
+ raise ValueError(f"Invalid source well reference: {value!r}")
+ return euid, well
+
+
+def _normalize_record(row: dict[str, Any], default_target: str | None) -> dict[str, Any]:
+ source = row.get("source") or row.get("source_euid") or row.get("euid") or row.get("0")
+ target = (
+ row.get("target")
+ or row.get("target_container_euid")
+ or row.get("target_container")
+ or row.get("1")
+ or default_target
+ )
+ target_well = row.get("target_well") or row.get("well") or row.get("2")
+ source_euid, source_well = _split_source(str(source or ""))
+ target_text = str(target or "").strip()
+ if not target_text:
+ raise ValueError(f"Target is required for source {source_euid}")
+ create_type = None
+ target_euid = target_text
+ if target_text.upper().startswith("CREATE."):
+ create_type = target_text.split(".", 1)[1].strip()
+ target_euid = None
+ if not create_type:
+ raise ValueError(f"CREATE target requires a type for source {source_euid}")
+ return {
+ "source_euid": source_euid,
+ "source_well": source_well,
+ "target_euid": target_euid,
+ "create_type": create_type,
+ "target_well": str(target_well or "").strip().upper() or None,
+ "mapping_mode": "directed" if target_well else "auto",
+ }
+
+
+def _parse_rows(payload: ContainerActionScanRequest) -> list[dict[str, Any]]:
+ records = list(payload.records)
+ if payload.rows:
+ sample = payload.rows[:1024]
+ try:
+ dialect = csv.Sniffer().sniff(sample, delimiters=",\t")
+ except csv.Error:
+ dialect = csv.excel
+ reader = csv.reader(StringIO(payload.rows), dialect)
+ for row in reader:
+ if not row or not any(str(cell).strip() for cell in row):
+ continue
+ records.append({str(index): value for index, value in enumerate(row)})
+ if not records:
+ raise ValueError("rows or records is required")
+ return [_normalize_record(row, payload.default_target) for row in records]
+
+
+def _object_kind(euid: str, user: APIUser) -> dict[str, Any]:
+ db = BLOOMdb3(app_username=user.email)
+ try:
+ instance = db.session.execute(
+ select(generic_instance).where(
+ generic_instance.euid == euid,
+ generic_instance.is_deleted.is_(False),
+ )
+ ).scalar_one_or_none()
+ if instance is None:
+ return {"euid": euid, "exists": False, "kind": None}
+ return {
+ "euid": euid,
+ "exists": True,
+ "kind": "/".join(
+ [
+ str(getattr(instance, "category", "") or ""),
+ str(getattr(instance, "type", "") or ""),
+ str(getattr(instance, "subtype", "") or ""),
+ str(getattr(instance, "version", "") or ""),
+ ]
+ ),
+ }
+ finally:
+ db.close()
+
+
+@router.post("/validate")
+async def validate_container_action(
+ payload: ContainerActionScanRequest,
+ user: APIUser = Depends(require_write),
+):
+ try:
+ planned = _parse_rows(payload)
+ source_types = {row["source_euid"]: _object_kind(row["source_euid"], user) for row in planned}
+ target_types = {
+ row["target_euid"]: _object_kind(row["target_euid"], user)
+ for row in planned
+ if row["target_euid"]
+ }
+ return {
+ "valid": True,
+ "row_count": len(planned),
+ "planned": planned,
+ "source_types": source_types,
+ "target_types": target_types,
+ "creates": [row for row in planned if row["create_type"]],
+ }
+ except (ValueError, ValidationError) as exc:
+ raise HTTPException(status_code=400, detail=str(exc)) from exc
+
+
+@router.post("/execute")
+async def execute_container_action(
+ payload: ContainerActionExecuteRequest,
+ user: APIUser = Depends(require_write),
+):
+ validation = await validate_container_action(payload, user)
+ if not payload.operation_type:
+ raise HTTPException(
+ status_code=400,
+ detail={
+ "message": (
+ "operation_type is required. Container actions do not infer "
+ "execution behavior from scanned rows."
+ ),
+ "validation": validation,
+ },
+ )
+ if not payload.operation_payload:
+ raise HTTPException(
+ status_code=400,
+ detail={
+ "message": "operation_payload is required for container-action execution.",
+ "operation_type": payload.operation_type,
+ "validation": validation,
+ },
+ )
+
+ service = _service_for_user(user)
+ try:
+ operation_payload = payload.operation_payload
+ if payload.operation_type == "extraction_plate":
+ result = service.create_extraction_plate(
+ ExtractionPlateRequest.model_validate(operation_payload)
+ )
+ elif payload.operation_type == "extraction_qc_plate":
+ result = service.fill_extraction_qc_plate(
+ ExtractionQcPlateRequest.model_validate(operation_payload)
+ )
+ elif payload.operation_type == "plate_well_data":
+ result = service.attach_plate_well_data(
+ PlateWellDataRequest.model_validate(operation_payload)
+ )
+ elif payload.operation_type == "seq_library_plate":
+ result = service.create_seq_library_plate(
+ SeqLibraryPlateRequest.model_validate(operation_payload)
+ )
+ elif payload.operation_type == "seq_library_pool":
+ result = service.create_seq_library_pool(
+ SeqLibraryPoolRequest.model_validate(operation_payload)
+ )
+ elif payload.operation_type == "seq_run_set":
+ result = service.create_seq_run_set(
+ SeqRunSetRequest.model_validate(operation_payload)
+ )
+ elif payload.operation_type == "lab_set":
+ result = service.create_lab_set(LabSetRequest.model_validate(operation_payload))
+ elif payload.operation_type == "print_euids":
+ result = service.print_euids(PrintEuidRequest.model_validate(operation_payload))
+ else: # pragma: no cover - Literal validation should prevent this.
+ raise HTTPException(status_code=400, detail="Unsupported operation_type")
+ return {
+ "operation_type": payload.operation_type,
+ "validation": validation,
+ "result": result,
+ }
+ except ValueError as exc:
+ raise HTTPException(status_code=400, detail=str(exc)) from exc
+ finally:
+ service.close()
diff --git a/bloom_lims/gui/routes/modern.py b/bloom_lims/gui/routes/modern.py
index abff4b4..27a57c3 100644
--- a/bloom_lims/gui/routes/modern.py
+++ b/bloom_lims/gui/routes/modern.py
@@ -175,6 +175,19 @@ async def lab_actions_wizard(request: Request, _auth=Depends(require_auth)):
return HTMLResponse(content=template.render(context), status_code=200)
+@router.get("/container-actions", response_class=HTMLResponse)
+async def container_actions_wizard(request: Request, _auth=Depends(require_auth)):
+ user_data = request.session.get("user_data", {})
+ template = templates.get_template("modern/container_actions.html")
+ context = {
+ "request": request,
+ "udat": user_data,
+ "user": user_data,
+ "page_title": "Container Actions",
+ }
+ return HTMLResponse(content=template.render(context), status_code=200)
+
+
@router.get("/help", response_class=HTMLResponse)
async def help_page(request: Request):
user_data = request.session.get("user_data", {})
diff --git a/templates/modern/base.html b/templates/modern/base.html
index d694f78..1afaa87 100644
--- a/templates/modern/base.html
+++ b/templates/modern/base.html
@@ -72,6 +72,9 @@
Lab Actions
+
+ Container Actions
+
Tools
diff --git a/templates/modern/container_actions.html b/templates/modern/container_actions.html
new file mode 100644
index 0000000..a7c5600
--- /dev/null
+++ b/templates/modern/container_actions.html
@@ -0,0 +1,155 @@
+{% extends "modern/base.html" %}
+
+{% block title %}Container Actions - BLOOM{% endblock %}
+
+{% block content %}
+
+
+
+
+
+
+
Rows
+
+
+
+
+
+
+ Validate rows
+
+
+
+
+
+
+
+
+
Operation type
+
+ Select explicit operation...
+ extraction_plate
+ extraction_qc_plate
+ plate_well_data
+ seq_library_plate
+ seq_library_pool
+ seq_run_set
+ lab_set
+ print_euids
+
+
+
Operation payload JSON
+
+
+
+
+ Execute explicit action
+
+
+
+
+
+
+
+{% endblock %}
+
+{% block extra_js %}
+
+{% endblock %}
diff --git a/tests/test_lab_actions_api.py b/tests/test_lab_actions_api.py
index 011a05b..616b867 100644
--- a/tests/test_lab_actions_api.py
+++ b/tests/test_lab_actions_api.py
@@ -12,6 +12,7 @@
from fastapi.testclient import TestClient
+from bloom_lims.api.v1 import container_actions as container_actions_api
from bloom_lims.domain.lab_action_spreadsheets import parse_workbook
from main import app
@@ -216,6 +217,99 @@ def test_lab_actions_full_ilmn_flow_and_csv_export() -> None:
assert library_content in sample_sheet.text
+def test_container_actions_validate_and_explicit_execute_dispatch(monkeypatch) -> None:
+ client = _client()
+ tube_euid = "Z-BCT-CONTAINER-ACTION"
+
+ def fake_object_kind(euid, user):
+ return {
+ "euid": euid,
+ "exists": True,
+ "kind": "container/tube/tube-generic-10ml/1.0",
+ }
+
+ monkeypatch.setattr(container_actions_api, "_object_kind", fake_object_kind)
+
+ validation = client.post(
+ "/api/v1/container-actions/validate",
+ json={
+ "rows": f"{tube_euid},CREATE.container/plate/96-well/1.0,A1\n",
+ "child_name": "pytest container action plate",
+ "child_content_type": "content/gdna/generic/1.0",
+ },
+ )
+ assert validation.status_code == 200, validation.text
+ payload = validation.json()
+ assert payload["valid"] is True
+ assert payload["row_count"] == 1
+ assert payload["planned"][0]["source_euid"] == tube_euid
+ assert payload["planned"][0]["create_type"] == "container/plate/96-well/1.0"
+ assert payload["planned"][0]["target_well"] == "A1"
+ assert payload["source_types"][tube_euid]["exists"] is True
+
+ tsv_validation = client.post(
+ "/api/v1/container-actions/validate",
+ json={
+ "rows": f"{tube_euid}\tCREATE.container/plate/96-well/1.0\tB2\n",
+ "child_name": "pytest tsv container action plate",
+ "child_content_type": "content/gdna/generic/1.0",
+ },
+ )
+ assert tsv_validation.status_code == 200, tsv_validation.text
+ tsv_payload = tsv_validation.json()
+ assert tsv_payload["valid"] is True
+ assert tsv_payload["planned"][0]["create_type"] == "container/plate/96-well/1.0"
+ assert tsv_payload["planned"][0]["target_well"] == "B2"
+
+ execution = client.post(
+ "/api/v1/container-actions/execute",
+ json={"rows": f"{tube_euid},CREATE.container/plate/96-well/1.0,A1\n"},
+ )
+ assert execution.status_code == 400, execution.text
+ assert "operation_type is required" in execution.text
+
+ class FakeLabActionsService:
+ def __init__(self):
+ self.closed = False
+
+ def create_lab_set(self, request):
+ return {
+ "set_euid": "Z-SET-CONTAINER-ACTION",
+ "members": request.members,
+ "external_members": request.external_members,
+ }
+
+ def close(self):
+ self.closed = True
+
+ fake_service = FakeLabActionsService()
+ monkeypatch.setattr(
+ container_actions_api,
+ "_service_for_user",
+ lambda user: fake_service,
+ )
+
+ explicit = client.post(
+ "/api/v1/container-actions/execute",
+ json={
+ "rows": f"{tube_euid},CREATE.set/run-set/generic/1.01,A1\n",
+ "operation_type": "lab_set",
+ "operation_payload": {
+ "name": "pytest container action set",
+ "members": [tube_euid],
+ "metadata": {"source": "container-actions-test"},
+ },
+ },
+ )
+ assert explicit.status_code == 200, explicit.text
+ executed = explicit.json()
+ assert executed["operation_type"] == "lab_set"
+ assert executed["validation"]["row_count"] == 1
+ assert executed["result"]["set_euid"]
+ assert executed["result"]["members"] == [tube_euid]
+ assert fake_service.closed is True
+
+
def test_lab_actions_validation_and_ont_samplesheet_download() -> None:
client = _client()
invalid = client.post(
@@ -326,6 +420,20 @@ def test_lab_actions_gui_renders_wizard() -> None:
assert "Download ${platform} sample sheet" in html
+def test_container_actions_gui_renders_dedicated_api_backed_page() -> None:
+ client = _client()
+ response = client.get("/container-actions")
+ assert response.status_code == 200, response.text
+ html = response.text
+ assert "Container Actions" in html
+ assert "/api/v1/container-actions/validate" in html
+ assert "/api/v1/container-actions/execute" in html
+ assert 'data-testid="bloom-container-action-rows"' in html
+ assert 'data-testid="bloom-container-action-operation"' in html
+ assert 'data-testid="bloom-container-action-payload"' in html
+ assert "Lab Actions" not in html.partition("")[0]
+
+
def test_directed_extraction_into_existing_plate_with_quant_and_reuse_guard() -> None:
client = _client()
existing_plate_euid = _create_plate(client, name="pytest existing extraction plate")
From b096f1464047717db8a97ef68b8d836289762186 Mon Sep 17 00:00:00 2001
From: John Major
Date: Fri, 19 Jun 2026 11:42:02 -0700
Subject: [PATCH 45/47] Pin TapDB 9.0.9
---
README.md | 2 +-
pyproject.toml | 2 +-
tests/test_packaging_metadata.py | 2 +-
uv.lock | 6 +++---
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 24a494e..62dd596 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@
Bloom is the LSMC internal material and container graph service. It owns laboratory containers, materials/content, equipment, lineage, recursive template creation, search, and graph views. Atlas owns orders and customer-facing accession context; Bloom owns the physical/material execution graph.
-Current Dayhoff pin: `7.0.20`. Current TapDB dependency: `daylily-tapdb @ ...@9.0.6`.
+Current Dayhoff pin: `7.0.22`. Current TapDB dependency: `daylily-tapdb @ ...@9.0.9`.
Bloom is internal-only in Dayhoff exposure policy. It must be reachable only through approved LSMC networks and Dayhoff-generated service credentials.
diff --git a/pyproject.toml b/pyproject.toml
index f6171e5..6a6225e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -28,7 +28,7 @@ license = {text = "MIT"}
requires-python = ">=3.12"
dependencies = [
"cli-core-yo==2.1.1",
- "daylily-tapdb @ git+https://github.com/Daylily-Informatics/daylily-tapdb.git@9.0.6",
+ "daylily-tapdb @ git+https://github.com/Daylily-Informatics/daylily-tapdb.git@9.0.9",
"daylily-auth-cognito==2.1.5",
"IPython>=8.18.1",
"bandit[toml]>=1.8.0",
diff --git a/tests/test_packaging_metadata.py b/tests/test_packaging_metadata.py
index 63c5e79..6051fbf 100644
--- a/tests/test_packaging_metadata.py
+++ b/tests/test_packaging_metadata.py
@@ -15,7 +15,7 @@ def test_project_dependencies_pin_release_train_versions() -> None:
assert "cli-core-yo==2.1.1" in dependencies
assert "daylily-auth-cognito==2.1.5" in dependencies
- assert "daylily-tapdb @ git+https://github.com/Daylily-Informatics/daylily-tapdb.git@9.0.6" in dependencies
+ assert "daylily-tapdb @ git+https://github.com/Daylily-Informatics/daylily-tapdb.git@9.0.9" in dependencies
assert "IPython>=8.18.1" in dependencies
assert "psycopg2-binary==2.9.12" in dependencies
assert not any(str(dep).startswith("zebra-day") for dep in dependencies)
diff --git a/uv.lock b/uv.lock
index 74ffb0e..f1b5a96 100644
--- a/uv.lock
+++ b/uv.lock
@@ -200,7 +200,7 @@ requires-dist = [
{ name = "cli-core-yo", specifier = "==2.1.1" },
{ name = "daylily-auth-cognito", specifier = "==2.1.5" },
{ name = "daylily-carrier-tracking", specifier = "==0.5.1" },
- { name = "daylily-tapdb", git = "https://github.com/Daylily-Informatics/daylily-tapdb.git?rev=9.0.6" },
+ { name = "daylily-tapdb", git = "https://github.com/Daylily-Informatics/daylily-tapdb.git?rev=9.0.9" },
{ name = "djlint" },
{ name = "fastapi", specifier = ">=0.110.0" },
{ name = "httpx", specifier = ">=0.27.2" },
@@ -704,8 +704,8 @@ wheels = [
[[package]]
name = "daylily-tapdb"
-version = "9.0.6"
-source = { git = "https://github.com/Daylily-Informatics/daylily-tapdb.git?rev=9.0.6#ea195137638d1cc49b4499c9bf778c57b6d70d9b" }
+version = "9.0.9"
+source = { git = "https://github.com/Daylily-Informatics/daylily-tapdb.git?rev=9.0.9#52d5f498dc4751b7e42d346bee2811a14080e5a5" }
dependencies = [
{ name = "cli-core-yo" },
{ name = "jsonschema" },
From e9961c942a1b69b35e63163eb48167bd8fee5641 Mon Sep 17 00:00:00 2001
From: John Major
Date: Fri, 19 Jun 2026 12:14:06 -0700
Subject: [PATCH 46/47] Ignore TapDB generic set prefix in Bloom seeding
---
bloom_lims/cli/db.py | 2 +-
tests/support/runtime.py | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/bloom_lims/cli/db.py b/bloom_lims/cli/db.py
index dd8859a..6117666 100644
--- a/bloom_lims/cli/db.py
+++ b/bloom_lims/cli/db.py
@@ -48,7 +48,7 @@
db_app = typer.Typer(help="Database management commands routed through daylily-tapdb.")
console = Console()
-_TAPDB_CORE_TEMPLATE_PREFIXES = {"ADT", "EDG", "GVR", "MSG", "SYS", "TPX", "XRF"}
+_TAPDB_CORE_TEMPLATE_PREFIXES = {"ADT", "EDG", "GSE", "GVR", "MSG", "SYS", "TPX", "XRF"}
_IDENTITY_PREFIXES: dict[str, str] = {
"generic_template": GENERIC_TEMPLATE_PREFIX,
"generic_instance_lineage": GENERIC_INSTANCE_LINEAGE_PREFIX,
diff --git a/tests/support/runtime.py b/tests/support/runtime.py
index 46dd1c1..fbc274f 100644
--- a/tests/support/runtime.py
+++ b/tests/support/runtime.py
@@ -56,6 +56,7 @@
_TAPDB_CORE_PREFIX_OWNERSHIP = {
"ADT",
"EDG",
+ "GSE",
"GVR",
"MSG",
"SYS",
From 856f92186a04ba91cf1ba3d825d0522d9ca97c32 Mon Sep 17 00:00:00 2001
From: John Major
Date: Wed, 1 Jul 2026 17:19:44 -0700
Subject: [PATCH 47/47] Release Bloom 8.0.0 with TapDB 9.0.10
---
README.md | 2 +-
bloom_lims/ai_agent_access.py | 28 ++-
bloom_lims/api/v1/__init__.py | 2 +-
bloom_lims/api/v1/auth.py | 25 +-
bloom_lims/api/v1/container_actions.py | 23 +-
bloom_lims/api/v1/lab_actions.py | 8 +-
bloom_lims/cli/db.py | 24 +-
bloom_lims/domain/beta_actions.py | 4 +-
bloom_lims/domain/beta_lab_refs.py | 18 +-
bloom_lims/domain/beta_lab_stages.py | 4 +-
bloom_lims/domain/containers.py | 14 +-
bloom_lims/domain/execution_actions.py | 2 +-
bloom_lims/domain/execution_queue.py | 40 ++--
bloom_lims/domain/lab_action_spreadsheets.py | 3 +-
bloom_lims/domain/lab_actions.py | 213 +++++++++++++-----
bloom_lims/etc/prefix_ownership_registry.json | 3 +
bloom_lims/gui/actions.py | 15 +-
bloom_lims/integrations/tapdb_mount.py | 4 +-
bloom_lims/schemas/beta_lab.py | 10 +-
bloom_lims/schemas/lab_actions.py | 4 +-
bloom_lims/schemas/objects.py | 70 ++++--
bloom_lims/tapdb_metrics.py | 4 +-
container_tests/test_container_runtime.py | 7 +-
pyproject.toml | 3 +-
tests/test_action_button_template_safety.py | 21 +-
tests/test_action_schema_hydration.py | 7 +-
tests/test_anomalies.py | 8 +-
tests/test_beta_lab_schema.py | 4 +-
tests/test_beta_modern_action_system.py | 56 ++++-
tests/test_cli_db_command_paths.py | 25 +-
tests/test_config_runtime.py | 7 +-
tests/test_core_validation.py | 85 ++++---
tests/test_cytoscape_dag.py | 100 ++++----
tests/test_domain_workflows_helpers.py | 100 ++++++--
tests/test_lab_actions_api.py | 28 ++-
tests/test_packaging_metadata.py | 10 +-
tests/test_queue_flow.py | 5 +-
tests/test_route_coverage_gaps_api.py | 19 +-
tests/test_route_coverage_gaps_gui.py | 20 +-
tests/test_sequencing_run_contract.py | 1 -
.../test_template_instantiation_recursion.py | 16 +-
uv.lock | 17 +-
42 files changed, 735 insertions(+), 324 deletions(-)
diff --git a/README.md b/README.md
index 62dd596..6e0ea7c 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@
Bloom is the LSMC internal material and container graph service. It owns laboratory containers, materials/content, equipment, lineage, recursive template creation, search, and graph views. Atlas owns orders and customer-facing accession context; Bloom owns the physical/material execution graph.
-Current Dayhoff pin: `7.0.22`. Current TapDB dependency: `daylily-tapdb @ ...@9.0.9`.
+Current Dayhoff pin: `8.0.0`. Current TapDB dependency: `daylily-tapdb @ ...@9.0.10`.
Bloom is internal-only in Dayhoff exposure policy. It must be reachable only through approved LSMC networks and Dayhoff-generated service credentials.
diff --git a/bloom_lims/ai_agent_access.py b/bloom_lims/ai_agent_access.py
index 8639e8b..2d18822 100644
--- a/bloom_lims/ai_agent_access.py
+++ b/bloom_lims/ai_agent_access.py
@@ -78,9 +78,13 @@ def _endpoint_id_for_request(method: str, path: str) -> str:
resolved_method = str(method or "").upper()
resolved_path = str(path or "").split("?", 1)[0].rstrip("/") or "/"
for spec in ENDPOINT_CATALOG:
- if spec.method == resolved_method and _template_matches(spec.path_template, resolved_path):
+ if spec.method == resolved_method and _template_matches(
+ spec.path_template, resolved_path
+ ):
return spec.endpoint_id
- raise AgentTokenError("AI-agent token is not authorized for this endpoint", status_code=403)
+ raise AgentTokenError(
+ "AI-agent token is not authorized for this endpoint", status_code=403
+ )
def _parse_expiry(value: str) -> datetime:
@@ -95,15 +99,21 @@ def _parse_expiry(value: str) -> datetime:
def _load_grants(path: Path) -> list[dict[str, Any]]:
if not path.is_absolute():
- raise AgentTokenError("AI-agent grant store path must be absolute", status_code=500)
+ raise AgentTokenError(
+ "AI-agent grant store path must be absolute", status_code=500
+ )
if not path.exists():
raise AgentTokenError("AI-agent grant store is missing", status_code=500)
try:
payload = json.loads(path.read_text(encoding="utf-8"))
except json.JSONDecodeError as exc:
- raise AgentTokenError("AI-agent grant store is malformed", status_code=500) from exc
+ raise AgentTokenError(
+ "AI-agent grant store is malformed", status_code=500
+ ) from exc
if not isinstance(payload, dict) or not isinstance(payload.get("tokens"), list):
- raise AgentTokenError("AI-agent grant store must contain a tokens list", status_code=500)
+ raise AgentTokenError(
+ "AI-agent grant store must contain a tokens list", status_code=500
+ )
return [record for record in payload["tokens"] if isinstance(record, dict)]
@@ -119,7 +129,9 @@ def validate_ai_agent_request(request: Request, token: str) -> ValidatedAgentAcc
endpoint_id = _endpoint_id_for_request(request.method, request.url.path)
token_digest = hashlib.sha256(token.encode("utf-8")).hexdigest()
for record in _load_grants(Path(raw_path)):
- if not secrets.compare_digest(str(record.get("token_hash") or ""), token_digest):
+ if not secrets.compare_digest(
+ str(record.get("token_hash") or ""), token_digest
+ ):
continue
if record.get("revoked_at"):
raise AgentTokenError("AI-agent token has been revoked")
@@ -128,7 +140,9 @@ def validate_ai_agent_request(request: Request, token: str) -> ValidatedAgentAcc
raise AgentTokenError("AI-agent token has expired")
endpoint_ids = [str(item) for item in record.get("endpoint_ids") or []]
if endpoint_id not in endpoint_ids:
- raise AgentTokenError("AI-agent token is not authorized for this endpoint", status_code=403)
+ raise AgentTokenError(
+ "AI-agent token is not authorized for this endpoint", status_code=403
+ )
validated = ValidatedAgentAccess(
token_id=str(record.get("token_id") or ""),
agent_id=str(record.get("agent_id") or ""),
diff --git a/bloom_lims/api/v1/__init__.py b/bloom_lims/api/v1/__init__.py
index 7fd8888..5c8dd61 100644
--- a/bloom_lims/api/v1/__init__.py
+++ b/bloom_lims/api/v1/__init__.py
@@ -20,8 +20,8 @@
from .auth import router as auth_router
from .batch import router as batch_router
from .beta_lab import router as beta_lab_router
-from .containers import router as containers_router
from .container_actions import router as container_actions_router
+from .containers import router as containers_router
from .content import router as content_router
from .equipment import router as equipment_router
from .execution_queue import router as execution_queue_router
diff --git a/bloom_lims/api/v1/auth.py b/bloom_lims/api/v1/auth.py
index f00a054..e0a32e7 100644
--- a/bloom_lims/api/v1/auth.py
+++ b/bloom_lims/api/v1/auth.py
@@ -25,9 +25,13 @@ def _broker_preferences_contract(email: str) -> tuple[str, dict[str, str]]:
token = str(os.environ.get("LSMC_AUTH_BROKER_SERVICE_TOKEN") or "").strip()
service_id = str(os.environ.get("LSMC_AUTH_BROKER_SERVICE_ID") or "bloom").strip()
if not raw_url:
- raise HTTPException(status_code=503, detail="Broker user preferences URL is not configured")
+ raise HTTPException(
+ status_code=503, detail="Broker user preferences URL is not configured"
+ )
if not token:
- raise HTTPException(status_code=503, detail="Broker service token is not configured")
+ raise HTTPException(
+ status_code=503, detail="Broker service token is not configured"
+ )
if "{email}" not in raw_url:
raise HTTPException(
status_code=503,
@@ -58,7 +62,9 @@ async def get_current_user(user: APIUser = Depends(require_api_auth)):
@preferences_router.get("/me/preferences")
async def current_user_preferences(user: APIUser = Depends(require_api_auth)):
if not user.email:
- raise HTTPException(status_code=400, detail="Authenticated user email is required")
+ raise HTTPException(
+ status_code=400, detail="Authenticated user email is required"
+ )
url, headers = _broker_preferences_contract(user.email)
with httpx.Client(timeout=5.0) as client:
response = client.get(url, headers=headers)
@@ -73,7 +79,9 @@ async def update_current_user_preferences(
user: APIUser = Depends(require_api_auth),
):
if not user.email:
- raise HTTPException(status_code=400, detail="Authenticated user email is required")
+ raise HTTPException(
+ status_code=400, detail="Authenticated user email is required"
+ )
payload = await request.json()
theme = str(payload.get("theme") or "").strip()
if theme and theme not in THEME_NAMES:
@@ -81,9 +89,14 @@ async def update_current_user_preferences(
service_themes = payload.get("service_themes")
if service_themes is not None:
if not isinstance(service_themes, dict):
- raise HTTPException(status_code=400, detail="service_themes must be an object")
+ raise HTTPException(
+ status_code=400, detail="service_themes must be an object"
+ )
for service_theme in service_themes.values():
- if service_theme is not None and str(service_theme).strip() not in THEME_NAMES:
+ if (
+ service_theme is not None
+ and str(service_theme).strip() not in THEME_NAMES
+ ):
raise HTTPException(status_code=400, detail="Unknown theme")
forward_payload = {}
if "theme" in payload:
diff --git a/bloom_lims/api/v1/container_actions.py b/bloom_lims/api/v1/container_actions.py
index 440324f..01cc548 100644
--- a/bloom_lims/api/v1/container_actions.py
+++ b/bloom_lims/api/v1/container_actions.py
@@ -10,7 +10,6 @@
from pydantic import BaseModel, Field, ValidationError
from sqlalchemy import select
-from bloom_lims.tapdb_adapter import BLOOMdb3, generic_instance
from bloom_lims.domain.lab_actions import LabActionsService
from bloom_lims.schemas.lab_actions import (
ExtractionPlateRequest,
@@ -22,6 +21,7 @@
SeqLibraryPoolRequest,
SeqRunSetRequest,
)
+from bloom_lims.tapdb_adapter import BLOOMdb3, generic_instance
from .dependencies import APIUser, require_write
@@ -76,8 +76,12 @@ def _split_source(value: str) -> tuple[str, str | None]:
return euid, well
-def _normalize_record(row: dict[str, Any], default_target: str | None) -> dict[str, Any]:
- source = row.get("source") or row.get("source_euid") or row.get("euid") or row.get("0")
+def _normalize_record(
+ row: dict[str, Any], default_target: str | None
+) -> dict[str, Any]:
+ source = (
+ row.get("source") or row.get("source_euid") or row.get("euid") or row.get("0")
+ )
target = (
row.get("target")
or row.get("target_container_euid")
@@ -159,7 +163,10 @@ async def validate_container_action(
):
try:
planned = _parse_rows(payload)
- source_types = {row["source_euid"]: _object_kind(row["source_euid"], user) for row in planned}
+ source_types = {
+ row["source_euid"]: _object_kind(row["source_euid"], user)
+ for row in planned
+ }
target_types = {
row["target_euid"]: _object_kind(row["target_euid"], user)
for row in planned
@@ -232,9 +239,13 @@ async def execute_container_action(
SeqRunSetRequest.model_validate(operation_payload)
)
elif payload.operation_type == "lab_set":
- result = service.create_lab_set(LabSetRequest.model_validate(operation_payload))
+ result = service.create_lab_set(
+ LabSetRequest.model_validate(operation_payload)
+ )
elif payload.operation_type == "print_euids":
- result = service.print_euids(PrintEuidRequest.model_validate(operation_payload))
+ result = service.print_euids(
+ PrintEuidRequest.model_validate(operation_payload)
+ )
else: # pragma: no cover - Literal validation should prevent this.
raise HTTPException(status_code=400, detail="Unsupported operation_type")
return {
diff --git a/bloom_lims/api/v1/lab_actions.py b/bloom_lims/api/v1/lab_actions.py
index 99191af..4698baa 100644
--- a/bloom_lims/api/v1/lab_actions.py
+++ b/bloom_lims/api/v1/lab_actions.py
@@ -177,13 +177,13 @@ async def download_seq_run_sample_sheet(
):
service = _service_for_user(user)
try:
- content, filename, media_type = service.sequencing_sample_sheet_download(set_euid)
+ content, filename, media_type = service.sequencing_sample_sheet_download(
+ set_euid
+ )
return PlainTextResponse(
content,
media_type=media_type,
- headers={
- "Content-Disposition": f'attachment; filename="{filename}"'
- },
+ headers={"Content-Disposition": f'attachment; filename="{filename}"'},
)
except Exception as exc:
_raise_http(exc)
diff --git a/bloom_lims/cli/db.py b/bloom_lims/cli/db.py
index 6117666..ae1ce71 100644
--- a/bloom_lims/cli/db.py
+++ b/bloom_lims/cli/db.py
@@ -383,6 +383,20 @@ def _retire_obsolete_template_variants(
domain_code: str,
) -> int:
current = _active_template_categories_by_semantic_key(templates)
+ current_semantic_types = {
+ (
+ str((template.get("json_addl") or {}).get("semantic_category") or "")
+ .strip()
+ .lower(),
+ str(template.get("type") or "").strip(),
+ )
+ for template in templates
+ if isinstance(template.get("json_addl"), dict)
+ and str(
+ (template.get("json_addl") or {}).get("semantic_category") or ""
+ ).strip()
+ and str(template.get("type") or "").strip()
+ }
current_prefixes = {
str(template.get("instance_prefix") or "").strip().upper()
for template in templates
@@ -411,18 +425,16 @@ def _retire_obsolete_template_variants(
)
expected_category = current.get(key)
actual_category = str(row.category or "").strip().upper()
- semantic_category = template_semantic_category(row).strip().upper()
- if semantic_category and actual_category != semantic_category:
- row.is_deleted = True
- row.bstatus = "retired"
- retired += 1
- continue
if actual_category in current_prefixes:
row.is_deleted = True
row.bstatus = "retired"
retired += 1
continue
if expected_category is None:
+ if (key[0], key[1]) in current_semantic_types:
+ row.is_deleted = True
+ row.bstatus = "retired"
+ retired += 1
continue
if actual_category == expected_category:
continue
diff --git a/bloom_lims/domain/beta_actions.py b/bloom_lims/domain/beta_actions.py
index 573b544..3ccd7fe 100644
--- a/bloom_lims/domain/beta_actions.py
+++ b/bloom_lims/domain/beta_actions.py
@@ -187,9 +187,7 @@ def record(
return action_record
def _ensure_action_template(self, action_key: str) -> generic_template:
- template_code = (
- f"{BETA_ACTION_TEMPLATE_PREFIX}/{BETA_ACTION_GROUP}/{action_key}/1.0/"
- )
+ template_code = f"action/{BETA_ACTION_GROUP}/{action_key}/1.0/"
return require_seeded_template(
self.session,
template_code,
diff --git a/bloom_lims/domain/beta_lab_refs.py b/bloom_lims/domain/beta_lab_refs.py
index a7890fb..71c2112 100644
--- a/bloom_lims/domain/beta_lab_refs.py
+++ b/bloom_lims/domain/beta_lab_refs.py
@@ -172,9 +172,7 @@ def _fulfillment_item_refs_for_instance(self, instance) -> list[dict[str, str]]:
).strip()
atlas_tenant_id = str(payload.get("atlas_tenant_id") or "").strip()
atlas_trf_euid = str(
- payload.get("atlas_trf_euid")
- or payload.get("atlas_order_euid")
- or ""
+ payload.get("atlas_trf_euid") or payload.get("atlas_order_euid") or ""
).strip()
if not (
fulfillment_item_euid
@@ -195,8 +193,7 @@ def _fulfillment_item_refs_for_instance(self, instance) -> list[dict[str, str]]:
payload.get("atlas_order_test_euid") or atlas_test_euid
).strip(),
"atlas_fulfillment_slot_euid": str(
- payload.get("atlas_fulfillment_slot_euid")
- or fulfillment_item_euid
+ payload.get("atlas_fulfillment_slot_euid") or fulfillment_item_euid
).strip(),
}
return list(refs.values())
@@ -366,7 +363,9 @@ def _replace_fulfillment_item_references(
atlas_tenant_id = str(atlas_context.get("atlas_tenant_id") or "").strip()
atlas_trf_euid = str(atlas_context.get("atlas_trf_euid") or "").strip()
atlas_order_euid = str(
- atlas_context.get("atlas_order_euid") or atlas_context.get("order_euid") or ""
+ atlas_context.get("atlas_order_euid")
+ or atlas_context.get("order_euid")
+ or ""
).strip()
fulfillment_items = list(atlas_context.get("fulfillment_items") or [])
for fulfillment_slot in list(atlas_context.get("fulfillment_slots") or []):
@@ -464,8 +463,7 @@ def _replace_fulfillment_item_references(
object_evidence(ref_obj.euid, role="atlas_reference_link"),
],
correlation_id=(
- f"SLOT_SATISFIED_BY:{atlas_fulfillment_slot_euid}:"
- f"{instance.euid}"
+ f"SLOT_SATISFIED_BY:{atlas_fulfillment_slot_euid}:{instance.euid}"
),
causation_id=(
f"bloom:atlas_fulfillment_reference:"
@@ -484,7 +482,9 @@ def _replace_container_entity_references(
) -> None:
atlas_tenant_id = str(atlas_context.get("atlas_tenant_id") or "").strip()
atlas_order_euid = str(
- atlas_context.get("atlas_order_euid") or atlas_context.get("order_euid") or ""
+ atlas_context.get("atlas_order_euid")
+ or atlas_context.get("order_euid")
+ or ""
).strip()
atlas_order_test_euid = str(
atlas_context.get("atlas_order_test_euid")
diff --git a/bloom_lims/domain/beta_lab_stages.py b/bloom_lims/domain/beta_lab_stages.py
index 971a736..5b8969f 100644
--- a/bloom_lims/domain/beta_lab_stages.py
+++ b/bloom_lims/domain/beta_lab_stages.py
@@ -409,9 +409,7 @@ def record_post_extract_qc(
"idempotency_key": idempotency_key or "",
"occurred_at": self._timestamp(),
},
- template_code=self.DATA_TEMPLATE_BY_BETA_KIND.get(
- "post_extract_qc_result"
- ),
+ template_code=self.DATA_TEMPLATE_BY_BETA_KIND.get("post_extract_qc_result"),
)
if payload.quant_artifact_euid:
qc_props = self._props(qc_record)
diff --git a/bloom_lims/domain/containers.py b/bloom_lims/domain/containers.py
index 8e63a2b..dfee826 100644
--- a/bloom_lims/domain/containers.py
+++ b/bloom_lims/domain/containers.py
@@ -18,7 +18,9 @@
class BloomContainer(BloomObj):
def __init__(self, bdb, is_deleted=False, cfg_printers=False, cfg_fedex=False):
- super().__init__(bdb,is_deleted=is_deleted, cfg_printers=cfg_printers, cfg_fedex=cfg_fedex)
+ super().__init__(
+ bdb, is_deleted=is_deleted, cfg_printers=cfg_printers, cfg_fedex=cfg_fedex
+ )
def create_empty_container(self, template_euid):
return self.create_instances(template_euid)
@@ -56,12 +58,16 @@ def unlink_content(self, container_euid, content_euid):
lineage.is_deleted = True
self.session.commit()
return
- raise Exception(f"Content {content_euid} not found in container {container_euid}")
+ raise Exception(
+ f"Content {content_euid} not found in container {container_euid}"
+ )
class BloomContainerPlate(BloomContainer):
def __init__(self, bdb, is_deleted=False, cfg_printers=False, cfg_fedex=False):
- super().__init__(bdb,is_deleted=is_deleted, cfg_printers=cfg_printers, cfg_fedex=cfg_fedex)
+ super().__init__(
+ bdb, is_deleted=is_deleted, cfg_printers=cfg_printers, cfg_fedex=cfg_fedex
+ )
def create_empty_plate(self, template_euid):
return self.create_instances(template_euid)
@@ -119,8 +125,6 @@ def organize_wells(self, wells, parent_container):
return matrix
-
-
__all__ = [
"BloomContainer",
"BloomContainerPlate",
diff --git a/bloom_lims/domain/execution_actions.py b/bloom_lims/domain/execution_actions.py
index f1f7b9f..27896a0 100644
--- a/bloom_lims/domain/execution_actions.py
+++ b/bloom_lims/domain/execution_actions.py
@@ -228,7 +228,7 @@ def record(
return action_record
def _ensure_action_template(self, action_key: str) -> generic_template:
- template_code = f"{EXECUTION_ACTION_TEMPLATE_PREFIX}/{EXECUTION_ACTION_GROUP}/{action_key}/1.0/"
+ template_code = f"action/{EXECUTION_ACTION_GROUP}/{action_key}/1.0/"
return require_seeded_template(
self.session,
template_code,
diff --git a/bloom_lims/domain/execution_queue.py b/bloom_lims/domain/execution_queue.py
index bdf0f6e..8b12f37 100644
--- a/bloom_lims/domain/execution_queue.py
+++ b/bloom_lims/domain/execution_queue.py
@@ -130,7 +130,7 @@ class ExecutionQueueService:
"dispatch_priority": 100,
"subject_template_codes": [
"container/tube/tube-generic-10ml/1.0",
- "material/specimen/blood-whole/1.0",
+ "content/specimen/blood-whole/1.0",
],
"required_worker_capabilities": ["wetlab.extraction"],
},
@@ -139,7 +139,7 @@ class ExecutionQueueService:
"dispatch_priority": 90,
"subject_template_codes": [
"container/tube/tube-generic-10ml/1.0",
- "material/specimen/blood-whole/1.0",
+ "content/specimen/blood-whole/1.0",
],
"required_worker_capabilities": ["wetlab.extraction"],
},
@@ -147,8 +147,8 @@ class ExecutionQueueService:
"display_name": "Post-Extract QC",
"dispatch_priority": 100,
"subject_template_codes": [
- "material/sample/cfdna/1.0",
- "material/sample/gdna/1.0",
+ "content/sample/cfdna/1.0",
+ "content/sample/gdna/1.0",
],
"required_worker_capabilities": ["wetlab.post_extract_qc"],
},
@@ -156,8 +156,8 @@ class ExecutionQueueService:
"display_name": "Illumina Library Prep",
"dispatch_priority": 100,
"subject_template_codes": [
- "material/sample/cfdna/1.0",
- "material/sample/gdna/1.0",
+ "content/sample/cfdna/1.0",
+ "content/sample/gdna/1.0",
],
"required_worker_capabilities": ["wetlab.library_prep", "platform.ILMN"],
},
@@ -165,7 +165,7 @@ class ExecutionQueueService:
"display_name": "Illumina Library QC",
"dispatch_priority": 100,
"subject_template_codes": [
- "material/sample/sequencing-library/1.0",
+ "content/sample/sequencing-library/1.0",
],
"required_worker_capabilities": ["wetlab.library_qc", "platform.ILMN"],
},
@@ -173,8 +173,8 @@ class ExecutionQueueService:
"display_name": "ONT Library Prep",
"dispatch_priority": 100,
"subject_template_codes": [
- "material/sample/cfdna/1.0",
- "material/sample/gdna/1.0",
+ "content/sample/cfdna/1.0",
+ "content/sample/gdna/1.0",
],
"required_worker_capabilities": ["wetlab.library_prep", "platform.ONT"],
},
@@ -183,7 +183,7 @@ class ExecutionQueueService:
"dispatch_priority": 100,
"subject_template_codes": [
"data/operation/library-prep/1.0",
- "material/sample/sequencing-library/1.0",
+ "content/sample/sequencing-library/1.0",
],
"required_worker_capabilities": ["wetlab.pooling", "platform.ILMN"],
},
@@ -192,28 +192,28 @@ class ExecutionQueueService:
"dispatch_priority": 100,
"subject_template_codes": [
"data/operation/library-prep/1.0",
- "material/sample/sequencing-library/1.0",
+ "content/sample/sequencing-library/1.0",
],
"required_worker_capabilities": ["wetlab.pooling", "platform.ONT"],
},
"ilmn_start_seq_run": {
"display_name": "Illumina Start Run",
"dispatch_priority": 100,
- "subject_template_codes": ["material/pool/sequencing-library/1.0"],
+ "subject_template_codes": ["content/pool/sequencing-library/1.0"],
"required_worker_capabilities": ["wetlab.run_start", "platform.ILMN"],
},
"ont_start_seq_run": {
"display_name": "ONT Start Run",
"dispatch_priority": 100,
- "subject_template_codes": ["material/pool/sequencing-library/1.0"],
+ "subject_template_codes": ["content/pool/sequencing-library/1.0"],
"required_worker_capabilities": ["wetlab.run_start", "platform.ONT"],
},
"post_extract_exception": {
"display_name": "Post-Extract QC Exception",
"dispatch_priority": 10,
"subject_template_codes": [
- "material/sample/cfdna/1.0",
- "material/sample/gdna/1.0",
+ "content/sample/cfdna/1.0",
+ "content/sample/gdna/1.0",
],
"required_worker_capabilities": ["wetlab.exception_review"],
},
@@ -221,7 +221,7 @@ class ExecutionQueueService:
"display_name": "Illumina Library QC Exception",
"dispatch_priority": 10,
"subject_template_codes": [
- "material/sample/sequencing-library/1.0",
+ "content/sample/sequencing-library/1.0",
],
"required_worker_capabilities": [
"wetlab.exception_review",
@@ -1480,7 +1480,9 @@ def current_queue_for_instance(self, instance) -> str | None:
if queue_key:
return queue_key
category = instance_semantic_category(instance)
- parent_relationship = "contains" if category == "container" else "HOLDS_MATERIAL"
+ parent_relationship = (
+ "contains" if category == "container" else "HOLDS_MATERIAL"
+ )
for lineage in get_child_lineages(instance):
if lineage.is_deleted or lineage.relationship_type != parent_relationship:
continue
@@ -2053,7 +2055,9 @@ def _is_visible_in_queue(self, subject, queue, now: datetime) -> bool:
if subject.uid in visible_uids:
return True
category = instance_semantic_category(subject)
- parent_relationship = "contains" if category == "container" else "HOLDS_MATERIAL"
+ parent_relationship = (
+ "contains" if category == "container" else "HOLDS_MATERIAL"
+ )
for lineage in get_child_lineages(subject):
if lineage.is_deleted or lineage.relationship_type != parent_relationship:
continue
diff --git a/bloom_lims/domain/lab_action_spreadsheets.py b/bloom_lims/domain/lab_action_spreadsheets.py
index e025cc9..fdf5587 100644
--- a/bloom_lims/domain/lab_action_spreadsheets.py
+++ b/bloom_lims/domain/lab_action_spreadsheets.py
@@ -9,7 +9,8 @@
from dataclasses import dataclass
from pathlib import PurePosixPath
from typing import Any
-from xml.etree import ElementTree
+
+from defusedxml import ElementTree
@dataclass(frozen=True)
diff --git a/bloom_lims/domain/lab_actions.py b/bloom_lims/domain/lab_actions.py
index 6adb276..a07cad2 100644
--- a/bloom_lims/domain/lab_actions.py
+++ b/bloom_lims/domain/lab_actions.py
@@ -237,13 +237,18 @@ def _normalize_assignments(
raise ValueError(f"duplicate destination well: {position}")
seen_positions.add(position)
if len(request.assignments) > MAX_EXTRACTION_TUBES:
- raise ValueError(f"directed extraction accepts at most {MAX_EXTRACTION_TUBES} tubes")
+ raise ValueError(
+ f"directed extraction accepts at most {MAX_EXTRACTION_TUBES} tubes"
+ )
return request.assignments
def _create_or_get_extraction_plate(self, request: ExtractionPlateRequest):
if request.plate_euid:
plate = self._require(request.plate_euid)
- if instance_semantic_category(plate) != "container" or plate.type != "plate":
+ if (
+ instance_semantic_category(plate) != "container"
+ or plate.type != "plate"
+ ):
raise ValueError(f"{request.plate_euid} is not a plate container")
return plate
return self._create_by_code(
@@ -303,7 +308,9 @@ def _well_for_qc_assignment(
if assignment.source_well_euid:
return self._require(assignment.source_well_euid)
if not source_plate_euid:
- raise ValueError("source_plate_euid is required when assignment uses row/col")
+ raise ValueError(
+ "source_plate_euid is required when assignment uses row/col"
+ )
return self._well_from_plate_position(
source_plate_euid, assignment.row, assignment.col
)
@@ -311,7 +318,10 @@ def _well_for_qc_assignment(
def _create_or_get_qc_plate(self, request: ExtractionQcPlateRequest):
if request.qc_plate_euid:
plate = self._require(request.qc_plate_euid)
- if instance_semantic_category(plate) != "container" or plate.type != "plate":
+ if (
+ instance_semantic_category(plate) != "container"
+ or plate.type != "plate"
+ ):
raise ValueError(f"{request.qc_plate_euid} is not a plate container")
return plate, []
plate = self._create_by_code(
@@ -369,9 +379,7 @@ def add_lab_set_members(
) -> dict[str, Any]:
run_set = self._require(set_euid)
props = self._props(run_set)
- members = list(
- dict.fromkeys([*props.get("members", []), *request.members])
- )
+ members = list(dict.fromkeys([*props.get("members", []), *request.members]))
external_members = list(
dict.fromkeys(
[*props.get("external_members", []), *request.external_members]
@@ -511,13 +519,17 @@ def attach_plate_well_data(self, request: PlateWellDataRequest) -> dict[str, Any
self.bdb.session.commit()
sorted_plate_euids = sorted(plate_euids)
return {
- "plate_euid": sorted_plate_euids[0] if len(sorted_plate_euids) == 1 else None,
+ "plate_euid": sorted_plate_euids[0]
+ if len(sorted_plate_euids) == 1
+ else None,
"plate_euids": sorted_plate_euids,
"run_set_euid": run_set.euid if run_set is not None else None,
"mappings": mappings,
}
- def create_extraction_plate(self, request: ExtractionPlateRequest) -> dict[str, Any]:
+ def create_extraction_plate(
+ self, request: ExtractionPlateRequest
+ ) -> dict[str, Any]:
assignments = self._normalize_assignments(request)
plate = self._create_or_get_extraction_plate(request)
wells = self._plate_wells(plate)
@@ -600,7 +612,9 @@ def create_extraction_plate(self, request: ExtractionPlateRequest) -> dict[str,
"mappings": [item.__dict__ for item in mappings],
}
- def create_seq_library_plate(self, request: SeqLibraryPlateRequest) -> dict[str, Any]:
+ def create_seq_library_plate(
+ self, request: SeqLibraryPlateRequest
+ ) -> dict[str, Any]:
if request.mode == "plate_1_to_1":
source_plate = self._require(request.source_plate_euid)
source_wells = self._plate_wells(source_plate)
@@ -669,7 +683,9 @@ def create_seq_library_plate(self, request: SeqLibraryPlateRequest) -> dict[str,
source_role="source_material",
target_role="derived_material",
)
- self._create_lineage(source_well.euid, dest_well.euid, "library_source_well")
+ self._create_lineage(
+ source_well.euid, dest_well.euid, "library_source_well"
+ )
if assignment.index_euid:
index = self._require(assignment.index_euid)
self._create_lineage(library.euid, index.euid, "uses_index")
@@ -688,7 +704,10 @@ def create_seq_library_plate(self, request: SeqLibraryPlateRequest) -> dict[str,
requested=request.create_run_set,
run_set=request.run_set,
default_name=f"{plate.euid} library set",
- member_euids=[plate.euid, *[item["library_content_euid"] for item in mappings]],
+ member_euids=[
+ plate.euid,
+ *[item["library_content_euid"] for item in mappings],
+ ],
)
self.bdb.session.commit()
return {
@@ -754,7 +773,9 @@ def create_seq_library_pool(self, request: SeqLibraryPoolRequest) -> dict[str, A
target_role="derived_material",
)
if container is not None:
- self._create_lineage(container.euid, pool_tube.euid, "pooled_from_container")
+ self._create_lineage(
+ container.euid, pool_tube.euid, "pooled_from_container"
+ )
run_set = self._run_set(
requested=request.create_run_set,
run_set=request.run_set,
@@ -802,7 +823,9 @@ def create_seq_run_set(self, request: SeqRunSetRequest) -> dict[str, Any]:
self._create_lineage(run_set.euid, pool_tube.euid, "run_uses_pool")
self._create_lineage(run_set.euid, pool_content.euid, "run_uses_pool")
if request.instrument_euid:
- self._create_lineage(run_set.euid, request.instrument_euid, "run_uses_instrument")
+ self._create_lineage(
+ run_set.euid, request.instrument_euid, "run_uses_instrument"
+ )
for reagent_euid in request.reagent_euids:
self._create_lineage(run_set.euid, reagent_euid, "run_uses_reagent")
assignments = self._create_sequenced_library_assignments(
@@ -890,7 +913,9 @@ def plate_mapping_rows(self, plate_euid: str) -> list[dict[str, str]]:
]
source_tubes = [
lineage.parent_instance.euid
- for lineage in self._lineages_to_child(well, "extraction_source_container")
+ for lineage in self._lineages_to_child(
+ well, "extraction_source_container"
+ )
]
for content in well_contents or [None]:
parent_contents = []
@@ -911,7 +936,9 @@ def plate_mapping_rows(self, plate_euid: str) -> list[dict[str, str]]:
"well_euid": well.euid,
"well_row": row,
"well_col": col,
- "well_content_euid": content.euid if content is not None else "",
+ "well_content_euid": content.euid
+ if content is not None
+ else "",
"parent_content_euid": "|".join(parent_contents),
"one_degree_parent_euids": "|".join(parent_contents),
"one_degree_child_euids": "|".join(child_euids),
@@ -958,7 +985,9 @@ def sequencing_sample_sheet(self, set_euid: str) -> str:
source_specimen = (
[
lineage.parent_instance
- for lineage in self._lineages_to_child(source_material, "DERIVED_FROM")
+ for lineage in self._lineages_to_child(
+ source_material, "DERIVED_FROM"
+ )
][0]
if source_material is not None
and self._lineages_to_child(source_material, "DERIVED_FROM")
@@ -985,12 +1014,16 @@ def sequencing_sample_sheet(self, set_euid: str) -> str:
}
)
if platform == "ONT":
- return self._ont_sample_sheet(run_set=run_set, props=props, data_rows=data_rows)
+ return self._ont_sample_sheet(
+ run_set=run_set, props=props, data_rows=data_rows
+ )
if platform != "ILMN":
raise ValueError(
f"Sample sheet download is implemented for ILMN and ONT, not {platform or 'unknown'}"
)
- return self._illumina_sample_sheet(run_set=run_set, props=props, data_rows=data_rows)
+ return self._illumina_sample_sheet(
+ run_set=run_set, props=props, data_rows=data_rows
+ )
def sequencing_sample_sheet_download(self, set_euid: str) -> tuple[str, str, str]:
run_set = self._require(set_euid)
@@ -999,7 +1032,11 @@ def sequencing_sample_sheet_download(self, set_euid: str) -> tuple[str, str, str
content = self.sequencing_sample_sheet(set_euid)
if platform == "ONT":
return content, f"{set_euid}_ONT_manifest.tsv", "text/tab-separated-values"
- return content, f"{set_euid}_{platform or 'sequencing'}_SampleSheet.csv", "text/csv"
+ return (
+ content,
+ f"{set_euid}_{platform or 'sequencing'}_SampleSheet.csv",
+ "text/csv",
+ )
def _illumina_sample_sheet(
self, *, run_set, props: dict[str, Any], data_rows: list[dict[str, str]]
@@ -1042,7 +1079,9 @@ def _ont_sample_sheet(
"alias": row.get("Sample_Name") or row.get("Sample_ID") or "",
"barcode": row.get("index") or "",
"run_set_euid": run_set.euid,
- "library_euid": description.get("library_euid") or row.get("Sample_ID") or "",
+ "library_euid": description.get("library_euid")
+ or row.get("Sample_ID")
+ or "",
"source_gdna_euid": description.get("source_gdna_euid") or "",
"source_specimen_content_euid": description.get(
"source_specimen_content_euid"
@@ -1081,7 +1120,10 @@ def _sheet_action(self, sheet: ParsedSheet) -> str:
return "seq_run_set"
if {"input_euid", "input_euids"} & headers:
return "seq_pool"
- if "source_well_euid" in headers and {"index_barcode", "index_euid"} & headers:
+ if (
+ "source_well_euid" in headers
+ and {"index_barcode", "index_euid"} & headers
+ ):
return "seq_library_plate"
if {"source_well_euid", "qc_row", "qc_col"} & headers:
return "extraction_qc"
@@ -1104,12 +1146,18 @@ def _sheet_action(self, sheet: ParsedSheet) -> str:
if name in {"sets", "set", "run sets", "run set"}:
return "sets"
if name in {"plate well data", "well data", "annotation"}:
- return "plate_well_data" if name != "annotation" else "container_annotation_preview"
+ return (
+ "plate_well_data"
+ if name != "annotation"
+ else "container_annotation_preview"
+ )
if name in {"bulk create", "transfer"}:
return "container_interaction_preview"
return "unknown"
- def _request_from_extraction_sheet(self, sheet: ParsedSheet) -> ExtractionPlateRequest:
+ def _request_from_extraction_sheet(
+ self, sheet: ParsedSheet
+ ) -> ExtractionPlateRequest:
assignments: list[ExtractionTubeAssignment] = []
tube_euids: list[str] = []
plate_name: str | None = None
@@ -1120,8 +1168,14 @@ def _request_from_extraction_sheet(self, sheet: ParsedSheet) -> ExtractionPlateR
if not tube_euid:
continue
plate_name = plate_name or str(row.get("plate_name") or "").strip() or None
- row_name = row.get("row") or row.get("well_row") or row.get("child_container_row")
- col_value = row.get("col") or row.get("well_col") or row.get("child_container_column")
+ row_name = (
+ row.get("row") or row.get("well_row") or row.get("child_container_row")
+ )
+ col_value = (
+ row.get("col")
+ or row.get("well_col")
+ or row.get("child_container_column")
+ )
if row_name not in (None, "") or col_value not in (None, ""):
assignments.append(
ExtractionTubeAssignment(
@@ -1150,13 +1204,21 @@ def _request_from_qc_sheet(self, sheet: ParsedSheet) -> ExtractionQcPlateRequest
qc_plate_name = None
assignments: list[ExtractionQcAssignment] = []
for row in sheet.rows:
- source_plate_euid = source_plate_euid or str(
- row.get("source_plate_euid") or row.get("plate_euid") or ""
- ).strip() or None
- qc_plate_name = qc_plate_name or str(row.get("qc_plate_name") or "").strip() or None
+ source_plate_euid = (
+ source_plate_euid
+ or str(
+ row.get("source_plate_euid") or row.get("plate_euid") or ""
+ ).strip()
+ or None
+ )
+ qc_plate_name = (
+ qc_plate_name or str(row.get("qc_plate_name") or "").strip() or None
+ )
assignments.append(
ExtractionQcAssignment(
- source_well_euid=str(row.get("source_well_euid") or row.get("well_euid") or "").strip()
+ source_well_euid=str(
+ row.get("source_well_euid") or row.get("well_euid") or ""
+ ).strip()
or None,
row=row.get("row") or row.get("well_row"),
col=row.get("col") or row.get("well_col"),
@@ -1178,18 +1240,23 @@ def _request_from_library_sheet(self, sheet: ParsedSheet) -> SeqLibraryPlateRequ
plate_name = None
assignments: list[LibraryPlateAssignment] = []
for row in sheet.rows:
- source_plate_euid = source_plate_euid or str(
- row.get("source_plate_euid") or ""
- ).strip() or None
+ source_plate_euid = (
+ source_plate_euid
+ or str(row.get("source_plate_euid") or "").strip()
+ or None
+ )
plate_name = plate_name or str(row.get("plate_name") or "").strip() or None
- source_well_euid = str(row.get("source_well_euid") or row.get("well_euid") or "").strip()
+ source_well_euid = str(
+ row.get("source_well_euid") or row.get("well_euid") or ""
+ ).strip()
if source_well_euid:
assignments.append(
LibraryPlateAssignment(
source_well_euid=source_well_euid,
row=row.get("row") or row.get("well_row"),
col=row.get("col") or row.get("well_col"),
- index_barcode=str(row.get("index_barcode") or "").strip() or None,
+ index_barcode=str(row.get("index_barcode") or "").strip()
+ or None,
index_euid=str(row.get("index_euid") or "").strip() or None,
data=self._row_metadata(row, "data_", "library_"),
)
@@ -1224,7 +1291,9 @@ def _request_from_pool_sheet(self, sheet: ParsedSheet) -> SeqLibraryPoolRequest:
)
)
platform = str(row.get("platform") or platform).strip() or platform
- pool_tube_euid = pool_tube_euid or str(row.get("pool_tube_euid") or "").strip() or None
+ pool_tube_euid = (
+ pool_tube_euid or str(row.get("pool_tube_euid") or "").strip() or None
+ )
pool_name = pool_name or str(row.get("pool_name") or "").strip() or None
metadata.update(self._row_metadata(row, "metadata_", "pool_"))
return SeqLibraryPoolRequest(
@@ -1246,8 +1315,12 @@ def _request_from_run_sheet(self, sheet: ParsedSheet) -> SeqRunSetRequest:
operator=str(row.get("operator") or "").strip() or None,
instrument_euid=str(row.get("instrument_euid") or "").strip() or None,
machine=str(row.get("machine") or "").strip() or None,
- flowcell_barcode=str(row.get("flowcell_barcode") or row.get("flowcell") or "").strip(),
- reagent_euids=self._split_values(row.get("reagent_euids") or row.get("reagents")),
+ flowcell_barcode=str(
+ row.get("flowcell_barcode") or row.get("flowcell") or ""
+ ).strip(),
+ reagent_euids=self._split_values(
+ row.get("reagent_euids") or row.get("reagents")
+ ),
status=str(row.get("status") or "created").strip() or "created",
name=str(row.get("name") or "").strip() or None,
description=str(row.get("description") or "").strip() or None,
@@ -1264,16 +1337,28 @@ def _request_from_data_sheet(self, sheet: ParsedSheet) -> PlateWellDataRequest:
or row.get("annotation_template_euid")
or data_template_code
).strip()
- relationship_type = str(row.get("relationship_type") or relationship_type).strip()
+ relationship_type = str(
+ row.get("relationship_type") or relationship_type
+ ).strip()
records.append(
PlateWellDataRecord(
- well_euid=str(row.get("well_euid") or row.get("child_container_euid") or "").strip()
+ well_euid=str(
+ row.get("well_euid") or row.get("child_container_euid") or ""
+ ).strip()
or None,
- plate_euid=str(row.get("plate_euid") or row.get("container_euid") or "").strip()
+ plate_euid=str(
+ row.get("plate_euid") or row.get("container_euid") or ""
+ ).strip()
or None,
- row=row.get("row") or row.get("well_row") or row.get("child_container_row"),
- col=row.get("col") or row.get("well_col") or row.get("child_container_column"),
- name=str(row.get("name") or row.get("annotation_name") or "").strip()
+ row=row.get("row")
+ or row.get("well_row")
+ or row.get("child_container_row"),
+ col=row.get("col")
+ or row.get("well_col")
+ or row.get("child_container_column"),
+ name=str(
+ row.get("name") or row.get("annotation_name") or ""
+ ).strip()
or None,
target="content"
if "content"
@@ -1281,11 +1366,17 @@ def _request_from_data_sheet(self, sheet: ParsedSheet) -> PlateWellDataRequest:
row.get("target")
or row.get("annotate_container_child_container_content")
or "content"
- ).strip().lower()
+ )
+ .strip()
+ .lower()
else "well",
data={
**self._row_metadata(row, "data_", "annotation_", "metric_"),
- **({"value": row.get("annotation_value")} if row.get("annotation_value") not in (None, "") else {}),
+ **(
+ {"value": row.get("annotation_value")}
+ if row.get("annotation_value") not in (None, "")
+ else {}
+ ),
},
)
)
@@ -1305,13 +1396,21 @@ def _requests_from_sets_sheet(self, sheet: ParsedSheet) -> list[LabSetRequest]:
LabSetRequest(
name=name,
description=str(row.get("description") or "").strip() or None,
- members=self._split_values(row.get("members") or row.get("member_euids")),
+ members=self._split_values(
+ row.get("members") or row.get("member_euids")
+ ),
external_members=self._split_values(row.get("external_members")),
operator=str(row.get("operator") or "").strip() or None,
- instrument=str(row.get("instrument") or row.get("instrument_euid") or "").strip() or None,
- reagents=self._split_values(row.get("reagents") or row.get("reagent_euids")),
+ instrument=str(
+ row.get("instrument") or row.get("instrument_euid") or ""
+ ).strip()
+ or None,
+ reagents=self._split_values(
+ row.get("reagents") or row.get("reagent_euids")
+ ),
machine=str(row.get("machine") or "").strip() or None,
- flowcell_barcode=str(row.get("flowcell_barcode") or "").strip() or None,
+ flowcell_barcode=str(row.get("flowcell_barcode") or "").strip()
+ or None,
status=str(row.get("status") or "created").strip() or "created",
metadata=self._row_metadata(row, "metadata_", "set_"),
)
@@ -1331,7 +1430,11 @@ def import_spreadsheet(
"headers": sheet.headers,
"row_count": len(sheet.rows),
}
- if action in {"container_interaction_preview", "container_annotation_preview", "unknown"}:
+ if action in {
+ "container_interaction_preview",
+ "container_annotation_preview",
+ "unknown",
+ }:
entry["preview_rows"] = sheet.rows[:25]
actions.append(entry)
continue
@@ -1399,4 +1502,8 @@ def print_euids(self, request: PrintEuidRequest) -> dict[str, Any]:
print_n=request.copies,
)
)
- return {"printed": 0 if request.dry_run else len(results), "dry_run": request.dry_run, "results": results}
+ return {
+ "printed": 0 if request.dry_run else len(results),
+ "dry_run": request.dry_run,
+ "results": results,
+ }
diff --git a/bloom_lims/etc/prefix_ownership_registry.json b/bloom_lims/etc/prefix_ownership_registry.json
index 2acba7a..9c703fd 100644
--- a/bloom_lims/etc/prefix_ownership_registry.json
+++ b/bloom_lims/etc/prefix_ownership_registry.json
@@ -172,6 +172,9 @@
"GVR": {
"issuer_app_code": "daylily-tapdb"
},
+ "GSE": {
+ "issuer_app_code": "daylily-tapdb"
+ },
"MSG": {
"issuer_app_code": "daylily-tapdb"
},
diff --git a/bloom_lims/gui/actions.py b/bloom_lims/gui/actions.py
index a41d394..d695dd2 100644
--- a/bloom_lims/gui/actions.py
+++ b/bloom_lims/gui/actions.py
@@ -25,10 +25,19 @@
{"value": "beta_pool_member", "label": "beta_pool_member"},
{"value": "beta_pooling_run_input", "label": "beta_pooling_run_input"},
{"value": "beta_sequencing_run", "label": "beta_sequencing_run"},
- {"value": "beta_sequenced_library_assignment", "label": "beta_sequenced_library_assignment"},
+ {
+ "value": "beta_sequenced_library_assignment",
+ "label": "beta_sequenced_library_assignment",
+ },
{"value": "beta_assignment_source", "label": "beta_assignment_source"},
- {"value": "beta_assignment_library_material", "label": "beta_assignment_library_material"},
- {"value": "beta_assignment_barcode_reagent", "label": "beta_assignment_barcode_reagent"},
+ {
+ "value": "beta_assignment_library_material",
+ "label": "beta_assignment_library_material",
+ },
+ {
+ "value": "beta_assignment_barcode_reagent",
+ "label": "beta_assignment_barcode_reagent",
+ },
{"value": "beta_run_artifact", "label": "beta_run_artifact"},
]
diff --git a/bloom_lims/integrations/tapdb_mount.py b/bloom_lims/integrations/tapdb_mount.py
index e81f39e..4ed417e 100644
--- a/bloom_lims/integrations/tapdb_mount.py
+++ b/bloom_lims/integrations/tapdb_mount.py
@@ -112,7 +112,9 @@ def _build_tapdb_host_bridge() -> TapdbHostBridge:
shell_title="Bloom",
shell_subtitle="TapDB substrate",
home_url="/",
- login_url=lambda request: f"/login?next={quote(_request_next_path(request), safe='/')}",
+ login_url=lambda request: (
+ f"/login?next={quote(_request_next_path(request), safe='/')}"
+ ),
logout_url="/logout",
change_password_url=None,
resolve_user=_tapdb_host_user,
diff --git a/bloom_lims/schemas/beta_lab.py b/bloom_lims/schemas/beta_lab.py
index 1e855ea..1cbe634 100644
--- a/bloom_lims/schemas/beta_lab.py
+++ b/bloom_lims/schemas/beta_lab.py
@@ -101,7 +101,9 @@ def validate_context(self) -> "AtlasFulfillmentContext":
self.atlas_order_test_euids = normalized_order_test_euids
if self.atlas_order_test_euid is None and self.atlas_order_test_euids:
self.atlas_order_test_euid = self.atlas_order_test_euids[0]
- if (self.atlas_order_test_euid or self.atlas_order_test_euids) and not self.atlas_order_euid:
+ if (
+ self.atlas_order_test_euid or self.atlas_order_test_euids
+ ) and not self.atlas_order_euid:
raise ValueError(
"atlas_order_euid is required when atlas_order_test_euid is provided"
)
@@ -394,9 +396,9 @@ class BetaRunArtifactInput(BaseModel):
class BetaRunCreateRequest(BaseModel):
pool_euid: str
platform: Literal["ILMN", "ONT", "Ultima", "PacBio", "CompleteGenomics"]
- run_subtype: Literal[
- "illumina", "ont", "ultima", "pacbio", "completegenomics"
- ] = Field(default="illumina")
+ run_subtype: Literal["illumina", "ont", "ultima", "pacbio", "completegenomics"] = (
+ Field(default="illumina")
+ )
flowcell_id: str
run_name: str | None = None
status: Literal["started", "completed"] = Field(default="completed")
diff --git a/bloom_lims/schemas/lab_actions.py b/bloom_lims/schemas/lab_actions.py
index 9757601..bb0b283 100644
--- a/bloom_lims/schemas/lab_actions.py
+++ b/bloom_lims/schemas/lab_actions.py
@@ -172,7 +172,9 @@ class PlateWellDataRecord(BaseModel):
@model_validator(mode="after")
def validate_target(self) -> "PlateWellDataRecord":
- if self.well_euid and (self.plate_euid or self.row is not None or self.col is not None):
+ if self.well_euid and (
+ self.plate_euid or self.row is not None or self.col is not None
+ ):
raise ValueError("provide well_euid or plate_euid with row/col, not both")
if not self.well_euid:
if not self.plate_euid or self.row is None or self.col is None:
diff --git a/bloom_lims/schemas/objects.py b/bloom_lims/schemas/objects.py
index deb3d97..784fdb4 100644
--- a/bloom_lims/schemas/objects.py
+++ b/bloom_lims/schemas/objects.py
@@ -21,7 +21,9 @@ class JsonAddlSchema(BloomBaseSchema):
# Common optional fields
notes: Optional[str] = Field(None, max_length=10000, description="General notes")
tags: Optional[List[str]] = Field(None, description="Tags for categorization")
- custom_fields: Optional[Dict[str, Any]] = Field(None, description="Custom field values")
+ custom_fields: Optional[Dict[str, Any]] = Field(
+ None, description="Custom field values"
+ )
# Allow extra fields for flexibility
model_config = {"extra": "allow"}
@@ -41,10 +43,19 @@ class ObjectBaseSchema(BloomBaseSchema):
"""Base schema for BloomObj/generic_instance objects."""
name: str = Field(..., min_length=1, max_length=500, description="Object name")
- type: str = Field(..., min_length=1, max_length=100, description="Object type (e.g., sample, plate)")
+ type: str = Field(
+ ...,
+ min_length=1,
+ max_length=100,
+ description="Object type (e.g., sample, plate)",
+ )
subtype: Optional[str] = Field(None, max_length=100, description="Object subtype")
- category: str = Field(default="instance", max_length=50, description="Object category")
- json_addl: Optional[Dict[str, Any]] = Field(default_factory=dict, description="Additional JSON data")
+ category: str = Field(
+ default="instance", max_length=50, description="Object category"
+ )
+ json_addl: Optional[Dict[str, Any]] = Field(
+ default_factory=dict, description="Additional JSON data"
+ )
@field_validator("type", mode="before")
@classmethod
@@ -62,6 +73,7 @@ def ensure_json_addl_dict(cls, v):
return {}
if isinstance(v, str):
import json
+
try:
return json.loads(v)
except json.JSONDecodeError:
@@ -72,10 +84,16 @@ def ensure_json_addl_dict(cls, v):
class ObjectCreateSchema(ObjectBaseSchema):
"""Schema for creating a new BloomObj."""
- parent_euid: Optional[str] = Field(None, description="Parent object EUID for lineage")
+ parent_euid: Optional[str] = Field(
+ None, description="Parent object EUID for lineage"
+ )
lineage_euid: Optional[str] = Field(None, description="Lineage EUID to attach to")
- container_euid: Optional[str] = Field(None, description="Container EUID for placement")
- container_position: Optional[str] = Field(None, description="Position in container (e.g., A1)")
+ container_euid: Optional[str] = Field(
+ None, description="Container EUID for placement"
+ )
+ container_position: Optional[str] = Field(
+ None, description="Position in container (e.g., A1)"
+ )
count: int = Field(
default=1,
ge=1,
@@ -95,16 +113,30 @@ def validate_euids(cls, v):
class ObjectUpdateSchema(BloomBaseSchema):
"""Schema for updating an existing BloomObj."""
- name: Optional[str] = Field(None, min_length=1, max_length=500, description="Object name")
- json_addl: Optional[Dict[str, Any]] = Field(None, description="Additional JSON data (merged)")
+ name: Optional[str] = Field(
+ None, min_length=1, max_length=500, description="Object name"
+ )
+ json_addl: Optional[Dict[str, Any]] = Field(
+ None, description="Additional JSON data (merged)"
+ )
status: Optional[str] = Field(None, max_length=50, description="Object status")
is_deleted: Optional[bool] = Field(None, description="Soft delete flag")
- created_dt: Optional[datetime] = Field(None, description="Creation datetime (admin only)")
+ created_dt: Optional[datetime] = Field(
+ None, description="Creation datetime (admin only)"
+ )
@model_validator(mode="after")
def check_at_least_one_field(self):
"""Ensure at least one field is provided for update."""
- if not any([self.name, self.json_addl, self.status, self.is_deleted is not None, self.created_dt]):
+ if not any(
+ [
+ self.name,
+ self.json_addl,
+ self.status,
+ self.is_deleted is not None,
+ self.created_dt,
+ ]
+ ):
raise ValueError("At least one field must be provided for update")
return self
@@ -116,7 +148,9 @@ class ObjectResponseSchema(ObjectBaseSchema, TimestampMixin):
status: str = Field(default="active", description="Object status")
is_deleted: bool = Field(default=False, description="Soft delete flag")
is_singleton: bool = Field(default=False, description="Singleton instance flag")
- polymorphic_discriminator: Optional[str] = Field(None, description="Type discriminator")
+ polymorphic_discriminator: Optional[str] = Field(
+ None, description="Type discriminator"
+ )
# Relationship info (optional)
parent_euid: Optional[str] = Field(None, description="Parent object EUID")
@@ -136,9 +170,15 @@ class ObjectQueryParams(BloomBaseSchema):
parent_euid: Optional[str] = Field(None, description="Filter by parent")
lineage_euid: Optional[str] = Field(None, description="Filter by lineage")
container_euid: Optional[str] = Field(None, description="Filter by container")
- created_after: Optional[datetime] = Field(None, description="Filter by creation date")
- created_before: Optional[datetime] = Field(None, description="Filter by creation date")
- include_deleted: bool = Field(default=False, description="Include soft-deleted objects")
+ created_after: Optional[datetime] = Field(
+ None, description="Filter by creation date"
+ )
+ created_before: Optional[datetime] = Field(
+ None, description="Filter by creation date"
+ )
+ include_deleted: bool = Field(
+ default=False, description="Include soft-deleted objects"
+ )
@field_validator("type", "subtype", mode="before")
@classmethod
diff --git a/bloom_lims/tapdb_metrics.py b/bloom_lims/tapdb_metrics.py
index 2c8be42..a4f4fca 100644
--- a/bloom_lims/tapdb_metrics.py
+++ b/bloom_lims/tapdb_metrics.py
@@ -85,7 +85,9 @@ def _explicit_config_metrics_enabled(config_path: Path) -> bool | None:
try:
loaded = yaml.safe_load(config_path.read_text(encoding="utf-8"))
except yaml.YAMLError as exc:
- raise RuntimeError(f"Failed to parse Bloom TapDB metrics config: {exc}") from exc
+ raise RuntimeError(
+ f"Failed to parse Bloom TapDB metrics config: {exc}"
+ ) from exc
if not isinstance(loaded, dict):
return None
target = loaded.get("target")
diff --git a/container_tests/test_container_runtime.py b/container_tests/test_container_runtime.py
index 4f93a29..6d8617d 100644
--- a/container_tests/test_container_runtime.py
+++ b/container_tests/test_container_runtime.py
@@ -7,7 +7,6 @@
from bloom_lims import container_entry
-
PROJECT_ROOT = Path(__file__).resolve().parents[1]
@@ -18,7 +17,7 @@ def test_docker_runtime_files_use_foreground_uv_and_no_legacy_runtime() -> None:
assert "uv sync --frozen --no-dev --no-install-project" in dockerfile
assert "uv sync --frozen --no-dev" in dockerfile
assert "USER lsmc" in dockerfile
- assert "python\", \"-m\", \"bloom_lims.container_entry" in dockerfile
+ assert 'python", "-m", "bloom_lims.container_entry' in dockerfile
assert ":latest" not in dockerfile
assert "conda" not in dockerfile.lower()
assert "tmux" not in entrypoint
@@ -26,7 +25,9 @@ def test_docker_runtime_files_use_foreground_uv_and_no_legacy_runtime() -> None:
assert "${BLOOM_CONFIG_PATH:?BLOOM_CONFIG_PATH is required}" in entrypoint
-def test_container_entry_requires_absolute_config_path(monkeypatch: pytest.MonkeyPatch) -> None:
+def test_container_entry_requires_absolute_config_path(
+ monkeypatch: pytest.MonkeyPatch,
+) -> None:
monkeypatch.setenv("BLOOM_CONFIG_PATH", "relative.yaml")
with pytest.raises(RuntimeError, match="must be an absolute path"):
diff --git a/pyproject.toml b/pyproject.toml
index 6a6225e..cb87f2a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -28,8 +28,9 @@ license = {text = "MIT"}
requires-python = ">=3.12"
dependencies = [
"cli-core-yo==2.1.1",
- "daylily-tapdb @ git+https://github.com/Daylily-Informatics/daylily-tapdb.git@9.0.9",
+ "daylily-tapdb @ git+https://github.com/Daylily-Informatics/daylily-tapdb.git@9.0.10",
"daylily-auth-cognito==2.1.5",
+ "defusedxml>=0.7.1",
"IPython>=8.18.1",
"bandit[toml]>=1.8.0",
"black>=24.0.0",
diff --git a/tests/test_action_button_template_safety.py b/tests/test_action_button_template_safety.py
index b06b0a8..5f3a9bf 100644
--- a/tests/test_action_button_template_safety.py
+++ b/tests/test_action_button_template_safety.py
@@ -2,7 +2,6 @@
from pathlib import Path
-
PROJECT_ROOT = Path(__file__).resolve().parent.parent
@@ -13,9 +12,12 @@ def _read(path: str) -> str:
def test_modern_euid_details_uses_data_attribute_action_handler():
template = _read("templates/modern/euid_details.html")
- assert "onclick=\"showCapturedDataFormFromDataAttributes(this)\"" in template
- assert "data-action-json=\"{{ action_value | tojson | e }}\"" in template
- assert "onclick=\"showCapturedDataForm(this, {{ action_value | tojson }}" not in template
+ assert 'onclick="showCapturedDataFormFromDataAttributes(this)"' in template
+ assert 'data-action-json="{{ action_value | tojson | e }}"' in template
+ assert (
+ 'onclick="showCapturedDataForm(this, {{ action_value | tojson }}'
+ not in template
+ )
def test_modern_euid_details_has_no_toast_only_print_button():
@@ -28,10 +30,13 @@ def test_modern_euid_details_has_no_toast_only_print_button():
def test_modern_workflow_details_uses_data_attribute_action_handler():
template = _read("templates/modern/workflow_details.html")
- assert "onclick=\"showCapturedDataFormFromDataAttributes(this)\"" in template
- assert "data-action-json=\"{{ action_value | tojson | e }}\"" in template
- assert "onclick=\"showCapturedDataForm(this, {{ action_value }}" not in template
- assert "onclick=\"showCapturedDataForm(this, {{ action_value | tojson }}" not in template
+ assert 'onclick="showCapturedDataFormFromDataAttributes(this)"' in template
+ assert 'data-action-json="{{ action_value | tojson | e }}"' in template
+ assert 'onclick="showCapturedDataForm(this, {{ action_value }}' not in template
+ assert (
+ 'onclick="showCapturedDataForm(this, {{ action_value | tojson }}'
+ not in template
+ )
def test_action_buttons_uses_ui_schema_fields_array_for_filtering():
diff --git a/tests/test_action_schema_hydration.py b/tests/test_action_schema_hydration.py
index 2b508d1..b84a45b 100644
--- a/tests/test_action_schema_hydration.py
+++ b/tests/test_action_schema_hydration.py
@@ -74,9 +74,10 @@ def test_hydrate_dynamic_action_groups_adds_relationship_type_dropdown():
assert {"value": "derived_from", "label": "derived_from"} in relationship_field[
"options"
]
- assert {"value": "beta_sequencing_run", "label": "beta_sequencing_run"} in relationship_field[
- "options"
- ]
+ assert {
+ "value": "beta_sequencing_run",
+ "label": "beta_sequencing_run",
+ } in relationship_field["options"]
def test_hydrate_dynamic_action_groups_hides_subject_decision_scope_action():
diff --git a/tests/test_anomalies.py b/tests/test_anomalies.py
index 888b8b3..cc48de9 100644
--- a/tests/test_anomalies.py
+++ b/tests/test_anomalies.py
@@ -33,7 +33,9 @@ def _build_fake_repository() -> TapdbAnomalyRepository:
instances: list[SimpleNamespace] = []
counter = {"value": 0}
- def create_instance(*, template_code: str, name: str, properties: dict, session) -> SimpleNamespace:
+ def create_instance(
+ *, template_code: str, name: str, properties: dict, session
+ ) -> SimpleNamespace:
counter["value"] += 1
category, type_name, subtype, version = template_code.strip("/").split("/")
instance = SimpleNamespace(
@@ -174,7 +176,9 @@ def test_anomaly_api_lists_and_reads_records(monkeypatch) -> None:
def test_admin_anomalies_views_render(monkeypatch) -> None:
monkeypatch.setattr(operations, "BLOOMdb3", _StubBloomDB)
- monkeypatch.setattr(operations, "TapdbAnomalyRepository", lambda _session: _StubRepository())
+ monkeypatch.setattr(
+ operations, "TapdbAnomalyRepository", lambda _session: _StubRepository()
+ )
with TestClient(app, raise_server_exceptions=False) as client:
listing = client.get("/admin/anomalies")
diff --git a/tests/test_beta_lab_schema.py b/tests/test_beta_lab_schema.py
index 74dfe1c..1921048 100644
--- a/tests/test_beta_lab_schema.py
+++ b/tests/test_beta_lab_schema.py
@@ -29,7 +29,9 @@ def test_atlas_fulfillment_context_preserves_order_refs():
"Z-AGX-TEST1",
"Z-AGX-TEST2",
]
- assert payload["fulfillment_slots"][0]["atlas_fulfillment_slot_euid"] == "Z-AGX-SLOT1"
+ assert (
+ payload["fulfillment_slots"][0]["atlas_fulfillment_slot_euid"] == "Z-AGX-SLOT1"
+ )
def test_atlas_fulfillment_context_requires_order_for_order_tests():
diff --git a/tests/test_beta_modern_action_system.py b/tests/test_beta_modern_action_system.py
index 03b4b5c..4f82f03 100644
--- a/tests/test_beta_modern_action_system.py
+++ b/tests/test_beta_modern_action_system.py
@@ -1029,15 +1029,57 @@ def v0_edge_tuples():
library_material_euid,
"source_material",
),
- ("RUN_CONSUMED", extraction_body["extraction_run_euid"], "workflow_run", specimen_euid, "consumed_material"),
- ("RUN_PRODUCED", extraction_body["extraction_run_euid"], "workflow_run", extraction_output_euid, "produced_material"),
- ("RUN_CONSUMED", pooling_run_euid, "workflow_run", library_material_euid, "consumed_material"),
- ("RUN_PRODUCED", pooling_run_euid, "workflow_run", pool_euid, "produced_material"),
+ (
+ "RUN_CONSUMED",
+ extraction_body["extraction_run_euid"],
+ "workflow_run",
+ specimen_euid,
+ "consumed_material",
+ ),
+ (
+ "RUN_PRODUCED",
+ extraction_body["extraction_run_euid"],
+ "workflow_run",
+ extraction_output_euid,
+ "produced_material",
+ ),
+ (
+ "RUN_CONSUMED",
+ pooling_run_euid,
+ "workflow_run",
+ library_material_euid,
+ "consumed_material",
+ ),
+ (
+ "RUN_PRODUCED",
+ pooling_run_euid,
+ "workflow_run",
+ pool_euid,
+ "produced_material",
+ ),
("RUN_CONSUMED", run_euid, "workflow_run", pool_euid, "consumed_material"),
- ("RUN_CONSUMED", run_euid, "workflow_run", lib_output_euid, "consumed_artifact"),
- ("RUN_CONSUMED", run_euid, "workflow_run", library_material_euid, "consumed_material"),
+ (
+ "RUN_CONSUMED",
+ run_euid,
+ "workflow_run",
+ lib_output_euid,
+ "consumed_artifact",
+ ),
+ (
+ "RUN_CONSUMED",
+ run_euid,
+ "workflow_run",
+ library_material_euid,
+ "consumed_material",
+ ),
("RUN_PRODUCED", run_euid, "workflow_run", artifact_euid, "produced_artifact"),
- ("SLOT_SATISFIED_BY", fulfillment_slot_ref, "fulfillment_slot", library_material_euid, "satisfying_bloom_object"),
+ (
+ "SLOT_SATISFIED_BY",
+ fulfillment_slot_ref,
+ "fulfillment_slot",
+ library_material_euid,
+ "satisfying_bloom_object",
+ ),
}.issubset(v0_edge_tuples())
plate_graph = _props(instance(plate_euid))["graph"]
diff --git a/tests/test_cli_db_command_paths.py b/tests/test_cli_db_command_paths.py
index d9aba92..b93d20d 100644
--- a/tests/test_cli_db_command_paths.py
+++ b/tests/test_cli_db_command_paths.py
@@ -630,6 +630,14 @@ def test_retire_obsolete_template_variants_only_deletes_stale_prefixes() -> None
"instance_prefix": "BRN",
"json_addl": {"semantic_category": "data"},
},
+ {
+ "category": "material",
+ "type": "sample",
+ "subtype": "gdna",
+ "version": "1.0",
+ "instance_prefix": "BNG",
+ "json_addl": {"semantic_category": "content"},
+ },
{
"category": "container",
"type": "tube",
@@ -679,6 +687,16 @@ def test_retire_obsolete_template_variants_only_deletes_stale_prefixes() -> None
bstatus="active",
json_addl={"semantic_category": "container"},
)
+ material_content = SimpleNamespace(
+ domain_code="Z",
+ type="sample",
+ category="material",
+ subtype="gdna",
+ version="1.0",
+ is_deleted=False,
+ bstatus="active",
+ json_addl={"semantic_category": "content"},
+ )
non_data = SimpleNamespace(
domain_code="Z",
type="sequencing_run",
@@ -709,6 +727,7 @@ def all(self):
stale_prefix,
stale_subtype,
stale_container_prefix,
+ material_content,
non_data,
]
@@ -731,7 +750,7 @@ def flush(self):
domain_code="Z",
)
- assert retired == 4
+ assert retired == 3
assert current.is_deleted is False
assert stale_prefix.is_deleted is True
assert stale_prefix.bstatus == "retired"
@@ -739,8 +758,8 @@ def flush(self):
assert stale_subtype.bstatus == "retired"
assert stale_container_prefix.is_deleted is True
assert stale_container_prefix.bstatus == "retired"
- assert non_data.is_deleted is True
- assert non_data.bstatus == "retired"
+ assert material_content.is_deleted is False
+ assert non_data.is_deleted is False
assert fake_session.flushed == 1
diff --git a/tests/test_config_runtime.py b/tests/test_config_runtime.py
index 4e23e87..627a372 100644
--- a/tests/test_config_runtime.py
+++ b/tests/test_config_runtime.py
@@ -348,7 +348,9 @@ def test_create_app_does_not_mount_upload_or_tmp_static_dirs(
get_settings.cache_clear()
app = create_app()
- mount_paths = {route.path for route in app.routes}
+ mount_paths = {
+ path for route in app.routes if (path := getattr(route, "path", None))
+ }
assert "/static" in mount_paths
assert "/templates" in mount_paths
@@ -445,7 +447,7 @@ def test_tapdb_contract_defaults_match_shipped_templates(monkeypatch, tmp_path:
settings = BloomSettings(storage={"upload_dir": str(tmp_path / "uploads")})
expected_tapdb_spec = read_pyproject_dependency_spec("daylily-tapdb")
- assert expected_tapdb_spec == "==9.0.4"
+ assert expected_tapdb_spec == "==9.0.10"
assert assert_tapdb_version()
assert settings.tapdb.owner_repo_name == DEFAULT_TAPDB_OWNER_REPO_NAME
assert settings.tapdb.domain_code == DEFAULT_TAPDB_DOMAIN_CODE
@@ -557,6 +559,7 @@ def test_tapdb_contract_defaults_match_shipped_templates(monkeypatch, tmp_path:
"BWF",
"BWS",
"EDG",
+ "GSE",
"GVR",
"MSG",
"SYS",
diff --git a/tests/test_core_validation.py b/tests/test_core_validation.py
index 388e728..eed3cb0 100644
--- a/tests/test_core_validation.py
+++ b/tests/test_core_validation.py
@@ -2,17 +2,26 @@
Tests for bloom_lims.core.validation module.
"""
+import json
+import tempfile
+from pathlib import Path
+
import pytest
+from bloom_lims.core.template_validation import (
+ TemplateDefinition,
+ TemplateValidator,
+ ValidationResult,
+)
from bloom_lims.core.validation import (
ValidationError,
validate_euid,
validate_json_addl,
- validate_type,
validate_not_empty,
validate_positive_int,
- validated,
validate_schema,
+ validate_type,
+ validated,
)
@@ -68,17 +77,19 @@ def test_invalid_format_with_leading_zero(self):
with pytest.raises(ValidationError) as exc_info:
validate_euid("CX01")
assert "No leading zeros" in str(exc_info.value)
+
+
class TestValidateJsonAddl:
"""Tests for validate_json_addl function."""
-
+
def test_valid_dict(self):
"""Test validation of valid dict."""
assert validate_json_addl({"key": "value"}) is True
-
+
def test_none_allowed(self):
"""Test that None is allowed."""
assert validate_json_addl(None) is True
-
+
def test_non_dict(self):
"""Test that non-dict raises ValidationError."""
with pytest.raises(ValidationError) as exc_info:
@@ -91,6 +102,7 @@ class TestValidatedDecorator:
def test_valid_arguments(self):
"""Test that valid arguments pass through."""
+
@validated(euid=validate_euid)
def process(euid: str) -> str:
return f"processed: {euid}"
@@ -100,6 +112,7 @@ def process(euid: str) -> str:
def test_invalid_argument_raises(self):
"""Test that invalid arguments raise ValidationError."""
+
@validated(euid=validate_euid)
def process(euid: str) -> str:
return f"processed: {euid}"
@@ -109,6 +122,7 @@ def process(euid: str) -> str:
def test_multiple_validators(self):
"""Test multiple validators on different arguments."""
+
@validated(euid=validate_euid, data=validate_json_addl)
def process(euid: str, data: dict) -> dict:
return {"euid": euid, "data": data}
@@ -155,16 +169,6 @@ def test_wrong_type(self):
# Template Validation Tests
-from bloom_lims.core.template_validation import (
- TemplateValidator,
- ValidationResult,
- TemplateDefinition,
-)
-from pathlib import Path
-import tempfile
-import json
-
-
class TestValidationResult:
"""Tests for ValidationResult dataclass."""
@@ -244,9 +248,7 @@ def test_validate_with_temp_directory(self):
"test_workflow": {
"1.0": {
"singleton": "0",
- "action_imports": {
- "test_action": "action/generic/test/1.0"
- }
+ "action_imports": {"test_action": "action/generic/test/1.0"},
}
}
}
@@ -274,9 +276,7 @@ def test_grouped_action_imports_is_rejected(self):
"1.0": {
"singleton": "0",
"action_imports": {
- "default": {
- "actions": {"action/generic/test/1.0": {}}
- }
+ "default": {"actions": {"action/generic/test/1.0": {}}}
},
}
}
@@ -313,21 +313,25 @@ class TestValidatorImports:
def test_import_validation_error(self):
"""Test ValidationError import."""
from bloom_lims.core.validation import ValidationError
+
assert ValidationError is not None
def test_import_validate_euid(self):
"""Test validate_euid import."""
from bloom_lims.core.validation import validate_euid
+
assert callable(validate_euid)
def test_import_validate_json_addl(self):
"""Test validate_json_addl import."""
from bloom_lims.core.validation import validate_json_addl
+
assert callable(validate_json_addl)
def test_import_validated_decorator(self):
"""Test validated decorator import."""
from bloom_lims.core.validation import validated
+
assert callable(validated)
@@ -361,7 +365,6 @@ def test_validate_schema_missing_required(self):
def test_validate_not_empty_with_values(self):
"""Test validate_not_empty with various values."""
- from bloom_lims.core.validation import validate_not_empty
assert validate_not_empty("hello") is True
assert validate_not_empty(" test ") is True
@@ -370,7 +373,7 @@ def test_validate_not_empty_with_values(self):
def test_validate_not_empty_with_empty(self):
"""Test validate_not_empty with empty values."""
- from bloom_lims.core.validation import validate_not_empty, ValidationError
+ from bloom_lims.core.validation import ValidationError
with pytest.raises(ValidationError):
validate_not_empty("")
@@ -383,7 +386,6 @@ def test_validate_not_empty_with_empty(self):
def test_validate_positive_int_valid(self):
"""Test validate_positive_int with valid values."""
- from bloom_lims.core.validation import validate_positive_int
assert validate_positive_int(1) is True
assert validate_positive_int(100) is True
@@ -391,7 +393,7 @@ def test_validate_positive_int_valid(self):
def test_validate_positive_int_invalid(self):
"""Test validate_positive_int with invalid values."""
- from bloom_lims.core.validation import validate_positive_int, ValidationError
+ from bloom_lims.core.validation import ValidationError
with pytest.raises(ValidationError):
validate_positive_int(0)
@@ -410,54 +412,49 @@ def test_validate_euid_with_prefix(self):
# Valid EUIDs require PREFIX (2-3 uppercase letters) + sequence number (no leading zeros)
# Pattern: [A-Z]{2,3}[1-9][0-9]*$
- assert validate_euid("CX1") == True
- assert validate_euid("WF123") == True
- assert validate_euid("MRX42") == True
+ assert validate_euid("CX1") is True
+ assert validate_euid("WF123") is True
+ assert validate_euid("MRX42") is True
def test_validate_json_addl_with_dict(self):
"""Test validate_json_addl with dictionary."""
from bloom_lims.core.validation import validate_json_addl
# Valid dict should pass
- assert validate_json_addl({"key": "value"}) == True
- assert validate_json_addl({}) == True
+ assert validate_json_addl({"key": "value"}) is True
+ assert validate_json_addl({}) is True
def test_validate_json_addl_with_none(self):
"""Test validate_json_addl with None."""
from bloom_lims.core.validation import validate_json_addl
# None should be valid (optional field)
- assert validate_json_addl(None) == True
+ assert validate_json_addl(None) is True
def test_validate_type_container(self):
"""Test validate_type with container type."""
- from bloom_lims.core.validation import validate_type
- assert validate_type("container") == True
+ assert validate_type("container") is True
def test_validate_type_content(self):
"""Test validate_type with content type."""
- from bloom_lims.core.validation import validate_type
- assert validate_type("content") == True
+ assert validate_type("content") is True
def test_validate_type_workflow(self):
"""Test validate_type with workflow type."""
- from bloom_lims.core.validation import validate_type
- assert validate_type("workflow") == True
+ assert validate_type("workflow") is True
def test_validate_not_empty_with_string(self):
"""Test validate_not_empty with non-empty string."""
- from bloom_lims.core.validation import validate_not_empty
- assert validate_not_empty("test") == True
+ assert validate_not_empty("test") is True
def test_validate_not_empty_with_list(self):
"""Test validate_not_empty with non-empty list."""
- from bloom_lims.core.validation import validate_not_empty
- assert validate_not_empty([1, 2, 3]) == True
+ assert validate_not_empty([1, 2, 3]) is True
def test_validate_schema_with_valid_data(self):
"""Test validate_schema with valid data."""
@@ -465,7 +462,7 @@ def test_validate_schema_with_valid_data(self):
schema = {
"name": {"type": str, "required": True},
- "count": {"type": int, "required": False}
+ "count": {"type": int, "required": False},
}
data = {"name": "test", "count": 5}
errors = validate_schema(data, schema)
@@ -475,9 +472,7 @@ def test_validate_schema_with_missing_required(self):
"""Test validate_schema with missing required field."""
from bloom_lims.core.validation import validate_schema
- schema = {
- "name": {"type": str, "required": True}
- }
+ schema = {"name": {"type": str, "required": True}}
data = {}
errors = validate_schema(data, schema)
assert len(errors) > 0
diff --git a/tests/test_cytoscape_dag.py b/tests/test_cytoscape_dag.py
index aa3429a..5728d5a 100644
--- a/tests/test_cytoscape_dag.py
+++ b/tests/test_cytoscape_dag.py
@@ -13,12 +13,12 @@
- Graph data structure validation
"""
-import pytest
-import json
import os
-from pathlib import Path
-from unittest.mock import MagicMock, patch, AsyncMock
from datetime import datetime
+from pathlib import Path
+from unittest.mock import MagicMock, patch
+
+import pytest
from bloom_lims.gui.routes.graph import _build_dag_filename
@@ -33,9 +33,7 @@ def test_valid_dag_structure(self):
"nodes": [
{"data": {"id": "CX1", "euid": "CX1", "obj_type": "container"}}
],
- "edges": [
- {"data": {"source": "CX1", "target": "CX2", "id": "LX1"}}
- ]
+ "edges": [{"data": {"source": "CX1", "target": "CX2", "id": "LX1"}}],
}
}
assert "elements" in valid_dag
@@ -45,8 +43,15 @@ def test_valid_dag_structure(self):
def test_node_required_fields(self):
"""Test that nodes have required fields for Cytoscape rendering."""
required_fields = ["id", "euid", "obj_type"]
- node = {"data": {"id": "CX123", "euid": "CX123", "obj_type": "container",
- "name": "Test", "color": "#8B00FF"}}
+ node = {
+ "data": {
+ "id": "CX123",
+ "euid": "CX123",
+ "obj_type": "container",
+ "name": "Test",
+ "color": "#8B00FF",
+ }
+ }
for field in required_fields:
assert field in node["data"], f"Missing required field: {field}"
@@ -54,9 +59,15 @@ def test_node_required_fields(self):
def test_edge_required_fields(self):
"""Test that edges have required fields."""
required_fields = ["source", "target", "id"]
- edge = {"data": {"source": "CX1", "target": "CX2", "id": "LX1",
- "relationship_type": "generic"}}
-
+ edge = {
+ "data": {
+ "source": "CX1",
+ "target": "CX2",
+ "id": "LX1",
+ "relationship_type": "generic",
+ }
+ }
+
for field in required_fields:
assert field in edge["data"], f"Missing required field: {field}"
@@ -97,23 +108,23 @@ def _detect_cycle(self, existing_edges, source, target):
"""Helper function implementing cycle detection algorithm."""
if source == target:
return True
-
+
# Build adjacency list
graph = {}
for src, tgt in existing_edges:
if src not in graph:
graph[src] = []
graph[src].append(tgt)
-
+
# Add proposed edge temporarily
if source not in graph:
graph[source] = []
graph[source].append(target)
-
+
# DFS to detect cycle from target to source
visited = set()
stack = [target]
-
+
while stack:
current = stack.pop()
if current == source:
@@ -123,7 +134,7 @@ def _detect_cycle(self, existing_edges, source, target):
for neighbor in graph.get(current, []):
if neighbor not in visited:
stack.append(neighbor)
-
+
return False
@@ -375,7 +386,7 @@ def test_add_edge_to_graph(self):
{"data": {"id": "CX1"}},
{"data": {"id": "CX2"}},
],
- "edges": []
+ "edges": [],
}
}
new_edge = {"data": {"source": "CX1", "target": "CX2", "id": "LX1"}}
@@ -392,20 +403,18 @@ def test_remove_node_removes_connected_edges(self):
{"data": {"id": "CX1"}},
{"data": {"id": "CX2"}},
],
- "edges": [
- {"data": {"source": "CX1", "target": "CX2", "id": "LX1"}}
- ]
+ "edges": [{"data": {"source": "CX1", "target": "CX2", "id": "LX1"}}],
}
}
# Remove node CX1
node_to_remove = "CX1"
graph["elements"]["nodes"] = [
- n for n in graph["elements"]["nodes"]
- if n["data"]["id"] != node_to_remove
+ n for n in graph["elements"]["nodes"] if n["data"]["id"] != node_to_remove
]
graph["elements"]["edges"] = [
- e for e in graph["elements"]["edges"]
+ e
+ for e in graph["elements"]["edges"]
if e["data"]["source"] != node_to_remove
and e["data"]["target"] != node_to_remove
]
@@ -488,7 +497,7 @@ def mock_request(self):
def test_get_dagv2_returns_empty_when_file_missing(self, mock_request):
"""Test get_dagv2 returns empty structure when file doesn't exist."""
- with patch('os.path.exists', return_value=False):
+ with patch("os.path.exists", return_value=False):
# Simulating the endpoint behavior
dag_fn = mock_request.session["user_data"]["dag_fnv2"]
dag_data = {"elements": {"nodes": [], "edges": []}}
@@ -511,10 +520,7 @@ def test_delete_object_endpoint_structure(self):
def test_add_new_edge_request_structure(self):
"""Test add_new_edge endpoint request structure."""
- request_data = {
- "parent_euid": "CX1",
- "child_euid": "CX2"
- }
+ request_data = {"parent_euid": "CX1", "child_euid": "CX2"}
assert "parent_euid" in request_data
assert "child_euid" in request_data
@@ -530,19 +536,19 @@ def test_all_edge_nodes_exist(self):
{"data": {"id": "CX1"}},
{"data": {"id": "CX2"}},
],
- "edges": [
- {"data": {"source": "CX1", "target": "CX2", "id": "LX1"}}
- ]
+ "edges": [{"data": {"source": "CX1", "target": "CX2", "id": "LX1"}}],
}
}
node_ids = {n["data"]["id"] for n in graph["elements"]["nodes"]}
for edge in graph["elements"]["edges"]:
- assert edge["data"]["source"] in node_ids, \
+ assert edge["data"]["source"] in node_ids, (
f"Edge source {edge['data']['source']} not in nodes"
- assert edge["data"]["target"] in node_ids, \
+ )
+ assert edge["data"]["target"] in node_ids, (
f"Edge target {edge['data']['target']} not in nodes"
+ )
def test_no_duplicate_node_ids(self):
"""Test that there are no duplicate node IDs."""
@@ -568,8 +574,9 @@ def test_no_duplicate_edge_ids(self):
def test_valid_euid_format_in_nodes(self):
"""Test that node EUIDs follow valid format."""
import re
+
# EUID pattern: 2-3 uppercase letters + sequence number (no leading zeros)
- euid_pattern = re.compile(r'^[A-Z]{2,3}[1-9][0-9]*$')
+ euid_pattern = re.compile(r"^[A-Z]{2,3}[1-9][0-9]*$")
valid_euids = ["CX1", "CX123", "WX1000", "MRX42"]
invalid_euids = ["CX01", "cx1", "C1", "BCN-123"]
@@ -628,9 +635,13 @@ def test_fuzzy_search_no_matches(self):
"""Test fuzzy search with no matches."""
nodes = [{"id": "CX1", "name": "Test", "obj_type": "container"}]
query = "xyz"
- matches = [n for n in nodes if query.lower() in n["id"].lower() or
- query.lower() in n["name"].lower() or
- query.lower() in n["obj_type"].lower()]
+ matches = [
+ n
+ for n in nodes
+ if query.lower() in n["id"].lower()
+ or query.lower() in n["name"].lower()
+ or query.lower() in n["obj_type"].lower()
+ ]
assert len(matches) == 0
@@ -664,6 +675,7 @@ def test_layout_data_includes_zoom_pan(self):
def test_layout_expiration_check(self):
"""Test layout expiration logic (7 days)."""
import time
+
max_age_ms = 7 * 24 * 60 * 60 * 1000 # 7 days in milliseconds
current_time = int(time.time() * 1000)
@@ -687,7 +699,7 @@ def test_timestamp_based_click_detection(self):
clicks = [0, 100, 200] # timestamps in ms
click_count = 1
for i in range(1, len(clicks)):
- if clicks[i] - clicks[i-1] < click_threshold_ms:
+ if clicks[i] - clicks[i - 1] < click_threshold_ms:
click_count += 1
else:
click_count = 1
@@ -702,7 +714,7 @@ def test_click_reset_on_timeout(self):
clicks = [0, 100, 700] # 700ms gap resets count
click_count = 1
for i in range(1, len(clicks)):
- if clicks[i] - clicks[i-1] < click_threshold_ms:
+ if clicks[i] - clicks[i - 1] < click_threshold_ms:
click_count += 1
else:
click_count = 1
@@ -803,9 +815,13 @@ def test_graph_js_preserves_tapdb_gestures_and_restored_shortcuts(self):
assert "runNeighborhoodFromNode(node)" in graph_js
assert "openNodeActionDialog(node.data())" in graph_js
- def test_graph_js_requires_z_for_mouse_wheel_zoom_and_points_arrows_to_parents(self):
+ def test_graph_js_requires_z_for_mouse_wheel_zoom_and_points_arrows_to_parents(
+ self,
+ ):
graph_js = Path("static/js/graph.js").read_text(encoding="utf-8")
- template = Path("templates/modern/dag_explorer.html").read_text(encoding="utf-8")
+ template = Path("templates/modern/dag_explorer.html").read_text(
+ encoding="utf-8"
+ )
assert "configureCytoscapeInteractions(container);" in graph_js
assert 'key === "z"' in graph_js
diff --git a/tests/test_domain_workflows_helpers.py b/tests/test_domain_workflows_helpers.py
index 1402b1f..768e3c6 100644
--- a/tests/test_domain_workflows_helpers.py
+++ b/tests/test_domain_workflows_helpers.py
@@ -9,8 +9,8 @@
allow_module_level=True,
)
-import bloom_lims.domain.workflows as workflows_mod
-from bloom_lims.domain.workflows import BloomWorkflowStep
+import bloom_lims.domain.workflows as workflows_mod # noqa: E402
+from bloom_lims.domain.workflows import BloomWorkflowStep # noqa: E402
def _subject() -> BloomWorkflowStep:
@@ -62,7 +62,9 @@ def test_iter_active_child_instances_filters_deleted_and_type():
s = _subject()
keep = _obj("KEEP", category="container", type_name="well")
deleted_lineage = _obj("DEL-LIN", category="container", type_name="well")
- deleted_child = _obj("DEL-CHILD", category="container", type_name="well", is_deleted=True)
+ deleted_child = _obj(
+ "DEL-CHILD", category="container", type_name="well", is_deleted=True
+ )
wrong_type = _obj("WRONG", category="container", type_name="plate")
parent = SimpleNamespace(
parent_of_lineages=[
@@ -72,7 +74,9 @@ def test_iter_active_child_instances_filters_deleted_and_type():
_lineage(wrong_type),
]
)
- found = list(s._iter_active_child_instances(parent, category="container", type_name="well"))
+ found = list(
+ s._iter_active_child_instances(parent, category="container", type_name="well")
+ )
assert [child.euid for _, child in found] == ["KEEP"]
@@ -108,7 +112,10 @@ def test_get_workflow_steps_sorts_by_step_number():
def test_default_queue_name_handles_special_tokens():
s = _subject()
- assert s._default_queue_name("input-gdna-normalization-eligible") == "Input gDNA Normalization Eligible"
+ assert (
+ s._default_queue_name("input-gdna-normalization-eligible")
+ == "Input gDNA Normalization Eligible"
+ )
assert s._default_queue_name("ont-novaseq-libprep") == "ONT Novaseq LibPrep"
@@ -184,16 +191,33 @@ def test_content_helpers_cover_first_active_child_and_occupancy():
def test_get_plate_wells_in_address_order_and_destination_resolution():
s = _subject()
- w2 = _obj("W2", category="container", type_name="well", cont_address={"row_idx": "2", "col_idx": "1"})
- w1 = _obj("W1", category="container", type_name="well", cont_address={"row_idx": "1", "col_idx": "2"})
- w0 = _obj("W0", category="container", type_name="well", cont_address={"row_idx": "1", "col_idx": "1"})
+ w2 = _obj(
+ "W2",
+ category="container",
+ type_name="well",
+ cont_address={"row_idx": "2", "col_idx": "1"},
+ )
+ w1 = _obj(
+ "W1",
+ category="container",
+ type_name="well",
+ cont_address={"row_idx": "1", "col_idx": "2"},
+ )
+ w0 = _obj(
+ "W0",
+ category="container",
+ type_name="well",
+ cont_address={"row_idx": "1", "col_idx": "1"},
+ )
plate = _obj("PLATE1", category="container", type_name="plate")
plate.parent_of_lineages = [_lineage(w2), _lineage(w1), _lineage(w0)]
ordered = s._get_plate_wells_in_address_order(plate)
assert [well.euid for well in ordered] == ["W0", "W1", "W2"]
- s._resolve_well_by_plate_and_address = lambda plate_euid, addr: _obj(f"{plate_euid}.{addr}")
+ s._resolve_well_by_plate_and_address = lambda plate_euid, addr: _obj(
+ f"{plate_euid}.{addr}"
+ )
assert s._resolve_destination_well_ref(plate, "B2").euid == "PLATE1.B2"
assert s._resolve_destination_well_ref(plate, "PLATE1.A1").euid == "PLATE1.A1"
with pytest.raises(Exception, match="does not target destination plate"):
@@ -207,20 +231,34 @@ def test_parse_mapping_rows_and_quant_rows_validation():
"mapping_csv_text": "source_ref,destination_ref\nPLATE1.A1,A1\nPLATE1.B1,B1\n"
}
}
- assert s._parse_mapping_rows(mapping_ds) == [("PLATE1.A1", "A1"), ("PLATE1.B1", "B1")]
+ assert s._parse_mapping_rows(mapping_ds) == [
+ ("PLATE1.A1", "A1"),
+ ("PLATE1.B1", "B1"),
+ ]
with pytest.raises(Exception, match="Invalid mapping row"):
- s._parse_mapping_rows({"captured_data": {"mapping_csv_text": "source_ref,destination_ref\nONLYSOURCE\n"}})
+ s._parse_mapping_rows(
+ {
+ "captured_data": {
+ "mapping_csv_text": "source_ref,destination_ref\nONLYSOURCE\n"
+ }
+ }
+ )
quant_ds = {
"captured_data": {
"quant_csv_text": "plate_euid,well,quant\nPLATE1,A1,1.5\nPLATE1,B1,2.0\n"
}
}
- assert s._parse_quant_rows(quant_ds) == [("PLATE1", "A1", 1.5), ("PLATE1", "B1", 2.0)]
+ assert s._parse_quant_rows(quant_ds) == [
+ ("PLATE1", "A1", 1.5),
+ ("PLATE1", "B1", 2.0),
+ ]
with pytest.raises(Exception, match="Quant value must be float"):
- s._parse_quant_rows({"captured_data": {"quant_csv_text": "PLATE1,A1,not-a-float\n"}})
+ s._parse_quant_rows(
+ {"captured_data": {"quant_csv_text": "PLATE1,A1,not-a-float\n"}}
+ )
def test_get_library_prep_targets_from_properties_or_defaults():
@@ -236,7 +274,9 @@ def test_get_library_prep_targets_from_properties_or_defaults():
]
wf_with_string = _obj("WF2", category="workflow")
- wf_with_string.json_addl["properties"]["library_prep_queue_subtypes"] = "ont-libprep-eligible"
+ wf_with_string.json_addl["properties"]["library_prep_queue_subtypes"] = (
+ "ont-libprep-eligible"
+ )
assert s._get_library_prep_targets(wf_with_string) == ["ont-libprep-eligible"]
wf_default = _obj("WF3", category="workflow")
@@ -276,7 +316,9 @@ def test_route_instances_to_library_prep_queues_links_each_instance():
def test_get_or_create_queue_step_returns_existing_without_creation():
s = _subject()
existing = _obj("STEP-EXIST", category="workflow_step", subtype="target")
- s._get_workflow_steps = lambda _wf, subtype=None: [existing] if subtype == "target" else [existing]
+ s._get_workflow_steps = lambda _wf, subtype=None: (
+ [existing] if subtype == "target" else [existing]
+ )
s.create_instance_by_code = lambda *_args, **_kwargs: _obj("STEP-NEW")
s.create_generic_instance_lineage_by_euids = lambda *_args, **_kwargs: None
s.session = SimpleNamespace(commit=lambda: None)
@@ -286,7 +328,9 @@ def test_get_or_create_queue_step_returns_existing_without_creation():
def test_get_or_create_queue_step_creates_new_step_with_incremented_number():
s = _subject()
- highest = _obj("STEP-HIGH", category="workflow_step", subtype="other", step_number="4")
+ highest = _obj(
+ "STEP-HIGH", category="workflow_step", subtype="other", step_number="4"
+ )
call_state = {"count": 0}
def _get_steps(_wf, subtype=None):
@@ -298,11 +342,11 @@ def _get_steps(_wf, subtype=None):
created = _obj("STEP-NEW", category="workflow_step", subtype="target-queue")
captured = {"layout": "", "payload": None, "lineage": None}
s._get_workflow_steps = _get_steps
- s.create_instance_by_code = (
- lambda layout, payload: captured.update({"layout": layout, "payload": payload}) or created
+ s.create_instance_by_code = lambda layout, payload: (
+ captured.update({"layout": layout, "payload": payload}) or created
)
- s.create_generic_instance_lineage_by_euids = (
- lambda parent, child: captured.update({"lineage": (parent, child)})
+ s.create_generic_instance_lineage_by_euids = lambda parent, child: captured.update(
+ {"lineage": (parent, child)}
)
s.session = SimpleNamespace(commit=lambda: None)
workflow = _obj("WF1", category="workflow")
@@ -332,7 +376,9 @@ def test_ensure_lineage_skips_existing_and_creates_when_missing():
def test_fill_plate_from_sources_undirected_and_directed_error_paths():
s = _subject()
- queue_step = _obj("Q1", category="workflow_step", subtype="input-gdna-normalization-eligible")
+ queue_step = _obj(
+ "Q1", category="workflow_step", subtype="input-gdna-normalization-eligible"
+ )
plate = _obj("PLATE1", category="container", type_name="plate")
source1 = _obj("SRC1", category="container", type_name="well")
source2 = _obj("SRC2", category="container", type_name="well")
@@ -362,7 +408,9 @@ def _resolve(token):
s._resolve_destination_well_ref = lambda _plate, _dest: dst1
s._is_well_occupied = lambda _well: True
with pytest.raises(Exception, match="Destination well already occupied"):
- s._fill_plate_from_sources(queue_step, plate, ["A1"], directed_mapping=[("A1", "A1")])
+ s._fill_plate_from_sources(
+ queue_step, plate, ["A1"], directed_mapping=[("A1", "A1")]
+ )
def test_fill_plate_from_sources_rejects_insufficient_wells():
@@ -377,7 +425,9 @@ def test_fill_plate_from_sources_rejects_insufficient_wells():
s._is_well_occupied = lambda _well: False
s._ensure_lineage = lambda *_args, **_kwargs: None
s._get_first_active_child_content = lambda _instance: None
- s._create_output_gdna_content = lambda normalized=False: _obj("OUT", category="content", type_name="sample")
+ s._create_output_gdna_content = lambda normalized=False: _obj(
+ "OUT", category="content", type_name="sample"
+ )
with pytest.raises(Exception, match="Not enough available wells"):
s._fill_plate_from_sources(queue_step, plate, ["A1", "B1"])
@@ -390,7 +440,9 @@ def test_create_output_gdna_content_sets_normalization_flags(monkeypatch):
touched: list[str] = []
s.query_template_by_component_v2 = lambda *_args: [template]
s.create_instances = lambda _template_euid: [[content_obj]]
- monkeypatch.setattr(workflows_mod, "flag_modified", lambda _obj, field: touched.append(field))
+ monkeypatch.setattr(
+ workflows_mod, "flag_modified", lambda _obj, field: touched.append(field)
+ )
out = s._create_output_gdna_content(normalized=True)
assert out.euid == "MX1"
diff --git a/tests/test_lab_actions_api.py b/tests/test_lab_actions_api.py
index 616b867..500cd01 100644
--- a/tests/test_lab_actions_api.py
+++ b/tests/test_lab_actions_api.py
@@ -48,7 +48,9 @@ def _create_object(
return response.json()
-def _link_material(client: TestClient, *, container_euid: str, content_euid: str) -> None:
+def _link_material(
+ client: TestClient, *, container_euid: str, content_euid: str
+) -> None:
response = client.post(
"/api/v1/lineages/",
json={
@@ -813,7 +815,7 @@ def cell_ref(row_index: int, col_index: int) -> str:
worksheet = (
''
''
- f'{"".join(sheet_rows)} '
+ f"{''.join(sheet_rows)} "
)
output = BytesIO()
with zipfile.ZipFile(output, "w") as archive:
@@ -847,8 +849,7 @@ def test_spreadsheet_import_csv_and_xlsx_preview() -> None:
client = _client()
tube, _ = _create_filled_tube(client, suffix="spreadsheet")
csv_bytes = (
- "tube_euid,row,col,plate_name\n"
- f"{tube},A,1,pytest upload extraction plate\n"
+ f"tube_euid,row,col,plate_name\n{tube},A,1,pytest upload extraction plate\n"
).encode()
dry_run = client.post(
"/api/v1/lab-actions/spreadsheet-import",
@@ -875,9 +876,24 @@ def test_spreadsheet_import_csv_and_xlsx_preview() -> None:
[
[],
[],
- ["SOURCE CONTAINER(s)", None, None, None, None, None, None, None, None, "DESTINATION CONTAINER(s)"],
+ [
+ "SOURCE CONTAINER(s)",
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ "DESTINATION CONTAINER(s)",
+ ],
["Container EUID", "Container Template EUID", "Continer Cat/Type/Subtype"],
- ["BCT-EXAMPLE", "container/tube/tube-generic-10ml/1.0", "container/tube/generic"],
+ [
+ "BCT-EXAMPLE",
+ "container/tube/tube-generic-10ml/1.0",
+ "container/tube/generic",
+ ],
],
)
parsed = parse_workbook("container_interactions.xlsx", workbook)
diff --git a/tests/test_packaging_metadata.py b/tests/test_packaging_metadata.py
index 6051fbf..ea1b0e0 100644
--- a/tests/test_packaging_metadata.py
+++ b/tests/test_packaging_metadata.py
@@ -15,7 +15,10 @@ def test_project_dependencies_pin_release_train_versions() -> None:
assert "cli-core-yo==2.1.1" in dependencies
assert "daylily-auth-cognito==2.1.5" in dependencies
- assert "daylily-tapdb @ git+https://github.com/Daylily-Informatics/daylily-tapdb.git@9.0.9" in dependencies
+ assert (
+ "daylily-tapdb @ git+https://github.com/Daylily-Informatics/daylily-tapdb.git@9.0.10"
+ in dependencies
+ )
assert "IPython>=8.18.1" in dependencies
assert "psycopg2-binary==2.9.12" in dependencies
assert not any(str(dep).startswith("zebra-day") for dep in dependencies)
@@ -48,7 +51,10 @@ def test_dockerfile_uses_package_specific_scm_version() -> None:
encoding="utf-8"
)
- assert "ENV SETUPTOOLS_SCM_PRETEND_VERSION=${SETUPTOOLS_SCM_PRETEND_VERSION}" not in dockerfile
+ assert (
+ "ENV SETUPTOOLS_SCM_PRETEND_VERSION=${SETUPTOOLS_SCM_PRETEND_VERSION}"
+ not in dockerfile
+ )
assert (
"ENV SETUPTOOLS_SCM_PRETEND_VERSION_FOR_BLOOM_LIMS=${SETUPTOOLS_SCM_PRETEND_VERSION}"
in dockerfile
diff --git a/tests/test_queue_flow.py b/tests/test_queue_flow.py
index bf67ba7..b989bdd 100644
--- a/tests/test_queue_flow.py
+++ b/tests/test_queue_flow.py
@@ -73,7 +73,10 @@ def _atlas_context_payload() -> dict[str, object]:
"atlas_tenant_id": _opaque("tenant"),
"atlas_order_euid": order_euid,
"atlas_order_test_euid": primary_order_test_euid,
- "atlas_order_test_euids": [primary_order_test_euid, _opaque("order-test-secondary")],
+ "atlas_order_test_euids": [
+ primary_order_test_euid,
+ _opaque("order-test-secondary"),
+ ],
"atlas_trf_euid": _opaque("trf"),
"atlas_test_euid": _opaque("test-primary"),
"atlas_test_euids": [_opaque("test-secondary")],
diff --git a/tests/test_route_coverage_gaps_api.py b/tests/test_route_coverage_gaps_api.py
index f42f170..4822d5b 100644
--- a/tests/test_route_coverage_gaps_api.py
+++ b/tests/test_route_coverage_gaps_api.py
@@ -113,9 +113,7 @@ def test_object_creation_creates_all_sequencing_run_platform_prefixes(
assert created["euid"].startswith(f"{domain_code}-{prefix}-")
-def test_object_creation_plate_creates_96_linked_wells(
- client: TestClient, bdb
-) -> None:
+def test_object_creation_plate_creates_96_linked_wells(client: TestClient, bdb) -> None:
created = _create_instance_via_object_creation(
client,
category="container",
@@ -140,8 +138,7 @@ def test_object_creation_plate_creates_96_linked_wells(
)
wells = [lineage.child_instance for lineage in lineages]
positions = {
- ((well.json_addl or {}).get("cont_address") or {}).get("name")
- for well in wells
+ ((well.json_addl or {}).get("cont_address") or {}).get("name") for well in wells
}
assert len(wells) == 96
assert {well.type for well in wells} == {"well"}
@@ -288,8 +285,16 @@ def test_containers_content_link_layout_and_delete(client: TestClient, bdb) -> N
)
assert link_resp.status_code == 200, link_resp.text
lineage_cls = bdb.Base.classes.generic_instance_lineage
- parent = bdb.session.query(bdb.Base.classes.generic_instance).filter_by(euid=container_euid).first()
- child = bdb.session.query(bdb.Base.classes.generic_instance).filter_by(euid=content_euid).first()
+ parent = (
+ bdb.session.query(bdb.Base.classes.generic_instance)
+ .filter_by(euid=container_euid)
+ .first()
+ )
+ child = (
+ bdb.session.query(bdb.Base.classes.generic_instance)
+ .filter_by(euid=content_euid)
+ .first()
+ )
lineage = (
bdb.session.query(lineage_cls)
.filter(
diff --git a/tests/test_route_coverage_gaps_gui.py b/tests/test_route_coverage_gaps_gui.py
index 7829a83..f9dba10 100644
--- a/tests/test_route_coverage_gaps_gui.py
+++ b/tests/test_route_coverage_gaps_gui.py
@@ -41,9 +41,21 @@ def _warm_session(client: TestClient) -> None:
assert resp.status_code == 200
-def _get_any_template_euid(bdb) -> str:
+def _get_bloom_creatable_template_euid(bdb) -> str:
GT = bdb.Base.classes.generic_template
- row = bdb.session.query(GT).filter(GT.is_deleted.is_(False)).first()
+ row = (
+ bdb.session.query(GT)
+ .filter(
+ GT.domain_code == "Z",
+ GT.category == "container",
+ GT.type == "tube",
+ GT.subtype == "tube-generic-10ml",
+ GT.version == "1.0",
+ GT.instance_prefix == "BCT",
+ GT.is_deleted.is_(False),
+ )
+ .one_or_none()
+ )
assert row is not None
return row.euid
@@ -216,7 +228,7 @@ def test_user_audit_logs_renders(client: TestClient) -> None:
def test_create_from_template_executes_handler(client: TestClient, bdb) -> None:
_warm_session(client)
- template_euid = _get_any_template_euid(bdb)
+ template_euid = _get_bloom_creatable_template_euid(bdb)
resp = client.get(
"/create_from_template", params={"euid": template_euid}, follow_redirects=False
)
@@ -232,7 +244,7 @@ def test_file_set_urls_and_admin_template_routes_are_removed(
resp = client.get("/file_set_urls", params={"fs_euid": "BFL-NOT-REAL"})
assert resp.status_code == 404
- template_euid = _get_any_template_euid(bdb)
+ template_euid = _get_bloom_creatable_template_euid(bdb)
# Admin template editor was retired.
resp = client.get("/admin_template", params={"euid": template_euid})
assert resp.status_code == 404
diff --git a/tests/test_sequencing_run_contract.py b/tests/test_sequencing_run_contract.py
index d689d84..0474c54 100644
--- a/tests/test_sequencing_run_contract.py
+++ b/tests/test_sequencing_run_contract.py
@@ -10,7 +10,6 @@
from bloom_lims.schemas.beta_lab import BetaRunCreateRequest
-
PROJECT_ROOT = Path(__file__).resolve().parents[1]
diff --git a/tests/test_template_instantiation_recursion.py b/tests/test_template_instantiation_recursion.py
index 752c999..19554a5 100644
--- a/tests/test_template_instantiation_recursion.py
+++ b/tests/test_template_instantiation_recursion.py
@@ -54,7 +54,9 @@ def _fake_bloom_obj(templates):
def get_by_euid(euid):
return templates_by_euid.get(euid) or created["instances"].get(euid)
- def query_template_by_component_v2(category=None, type=None, subtype=None, version=None):
+ def query_template_by_component_v2(
+ category=None, type=None, subtype=None, version=None
+ ):
return [
template
for template in templates
@@ -133,9 +135,7 @@ def test_create_instances_recurses_nested_instantiation_layouts():
assert len(parent_rows) == 1
assert len(child_rows) == 2
assert {child.type for child in child_rows} == {"well", "material"}
- lineages = [
- row for row in obj.session.added if isinstance(row, _FakeLineage)
- ]
+ lineages = [row for row in obj.session.added if isinstance(row, _FakeLineage)]
assert [row.relationship_type for row in lineages] == [
"HOLDS_MATERIAL",
"contains",
@@ -151,9 +151,7 @@ def test_create_instances_rejects_template_cycles():
layouts=[
{
"relationship_type": "contains",
- "child_templates": [
- {"template_code": "container/plate/cycle/1.0/"}
- ],
+ "child_templates": [{"template_code": "container/plate/cycle/1.0/"}],
}
],
)
@@ -173,9 +171,7 @@ def test_create_instances_enforces_object_count_limit():
layouts=[
{
"relationship_type": "contains",
- "child_templates": [
- {"template_code": "container/well/child/1.0/"}
- ],
+ "child_templates": [{"template_code": "container/well/child/1.0/"}],
}
],
)
diff --git a/uv.lock b/uv.lock
index f1b5a96..d116384 100644
--- a/uv.lock
+++ b/uv.lock
@@ -160,6 +160,7 @@ dependencies = [
{ name = "daylily-auth-cognito" },
{ name = "daylily-carrier-tracking" },
{ name = "daylily-tapdb" },
+ { name = "defusedxml" },
{ name = "djlint" },
{ name = "fastapi" },
{ name = "httpx" },
@@ -200,7 +201,8 @@ requires-dist = [
{ name = "cli-core-yo", specifier = "==2.1.1" },
{ name = "daylily-auth-cognito", specifier = "==2.1.5" },
{ name = "daylily-carrier-tracking", specifier = "==0.5.1" },
- { name = "daylily-tapdb", git = "https://github.com/Daylily-Informatics/daylily-tapdb.git?rev=9.0.9" },
+ { name = "daylily-tapdb", git = "https://github.com/Daylily-Informatics/daylily-tapdb.git?rev=9.0.10" },
+ { name = "defusedxml", specifier = ">=0.7.1" },
{ name = "djlint" },
{ name = "fastapi", specifier = ">=0.110.0" },
{ name = "httpx", specifier = ">=0.27.2" },
@@ -704,8 +706,8 @@ wheels = [
[[package]]
name = "daylily-tapdb"
-version = "9.0.9"
-source = { git = "https://github.com/Daylily-Informatics/daylily-tapdb.git?rev=9.0.9#52d5f498dc4751b7e42d346bee2811a14080e5a5" }
+version = "9.0.10"
+source = { git = "https://github.com/Daylily-Informatics/daylily-tapdb.git?rev=9.0.10#12351b832276d35228527c3c9596e5d60e7c7824" }
dependencies = [
{ name = "cli-core-yo" },
{ name = "jsonschema" },
@@ -728,6 +730,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/05/7f/798705f5296a58ca505d600456748d1be48078eac8a7050d8a98bc9edb89/decorator-5.3.1-py3-none-any.whl", hash = "sha256:f47fe6fdbd2edd623ecfe36875d37aba411624e2670dd395dddae1358689bb3c", size = 10365, upload-time = "2026-05-18T06:03:26.517Z" },
]
+[[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 = "distlib"
version = "0.4.0"