Merge remote-tracking branch 'origin/sprint-31/ci'
This commit is contained in:
@@ -14,10 +14,12 @@ REMOTE_REF="origin/$BRANCH"
|
||||
if git rev-parse --verify "$REMOTE_REF" >/dev/null 2>&1; then
|
||||
CLIENT_CHANGED=$(git diff --name-only "$REMOTE_REF"..HEAD -- client/ 2>/dev/null | wc -l)
|
||||
SERVER_CHANGED=$(git diff --name-only "$REMOTE_REF"..HEAD -- server/ 2>/dev/null | wc -l)
|
||||
TOOLING_CHANGED=$(git diff --name-only "$REMOTE_REF"..HEAD -- tooling/ pyproject.toml 2>/dev/null | wc -l)
|
||||
else
|
||||
# New branch or no remote ref — fall through to directory checks
|
||||
CLIENT_CHANGED=1
|
||||
SERVER_CHANGED=1
|
||||
TOOLING_CHANGED=1
|
||||
fi
|
||||
|
||||
# --- GDScript parse check (headless Godot) ---
|
||||
@@ -97,6 +99,20 @@ else
|
||||
echo "pre-push: WARNING — cargo not found or server/ missing, skipping Rust lint"
|
||||
fi
|
||||
|
||||
# --- Python lint (ruff) ---
|
||||
if [ "$TOOLING_CHANGED" -eq 0 ]; then
|
||||
echo "pre-push: no tooling/ changes — skipping Python lint"
|
||||
elif command -v ruff >/dev/null 2>&1 && [ -d "$REPO_ROOT/tooling" ]; then
|
||||
echo "pre-push: checking Python (ruff)..."
|
||||
if ! (cd "$REPO_ROOT" && ruff check tooling/ 2>&1); then
|
||||
ERRORS=$((ERRORS + 1))
|
||||
else
|
||||
echo "pre-push: ruff — OK"
|
||||
fi
|
||||
else
|
||||
echo "pre-push: skipping Python lint (ruff not found — install with: pip install 'ruff>=0.9')"
|
||||
fi
|
||||
|
||||
if [ "$ERRORS" -gt 0 ]; then
|
||||
echo ""
|
||||
echo "pre-push: $ERRORS check(s) failed. Push aborted."
|
||||
|
||||
@@ -6,6 +6,17 @@ Format based on [Keep a Changelog](https://keepachangelog.com/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- Shared Python module `tooling/db/common.py` — centralizes DB path resolution, config loading, and WAL-mode connection setup (#777)
|
||||
- `ensure_venv()` auto-activation for Python tooling scripts with third-party dependencies (#777)
|
||||
- `make lint-python` target running ruff on `tooling/` (#777)
|
||||
- `make setup-venv` target for Python venv creation (#777)
|
||||
- Python/ruff lint block in pre-push hook (#777)
|
||||
|
||||
### Fixed
|
||||
- Pre-existing `NameError` in `decisions_sync.py` (missing `import os`) resolved via shared module extraction (#777)
|
||||
- Unused imports removed from `assign-astro-ids.py`, `generate-star-map.py`, `test_quaternius_raw.py` (#777)
|
||||
|
||||
## [v0.1.30] — 2026-04-05
|
||||
|
||||
### Added
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
GODOT := $(shell command -v godot4 2>/dev/null || command -v godot 2>/dev/null)
|
||||
|
||||
.PHONY: help setup build check-protocol client server game stop test lint ci ci-client ci-server clean \
|
||||
.PHONY: help setup build check-protocol client server game stop test lint lint-python setup-venv ci ci-client ci-server clean \
|
||||
decisions-sync decisions-coverage decisions-active decisions-orphan \
|
||||
db-backup db-install validate-content check-fact-ids setup-hooks \
|
||||
audit atlas-verify \
|
||||
@@ -22,7 +22,8 @@ GODOT_VERSION ?= 4.6
|
||||
help:
|
||||
@echo "The Settled Reach — Development Commands"
|
||||
@echo ""
|
||||
@echo " make setup Install dev dependencies (Rust, Godot, tooling)"
|
||||
@echo " make setup Install dev dependencies (Rust, Godot, tooling, venv)"
|
||||
@echo " make setup-venv Create .venv and install Python tooling deps"
|
||||
@echo " make build Build client and server"
|
||||
@echo " make game Build and run the full game (server + client)"
|
||||
@echo " make stop Stop any running server instance"
|
||||
@@ -33,7 +34,8 @@ help:
|
||||
@echo " make test-ipc-protocol Layer 2: mock IPC protocol tests"
|
||||
@echo " make test-ipc-integration Layer 3: real subprocess round-trip"
|
||||
@echo " make test-ipc-benchmark IPC latency benchmark (blocked: #555/#556)"
|
||||
@echo " make lint Run all linters"
|
||||
@echo " make lint Run all linters (server, client, python)"
|
||||
@echo " make lint-python Run ruff on tooling/"
|
||||
@echo " make ci Run full CI pipeline locally"
|
||||
@echo " make ci-client Run client CI checks"
|
||||
@echo " make ci-server Run server CI checks"
|
||||
@@ -82,7 +84,7 @@ help:
|
||||
|
||||
# --- Setup ---
|
||||
|
||||
setup: setup-rust setup-godot setup-tooling setup-hooks decisions-sync
|
||||
setup: setup-rust setup-godot setup-tooling setup-venv setup-hooks decisions-sync
|
||||
@echo "Dev environment ready."
|
||||
|
||||
setup-rust:
|
||||
@@ -103,6 +105,11 @@ setup-hooks:
|
||||
@git config core.hooksPath .config/hooks
|
||||
@echo "Git hooks path set to .config/hooks"
|
||||
|
||||
setup-venv:
|
||||
@python3 -m venv .venv
|
||||
@.venv/bin/pip install -e ".[dev]" --quiet
|
||||
@echo "Venv ready at .venv — activate with: source .venv/bin/activate"
|
||||
|
||||
# --- Build ---
|
||||
|
||||
check-protocol:
|
||||
@@ -222,7 +229,10 @@ clean-imports:
|
||||
|
||||
# --- Lint ---
|
||||
|
||||
lint: lint-server lint-client
|
||||
lint: lint-server lint-client lint-python
|
||||
|
||||
lint-python:
|
||||
ruff check tooling/
|
||||
|
||||
lint-server:
|
||||
cd server && cargo clippy -- -D warnings
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
[project]
|
||||
name = "settled-reach-tooling"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"PyYAML",
|
||||
"jsonschema",
|
||||
"numpy",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
# ruff 0.15.9 — checked clean against NVD + OSV, no CVEs on record (2026-04-05)
|
||||
"ruff==0.15.9",
|
||||
]
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
target-version = "py311"
|
||||
|
||||
[tool.ruff.lint]
|
||||
# E9xx: Runtime syntax/encoding errors
|
||||
# F401: Unused imports
|
||||
# F811: Redefinition of unused name
|
||||
# F821: Undefined name (catches missing imports like bare `os`)
|
||||
select = ["E9", "F401", "F811", "F821"]
|
||||
@@ -17,7 +17,6 @@ Also writes spectral class from the real catalog into each node.
|
||||
"""
|
||||
|
||||
import json
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
|
||||
STAR_MAP_PATH = Path(__file__).parent.parent / "docs/design/star-map.json"
|
||||
|
||||
@@ -8,12 +8,18 @@ Usage:
|
||||
python3 audio_batch.py manifest.json [--dry-run] [--only ID,ID,...] [--skip-existing]
|
||||
"""
|
||||
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from common import ensure_venv # noqa: E402
|
||||
|
||||
ensure_venv()
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import wave
|
||||
|
||||
import numpy as np
|
||||
|
||||
@@ -10,14 +10,22 @@ Usage:
|
||||
python3 audio_connector.py health
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from common import ensure_venv # noqa: E402
|
||||
|
||||
ensure_venv()
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
import shutil
|
||||
|
||||
CONFIG_PATH = os.path.join(os.path.dirname(__file__), "config.json")
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Shared utilities for Settled Reach DB tooling scripts.
|
||||
|
||||
Provides the standard DB path resolution, config loading, and connection
|
||||
helpers used across ticket, sprint, sqlite_connector, and decisions_sync.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Paths
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
CONFIG_PATH = SCRIPT_DIR / "config.json"
|
||||
WORKTREE_ROOT = (SCRIPT_DIR / ".." / "..").resolve()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def resolve_db_path() -> Path:
|
||||
"""Return the ticket database path.
|
||||
|
||||
Prefers the SR_DB_PATH environment variable (absolute path).
|
||||
Falls back to <worktree-parent>/settledreach.db — the shared DB location
|
||||
used when working directly in the main repo checkout.
|
||||
"""
|
||||
if os.environ.get("SR_DB_PATH"):
|
||||
return Path(os.environ["SR_DB_PATH"]).resolve()
|
||||
return (WORKTREE_ROOT / ".." / "settledreach.db").resolve()
|
||||
|
||||
|
||||
def load_config() -> dict:
|
||||
"""Load tooling/db/config.json and inject the resolved DB path."""
|
||||
with open(CONFIG_PATH) as f:
|
||||
cfg = json.load(f)
|
||||
cfg["sqlite_db_resolved"] = str(resolve_db_path())
|
||||
return cfg
|
||||
|
||||
|
||||
def get_connection(cfg: dict) -> sqlite3.Connection:
|
||||
"""Return a WAL-mode SQLite connection with foreign keys enabled."""
|
||||
conn = sqlite3.connect(cfg["sqlite_db_resolved"])
|
||||
conn.execute("PRAGMA journal_mode=WAL;")
|
||||
conn.execute("PRAGMA foreign_keys=ON;")
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
|
||||
def ensure_venv() -> None:
|
||||
"""Re-exec into the project .venv Python if not already running there.
|
||||
|
||||
Call this at the top of any script that uses third-party packages,
|
||||
before those imports. Pure-stdlib scripts (ticket, sprint,
|
||||
sqlite_connector, decisions_sync) do not need it.
|
||||
|
||||
Usage::
|
||||
|
||||
from common import ensure_venv
|
||||
ensure_venv()
|
||||
import numpy as np # third-party import follows
|
||||
"""
|
||||
venv_python = WORKTREE_ROOT / ".venv" / "bin" / "python"
|
||||
|
||||
# Already running inside the venv — nothing to do.
|
||||
if Path(sys.executable).resolve() == venv_python.resolve():
|
||||
return
|
||||
|
||||
# .venv not set up yet — fail with a helpful message.
|
||||
if not venv_python.exists():
|
||||
print(
|
||||
"error: .venv not found — run `make setup-venv` first.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
# Re-exec into the venv Python, preserving all arguments.
|
||||
os.execv(str(venv_python), [str(venv_python)] + sys.argv)
|
||||
@@ -17,38 +17,16 @@ import sqlite3
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from common import CONFIG_PATH, WORKTREE_ROOT, get_connection, load_config # noqa: E402
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Paths
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
CONFIG_PATH = SCRIPT_DIR / "config.json"
|
||||
WORKTREE_ROOT = (SCRIPT_DIR / ".." / "..").resolve()
|
||||
SCHEMA_PATH = WORKTREE_ROOT / "db" / "schema.sql"
|
||||
DECISIONS_DIR = WORKTREE_ROOT / "decisions"
|
||||
# Database path: SR_DB_PATH env var (absolute), or fallback to parent directory heuristic.
|
||||
DB_PATH = Path(os.environ["SR_DB_PATH"]).resolve() if os.environ.get("SR_DB_PATH") else (WORKTREE_ROOT / ".." / "settledreach.db").resolve()
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Config / DB (same pattern as sqlite_connector.py)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def load_config():
|
||||
"""Load config.json and resolve the SQLite database path."""
|
||||
with open(CONFIG_PATH, "r") as f:
|
||||
cfg = json.load(f)
|
||||
cfg["sqlite_db_resolved"] = str(DB_PATH)
|
||||
return cfg
|
||||
|
||||
|
||||
def get_connection(cfg):
|
||||
"""Return an sqlite3 connection with WAL mode and foreign keys enabled."""
|
||||
conn = sqlite3.connect(cfg["sqlite_db_resolved"])
|
||||
conn.execute("PRAGMA journal_mode=WAL;")
|
||||
conn.execute("PRAGMA foreign_keys=ON;")
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -10,10 +10,18 @@ Usage:
|
||||
python3 image_connector.py generate "prompt" [--output file.png] [--aspect 1:1] [--size 1K] [--input image.png]
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from common import ensure_venv # noqa: E402
|
||||
|
||||
ensure_venv()
|
||||
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
|
||||
@@ -14,14 +14,20 @@ Usage:
|
||||
Requires only Python 3 stdlib (no pip dependencies).
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from common import ensure_venv # noqa: E402
|
||||
|
||||
ensure_venv()
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Paths / Config
|
||||
|
||||
+9
-19
@@ -15,17 +15,16 @@ Usage:
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from common import WORKTREE_ROOT, get_connection, load_config # noqa: E402
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
TICKET_CLI = str(SCRIPT_DIR / "ticket")
|
||||
WORKTREE_ROOT = (SCRIPT_DIR / ".." / "..").resolve()
|
||||
# Database path: SR_DB_PATH env var (absolute), or fallback to parent directory heuristic.
|
||||
DB_PATH = Path(os.environ["SR_DB_PATH"]).resolve() if os.environ.get("SR_DB_PATH") else (WORKTREE_ROOT / ".." / "settledreach.db").resolve()
|
||||
PROJECT_ROOT = WORKTREE_ROOT
|
||||
|
||||
REMINDER = """---
|
||||
@@ -48,15 +47,6 @@ def run_ticket(*args):
|
||||
return {"ok": False, "error": f"Bad ticket output: {result.stdout[:200]}"}
|
||||
|
||||
|
||||
def get_connection():
|
||||
"""Direct DB connection for lifecycle mutations only."""
|
||||
conn = sqlite3.connect(str(DB_PATH))
|
||||
conn.execute("PRAGMA journal_mode=WAL;")
|
||||
conn.execute("PRAGMA foreign_keys=ON;")
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
|
||||
def parse_flags(args, known_flags):
|
||||
"""Parse --flag value pairs from args, return (flags_dict, positional_args)."""
|
||||
flags = {}
|
||||
@@ -325,7 +315,7 @@ def cmd_start(args):
|
||||
sys.exit(1)
|
||||
|
||||
# Activate
|
||||
conn = get_connection()
|
||||
conn = get_connection(load_config())
|
||||
conn.execute(
|
||||
"UPDATE sprints SET status='active', start_date=date('now') WHERE id=?",
|
||||
(sprint["id"],)
|
||||
@@ -369,7 +359,7 @@ def cmd_stop(args):
|
||||
picked_up = [t for t in incomplete if t["status"] in picked_up_statuses]
|
||||
auto_closed = []
|
||||
if picked_up:
|
||||
conn = get_connection()
|
||||
conn = get_connection(load_config())
|
||||
for t in picked_up:
|
||||
conn.execute("UPDATE tickets SET status='done' WHERE id=?", (t["id"],))
|
||||
auto_closed.append(t)
|
||||
@@ -380,7 +370,7 @@ def cmd_stop(args):
|
||||
incomplete = [t for t in incomplete if t["status"] not in picked_up_statuses]
|
||||
|
||||
# Complete the sprint
|
||||
conn = get_connection()
|
||||
conn = get_connection(load_config())
|
||||
conn.execute(
|
||||
"UPDATE sprints SET status='completed', end_date=date('now') WHERE id=?",
|
||||
(sprint["id"],)
|
||||
@@ -602,7 +592,7 @@ def cmd_prepare(args):
|
||||
|
||||
# Create sprint record if it doesn't exist
|
||||
if sprint.get("status") == "new":
|
||||
conn = get_connection()
|
||||
conn = get_connection(load_config())
|
||||
conn.execute(
|
||||
"INSERT INTO sprints (id, name, status) VALUES (?, ?, 'planning')",
|
||||
(sprint["id"], f"Sprint {sprint['id']}")
|
||||
@@ -664,7 +654,7 @@ def cmd_prepare(args):
|
||||
print()
|
||||
|
||||
# Decision coverage gaps
|
||||
conn = get_connection()
|
||||
conn = get_connection(load_config())
|
||||
cursor = conn.execute("""
|
||||
SELECT id, title FROM decisions
|
||||
WHERE type='confirmed' AND status='active'
|
||||
|
||||
@@ -11,38 +11,15 @@ Usage:
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Paths
|
||||
# ---------------------------------------------------------------------------
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from common import WORKTREE_ROOT, get_connection, load_config # noqa: E402
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
CONFIG_PATH = SCRIPT_DIR / "config.json"
|
||||
WORKTREE_ROOT = (SCRIPT_DIR / ".." / "..").resolve()
|
||||
SCHEMA_PATH = WORKTREE_ROOT / "db" / "schema.sql"
|
||||
# Database path: SR_DB_PATH env var (absolute), or fallback to parent directory heuristic.
|
||||
DB_PATH = Path(os.environ["SR_DB_PATH"]).resolve() if os.environ.get("SR_DB_PATH") else (WORKTREE_ROOT / ".." / "settledreach.db").resolve()
|
||||
|
||||
|
||||
def load_config():
|
||||
"""Load config.json and resolve the SQLite database path."""
|
||||
with open(CONFIG_PATH, "r") as f:
|
||||
cfg = json.load(f)
|
||||
cfg["sqlite_db_resolved"] = str(DB_PATH)
|
||||
return cfg
|
||||
|
||||
|
||||
def get_connection(cfg):
|
||||
"""Return an sqlite3 connection with WAL mode and foreign keys enabled."""
|
||||
conn = sqlite3.connect(cfg["sqlite_db_resolved"])
|
||||
conn.execute("PRAGMA journal_mode=WAL;")
|
||||
conn.execute("PRAGMA foreign_keys=ON;")
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -180,9 +157,8 @@ Usage:
|
||||
|
||||
All output is JSON on stdout. Errors also use JSON with {{"ok": false, "error": "..."}}.
|
||||
|
||||
Config: {config}
|
||||
Schema: {schema}
|
||||
""".format(config=CONFIG_PATH, schema=SCHEMA_PATH)
|
||||
""".format(schema=SCHEMA_PATH)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
+2
-21
@@ -23,31 +23,12 @@ All output is JSON on stdout.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
CONFIG_PATH = SCRIPT_DIR / "config.json"
|
||||
WORKTREE_ROOT = (SCRIPT_DIR / ".." / "..").resolve()
|
||||
# Database path: SR_DB_PATH env var (absolute), or fallback to parent directory heuristic.
|
||||
DB_PATH = Path(os.environ["SR_DB_PATH"]).resolve() if os.environ.get("SR_DB_PATH") else (WORKTREE_ROOT / ".." / "settledreach.db").resolve()
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
|
||||
def load_config():
|
||||
with open(CONFIG_PATH, "r") as f:
|
||||
cfg = json.load(f)
|
||||
cfg["sqlite_db_resolved"] = str(DB_PATH)
|
||||
return cfg
|
||||
|
||||
|
||||
def get_connection(cfg):
|
||||
conn = sqlite3.connect(cfg["sqlite_db_resolved"])
|
||||
conn.execute("PRAGMA journal_mode=WAL;")
|
||||
conn.execute("PRAGMA foreign_keys=ON;")
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
from common import get_connection, load_config # noqa: E402
|
||||
|
||||
|
||||
def query(conn, sql, params=()):
|
||||
|
||||
@@ -36,15 +36,22 @@ Gradio API Parameter Reference (TRELLIS v1, microsoft/TRELLIS):
|
||||
- CUDA device mismatch after crash: restart the container to clear GPU state
|
||||
"""
|
||||
|
||||
import base64
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from common import ensure_venv # noqa: E402
|
||||
|
||||
ensure_venv()
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
CONFIG_PATH = os.path.join(os.path.dirname(__file__), "config.json")
|
||||
|
||||
|
||||
@@ -13,10 +13,8 @@ Standard library only. No external dependencies.
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import math
|
||||
import random
|
||||
import sys
|
||||
import os
|
||||
import argparse
|
||||
from collections import defaultdict, deque
|
||||
from pathlib import Path
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""Load original Quaternius body + hair as-is and export a combined GLB for visual inspection."""
|
||||
import sys
|
||||
import os
|
||||
import bpy
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user