Retention deletions are sequenced so the guarantee actually holds: the video goes only after the FLAC is extracted, verified and committed, and the FLAC only after every output is written and committed. Each deletion records itself both in state.json and in events.jsonl, so a later run can tell "removed as requested" from "gone and should not be". Two bugs the tests caught while writing this: - params_changed compared the requested model id against the resolved one, so every re-run looked like a parameter change and re-transcribed. An unpinned model now matches whatever ran; only an explicit --model can disagree. - chain=DEFAULT_CHAIN as a default argument binds at import time, which made the backend chain impossible to override. It is resolved at call time now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
107 lines
2.8 KiB
TOML
107 lines
2.8 KiB
TOML
[build-system]
|
|
requires = ["hatchling"]
|
|
build-backend = "hatchling.build"
|
|
|
|
[project]
|
|
name = "ccn-transcribe"
|
|
version = "0.1.0"
|
|
description = "Download videos, extract FLAC, and transcribe with Whisper on whatever GPU is present."
|
|
requires-python = ">=3.12"
|
|
dependencies = [
|
|
"click>=8.1,<9",
|
|
"numpy>=2.5,<3",
|
|
"huggingface-hub>=1.31,<2",
|
|
"yt-dlp[default,deno]>=2026.8.19",
|
|
"yt-dlp-ejs>=0.8",
|
|
"openvino==2026.3.1",
|
|
"openvino-genai==2026.3.1.0",
|
|
]
|
|
|
|
[project.scripts]
|
|
ccn-transcribe = "ccn_transcribe.cli:main"
|
|
|
|
[dependency-groups]
|
|
dev = [
|
|
"pytest>=8",
|
|
"pytest-cov>=5",
|
|
"ruff>=0.6",
|
|
"pyright>=1.1.380",
|
|
"mypy>=1.11",
|
|
"pylint>=3.2",
|
|
"pre-commit>=3.8",
|
|
]
|
|
|
|
[tool.hatch.build.targets.wheel]
|
|
packages = ["src/ccn_transcribe"]
|
|
|
|
[tool.ruff]
|
|
line-length = 100
|
|
src = ["src", "tests"]
|
|
# ruff format also restyles Python blocks inside Markdown; docs are not ours to restyle.
|
|
extend-exclude = ["*.md"]
|
|
|
|
[tool.ruff.lint]
|
|
select = ["E", "F", "W", "I", "N", "UP", "B", "A", "C4", "SIM", "PTH", "RET", "ARG", "TID", "TC", "RUF", "S"]
|
|
# S607: binaries are looked up on PATH on purpose and preflight-checked with
|
|
# shutil.which; hardcoding absolute paths would be less portable, not safer.
|
|
ignore = ["S607"]
|
|
|
|
[tool.ruff.lint.per-file-ignores]
|
|
# S101: asserts are the point of a test file.
|
|
"tests/*" = ["ARG001", "ARG002", "S101"]
|
|
# Throwaway benchmarks, not pipeline code.
|
|
"scripts/*" = ["S603"]
|
|
|
|
[tool.pyright]
|
|
include = ["src", "tests"]
|
|
typeCheckingMode = "strict"
|
|
venvPath = "."
|
|
venv = ".venv"
|
|
|
|
[tool.mypy]
|
|
strict = true
|
|
files = ["src", "tests"]
|
|
|
|
[[tool.mypy.overrides]]
|
|
# These ship no py.typed marker.
|
|
module = ["openvino.*", "openvino_genai.*", "huggingface_hub.*", "yt_dlp.*"]
|
|
ignore_missing_imports = true
|
|
|
|
[tool.pylint.design]
|
|
max-attributes = 20
|
|
# Keyword-only arguments do not carry the readability cost this check guards against.
|
|
max-args = 9
|
|
# Pipeline entry points carry injectable seams for testing.
|
|
max-locals = 18
|
|
|
|
[tool.pylint.main]
|
|
# W0621: pytest fixtures shadow their names by design.
|
|
# C1803: asserting == () is more precise than truthiness about what a call returns.
|
|
# R0903: dataclasses and pytest grouping classes legitimately have few methods.
|
|
disable = [
|
|
"C0114", "C0115", "C0116", "C0301",
|
|
"W0611", "W0612", "W0621",
|
|
"R0801", "R0903", "C1803",
|
|
]
|
|
|
|
[tool.pytest.ini_options]
|
|
testpaths = ["tests"]
|
|
# NOTE: --cov-fail-under deliberately lives in the pre-commit hook, not here, so a
|
|
# single-file TDD run (`uv run pytest tests/test_x.py`) is not blocked by coverage.
|
|
addopts = "-q"
|
|
|
|
[tool.coverage.run]
|
|
branch = true
|
|
source = ["src/ccn_transcribe"]
|
|
|
|
[tool.coverage.report]
|
|
fail_under = 100
|
|
show_missing = true
|
|
exclude_also = [
|
|
"if TYPE_CHECKING:",
|
|
'if __name__ == "__main__":',
|
|
"@overload",
|
|
"raise NotImplementedError",
|
|
"class .*\\(Protocol\\):",
|
|
]
|