Add single-command installation: install.sh, Makefile, frontend build hook
- hatch_build.py: custom hatchling build hook that compiles the React frontend (npm ci + build) when frontend/dist is missing or stale, so 'uv tool install git+https://gitea.zephyre.one/Pakobbix/nvcurve.git' works as a single command - install.sh: curl|bash installer (checks prerequisites, auto-installs uv, clones and installs) - Makefile: dev targets (frontend, install, dev, test, clean) - README/docs: document the one-liner, clone, and direct-git installs
This commit is contained in:
1 parent
d810c44478
commit
a8462e696c
7 files changed
+287
-30
No files matched your search
@@ -0,0 +1,29 @@
|
|||||||
|
# NVCurve — developer convenience targets.
|
||||||
|
#
|
||||||
|
# End users don't need make: run ./install.sh (see README "Installation").
|
||||||
|
|
||||||
|
UV ?= uv
|
||||||
|
NPM ?= npm
|
||||||
|
|
||||||
|
.PHONY: help frontend frontend-dev install dev test clean
|
||||||
|
|
||||||
|
help: ## Show available targets
|
||||||
|
@grep -E '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}'
|
||||||
|
|
||||||
|
frontend: ## Build the React frontend into frontend/dist
|
||||||
|
cd frontend && $(NPM) ci && $(NPM) run build
|
||||||
|
|
||||||
|
frontend-dev: ## Run the Vite dev server (hot reload)
|
||||||
|
cd frontend && $(NPM) run dev
|
||||||
|
|
||||||
|
install: ## Install nvcurve as a uv tool (builds frontend if missing/stale)
|
||||||
|
$(UV) tool install --force .
|
||||||
|
|
||||||
|
dev: ## Create/refresh the dev environment (uv sync)
|
||||||
|
$(UV) sync
|
||||||
|
|
||||||
|
test: ## Run the test suite
|
||||||
|
$(UV) run python tests/test_security.py
|
||||||
|
|
||||||
|
clean: ## Remove build artifacts
|
||||||
|
rm -rf frontend/dist frontend/node_modules
|
||||||
@@ -37,20 +37,28 @@ NVCurve brings MSI Afterburner-style per-point voltage-frequency curve control t
|
|||||||
- **[uv](https://docs.astral.sh/uv/)** — Python package manager
|
- **[uv](https://docs.astral.sh/uv/)** — Python package manager
|
||||||
- **Root/sudo access** (required for GPU hardware interactions)
|
- **Root/sudo access** (required for GPU hardware interactions)
|
||||||
|
|
||||||
## Installation from Source
|
## Installation
|
||||||
|
|
||||||
|
### One-liner
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone <this-repo-url>.git
|
curl -fsSL https://gitea.zephyre.one/Pakobbix/nvcurve/raw/branch/main/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
The script checks prerequisites (installs `uv` if missing), clones the repo, and installs NVCurve — the React frontend is compiled automatically during the build.
|
||||||
|
|
||||||
|
### From a clone
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://gitea.zephyre.one/Pakobbix/nvcurve.git
|
||||||
cd nvcurve
|
cd nvcurve
|
||||||
|
./install.sh
|
||||||
|
```
|
||||||
|
|
||||||
# Build the React frontend
|
### Direct from git (no clone, no script)
|
||||||
cd frontend
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
# Install the Python package (includes bundled frontend)
|
```bash
|
||||||
uv tool install .
|
uv tool install "git+https://gitea.zephyre.one/Pakobbix/nvcurve.git"
|
||||||
```
|
```
|
||||||
|
|
||||||
After installation, verify hardware compatibility:
|
After installation, verify hardware compatibility:
|
||||||
@@ -200,10 +208,11 @@ The GPU key can be a UUID, `pci:XXXX`, or `idx:N` fallback. Find your GPU key wi
|
|||||||
```bash
|
```bash
|
||||||
cd nvcurve
|
cd nvcurve
|
||||||
git pull
|
git pull
|
||||||
cd frontend && npm run build && cd ..
|
uv tool install --force .
|
||||||
uv tool install .
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The frontend is rebuilt automatically if it is missing or older than the frontend sources. If you modified frontend code locally, run `make frontend` first (or `rm -rf frontend/dist`).
|
||||||
|
|
||||||
If running as a systemd service:
|
If running as a systemd service:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
+28
-19
@@ -29,37 +29,45 @@ sudo pacman -S uv
|
|||||||
pip install uv
|
pip install uv
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation from Source
|
## Installation
|
||||||
|
|
||||||
### Step 1: Clone the Repository
|
### Option 1: One-liner (recommended)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone <this-repo-url>.git
|
curl -fsSL https://gitea.zephyre.one/Pakobbix/nvcurve/raw/branch/main/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
The script checks prerequisites (installs `uv` if missing), clones the repository, and installs NVCurve. The React frontend is compiled automatically during the build by a hatchling build hook (`hatch_build.py`).
|
||||||
|
|
||||||
|
### Option 2: From a clone
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://gitea.zephyre.one/Pakobbix/nvcurve.git
|
||||||
cd nvcurve
|
cd nvcurve
|
||||||
|
./install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 2: Build the Frontend
|
Equivalent manual steps (what the script does):
|
||||||
|
|
||||||
The frontend is a React + TypeScript + Vite application in the `frontend/` directory.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd frontend
|
git clone https://gitea.zephyre.one/Pakobbix/nvcurve.git
|
||||||
npm install
|
cd nvcurve
|
||||||
npm run build
|
uv tool install . # frontend is built automatically if missing/stale
|
||||||
cd ..
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This produces a `dist/` directory with the compiled static assets. The hatch build system bundles `frontend/dist` into the Python package.
|
### Option 3: Direct from git (no clone, no script)
|
||||||
|
|
||||||
### Step 3: Install the Python Package
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uv tool install .
|
uv tool install "git+https://gitea.zephyre.one/Pakobbix/nvcurve.git"
|
||||||
```
|
```
|
||||||
|
|
||||||
This installs `nvcurve` as a system-wide tool with the bundled frontend.
|
To install a specific branch:
|
||||||
|
|
||||||
### Step 4: Verify
|
```bash
|
||||||
|
uv tool install "git+https://gitea.zephyre.one/Pakobbix/nvcurve.git@<branch>"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Verify
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nvcurve setup
|
nvcurve setup
|
||||||
@@ -94,10 +102,11 @@ nvcurve serve start
|
|||||||
```bash
|
```bash
|
||||||
cd nvcurve
|
cd nvcurve
|
||||||
git pull
|
git pull
|
||||||
cd frontend && npm run build && cd ..
|
uv tool install --force .
|
||||||
uv tool install .
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The frontend is rebuilt automatically if it is missing or older than the frontend sources. If you modified frontend code locally, run `make frontend` first (or `rm -rf frontend/dist`).
|
||||||
|
|
||||||
If running as a systemd service:
|
If running as a systemd service:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -116,7 +125,7 @@ source ~/.local/bin/env # or wherever uv installed
|
|||||||
|
|
||||||
### Frontend not loading in the web UI
|
### Frontend not loading in the web UI
|
||||||
|
|
||||||
Verify that `frontend/dist` exists and contains built assets. If the directory is empty or missing, rebuild with `npm run build` and reinstall with `uv tool install .`.
|
Verify that the installed package contains the frontend. If `frontend/dist` is empty or missing, rebuild with `make frontend` (or `cd frontend && npm ci && npm run build`) and reinstall with `uv tool install --force .`.
|
||||||
|
|
||||||
### NvAPI functions not found
|
### NvAPI functions not found
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
"""Custom hatchling build hook: build the React frontend if it is missing or stale.
|
||||||
|
|
||||||
|
This makes NVCurve installable with a single command, e.g.::
|
||||||
|
|
||||||
|
uv tool install "git+https://gitea.zephyre.one/Pakobbix/nvcurve.git"
|
||||||
|
|
||||||
|
The hook runs inside the isolated build environment right before the wheel
|
||||||
|
(or sdist) is assembled. If ``frontend/dist`` does not exist yet — or is older
|
||||||
|
than the frontend sources — it compiles the frontend using the host's ``npm``
|
||||||
|
(PATH is inherited from the environment).
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
||||||
|
|
||||||
|
# Frontend inputs that must be newer than dist/index.html to trigger a rebuild.
|
||||||
|
_FRONTEND_INPUTS = ("src", "index.html", "vite.config.ts", "package.json", "tsconfig.json")
|
||||||
|
|
||||||
|
|
||||||
|
class FrontendBuildHook(BuildHookInterface):
|
||||||
|
"""Build ``frontend/dist`` with npm when it is missing or stale."""
|
||||||
|
|
||||||
|
PLUGIN_NAME = "custom"
|
||||||
|
|
||||||
|
def initialize(self, version: str, build_data: dict) -> None:
|
||||||
|
frontend = os.path.join(self.root, "frontend")
|
||||||
|
dist_index = os.path.join(frontend, "dist", "index.html")
|
||||||
|
|
||||||
|
if not self._needs_build(frontend, dist_index):
|
||||||
|
return
|
||||||
|
|
||||||
|
npm = shutil.which("npm")
|
||||||
|
if npm is None:
|
||||||
|
raise RuntimeError(
|
||||||
|
"npm not found on PATH. Node.js 18+ and npm are required to build "
|
||||||
|
"the NVCurve frontend. Install them and retry, or use install.sh "
|
||||||
|
"which checks prerequisites for you."
|
||||||
|
)
|
||||||
|
|
||||||
|
print(
|
||||||
|
"[nvcurve] frontend/dist missing or stale — building frontend with npm ...",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
subprocess.run([npm, "ci", "--no-audit", "--no-fund"], cwd=frontend, check=True)
|
||||||
|
subprocess.run([npm, "run", "build"], cwd=frontend, check=True)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _needs_build(frontend: str, dist_index: str) -> bool:
|
||||||
|
if not os.path.isfile(dist_index):
|
||||||
|
return True
|
||||||
|
dist_mtime = os.path.getmtime(dist_index)
|
||||||
|
for name in _FRONTEND_INPUTS:
|
||||||
|
path = os.path.join(frontend, name)
|
||||||
|
if os.path.isfile(path):
|
||||||
|
if os.path.getmtime(path) > dist_mtime:
|
||||||
|
return True
|
||||||
|
elif os.path.isdir(path):
|
||||||
|
for root, _dirs, files in os.walk(path):
|
||||||
|
for file in files:
|
||||||
|
if os.path.getmtime(os.path.join(root, file)) > dist_mtime:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
Executable
+62
@@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# NVCurve single-command installer.
|
||||||
|
#
|
||||||
|
# curl -fsSL https://gitea.zephyre.one/Pakobbix/nvcurve/raw/branch/main/install.sh | bash
|
||||||
|
#
|
||||||
|
# or from a local clone:
|
||||||
|
#
|
||||||
|
# git clone https://gitea.zephyre.one/Pakobbix/nvcurve.git && cd nvcurve && ./install.sh
|
||||||
|
#
|
||||||
|
# The React frontend is compiled automatically during the Python build
|
||||||
|
# (see hatch_build.py), so Node.js 18+ and npm must be available.
|
||||||
|
#
|
||||||
|
# Environment:
|
||||||
|
# NVCURVE_BRANCH branch to install (default: main)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_URL="https://gitea.zephyre.one/Pakobbix/nvcurve.git"
|
||||||
|
BRANCH="${NVCURVE_BRANCH:-main}"
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo "error: $*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- prerequisites -----------------------------------------------------------
|
||||||
|
command -v git >/dev/null 2>&1 \
|
||||||
|
|| fail "git is required. Install it first."
|
||||||
|
command -v node >/dev/null 2>&1 \
|
||||||
|
|| fail "Node.js 18+ is required (e.g. 'sudo pacman -S nodejs npm' or 'sudo apt install nodejs npm')."
|
||||||
|
command -v npm >/dev/null 2>&1 \
|
||||||
|
|| fail "npm is required (usually installed together with Node.js)."
|
||||||
|
|
||||||
|
if ! command -v uv >/dev/null 2>&1; then
|
||||||
|
echo "uv not found — installing it from https://astral.sh/uv ..."
|
||||||
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
|
export PATH="$HOME/.local/bin:$PATH"
|
||||||
|
command -v uv >/dev/null 2>&1 \
|
||||||
|
|| fail "uv installation failed. Install uv manually: https://docs.astral.sh/uv/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- locate the source tree ---------------------------------------------------
|
||||||
|
if [ -f pyproject.toml ] && [ -d frontend ]; then
|
||||||
|
src="$(pwd)"
|
||||||
|
echo "Installing from current directory: $src"
|
||||||
|
else
|
||||||
|
tmp="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$tmp"' EXIT
|
||||||
|
echo "Cloning $REPO_URL (branch: $BRANCH) ..."
|
||||||
|
git clone --quiet --depth 1 --branch "$BRANCH" "$REPO_URL" "$tmp/nvcurve"
|
||||||
|
src="$tmp/nvcurve"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- install -------------------------------------------------------------------
|
||||||
|
# The frontend is built automatically by the build hook (hatch_build.py).
|
||||||
|
uv tool install --force "$src"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "NVCurve installed."
|
||||||
|
echo " Verify your GPU: nvcurve setup"
|
||||||
|
echo " Start the web UI: nvcurve"
|
||||||
@@ -19,9 +19,20 @@ dependencies = [
|
|||||||
[project.scripts]
|
[project.scripts]
|
||||||
nvcurve = "nvcurve.cli:main"
|
nvcurve = "nvcurve.cli:main"
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"hatchling", # enables local `hatch build` and resolves hatch_build.py imports
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.hatch.build.hooks.custom]
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel]
|
[tool.hatch.build.targets.wheel]
|
||||||
packages = ["nvcurve"]
|
packages = ["nvcurve"]
|
||||||
|
|
||||||
|
# The custom build hook (hatch_build.py) compiles the React frontend when
|
||||||
|
# frontend/dist is missing or stale, so `uv tool install git+<repo-url>` works
|
||||||
|
# as a single command. It runs for both wheel and sdist builds.
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel.force-include]
|
[tool.hatch.build.targets.wheel.force-include]
|
||||||
"frontend/dist" = "nvcurve/frontend/dist"
|
"frontend/dist" = "nvcurve/frontend/dist"
|
||||||
|
|
||||||
|
|||||||
@@ -154,6 +154,22 @@ 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" },
|
{ 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 = "hatchling"
|
||||||
|
version = "1.32.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "packaging" },
|
||||||
|
{ name = "pathspec" },
|
||||||
|
{ name = "pluggy" },
|
||||||
|
{ name = "tomlkit" },
|
||||||
|
{ name = "trove-classifiers" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/69/08/33331757185504aae48b8d9bd78cec03a76e3aecfb52e549d05a2347c0dd/hatchling-1.32.0.tar.gz", hash = "sha256:0bdbde4a52b06c37e3eca395f85a762bf0ef06fe374fd8ae429dc6be10230f5f", size = 57783, upload-time = "2026-08-11T05:03:44.114Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/84/1798b6d85ecde0e31546004efd25c5de1b1f49250644a60cce460e12593a/hatchling-1.32.0-py3-none-any.whl", hash = "sha256:0e17c9c3b9aa7c625acc8d0f5b622f107d5049af9ecf5ada4de1aada5be7cdbc", size = 78435, upload-time = "2026-08-11T05:03:42.644Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httpcore"
|
name = "httpcore"
|
||||||
version = "1.0.9"
|
version = "1.0.9"
|
||||||
@@ -233,6 +249,11 @@ dependencies = [
|
|||||||
{ name = "uvicorn", extra = ["standard"] },
|
{ name = "uvicorn", extra = ["standard"] },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[package.dev-dependencies]
|
||||||
|
dev = [
|
||||||
|
{ name = "hatchling" },
|
||||||
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "bcrypt", specifier = ">=4.0" },
|
{ name = "bcrypt", specifier = ">=4.0" },
|
||||||
@@ -243,6 +264,9 @@ requires-dist = [
|
|||||||
{ name = "uvicorn", extras = ["standard"], specifier = ">=0.30" },
|
{ name = "uvicorn", extras = ["standard"], specifier = ">=0.30" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[package.metadata.requires-dev]
|
||||||
|
dev = [{ name = "hatchling" }]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nvidia-ml-py"
|
name = "nvidia-ml-py"
|
||||||
version = "13.590.48"
|
version = "13.590.48"
|
||||||
@@ -252,6 +276,33 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/fd/72/fb2af0d259a651affdce65fd6a495f0e07a685a0136baf585c5065204ee7/nvidia_ml_py-13.590.48-py3-none-any.whl", hash = "sha256:fd43d30ee9cd0b7940f5f9f9220b68d42722975e3992b6c21d14144c48760e43", size = 50680, upload-time = "2026-01-22T01:14:55.281Z" },
|
{ url = "https://files.pythonhosted.org/packages/fd/72/fb2af0d259a651affdce65fd6a495f0e07a685a0136baf585c5065204ee7/nvidia_ml_py-13.590.48-py3-none-any.whl", hash = "sha256:fd43d30ee9cd0b7940f5f9f9220b68d42722975e3992b6c21d14144c48760e43", size = 50680, upload-time = "2026-01-22T01:14:55.281Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "packaging"
|
||||||
|
version = "26.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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 = "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]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.12.5"
|
version = "2.12.5"
|
||||||
@@ -406,6 +457,24 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" },
|
{ url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tomlkit"
|
||||||
|
version = "0.15.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/94/96/e07752635b98536177fa1f37671c8f3cdde2e724c6bcf6034b2cfb571565/tomlkit-0.15.1.tar.gz", hash = "sha256:e25bbf38843005246210a12982776f27f99cb9be67160e14434d0c0d21ee1e97", size = 180129, upload-time = "2026-07-17T01:48:04.562Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/13/bc/8c13eb66537dce1d2bd3a57132902f38d0e7f5bb46fa9f4daed9fe9d76ee/tomlkit-0.15.1-py3-none-any.whl", hash = "sha256:177a05aece5a8ca5266fd3c448abb47b8d352f09d477d3ca8332db4d89b24304", size = 49449, upload-time = "2026-07-17T01:48:05.728Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "trove-classifiers"
|
||||||
|
version = "2026.6.1.19"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/c2/e3/7ca82ee24c82d344584abd5b8637b3bd056f2900226e8d82fc22f1184b92/trove_classifiers-2026.6.1.19.tar.gz", hash = "sha256:c5132b4b61a829d11cfbd2d72e97f20a45ed6edb95e45c5efdeb5e00836b2745", size = 17059, upload-time = "2026-06-01T19:41:34.649Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/a4/81502f486f01db95bc8320646a8a12511f5e556cb63d5e224d91816605c4/trove_classifiers-2026.6.1.19-py3-none-any.whl", hash = "sha256:ab4c4ec93cc4a4e7815fa759906e05e6bb3f2fbd92ea0f897288c6a43efd15b3", size = 14211, upload-time = "2026-06-01T19:41:33.434Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typing-extensions"
|
name = "typing-extensions"
|
||||||
version = "4.15.0"
|
version = "4.15.0"
|
||||||
|
|||||||
Reference in new issue
Block a user