diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..794d0f132 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,7 @@ +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.9.4 + hooks: + - id: ruff + args: [--fix] + - id: ruff-format diff --git a/pyproject.toml b/pyproject.toml index ca2d20f5a..265bda1c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,6 +88,7 @@ dev = [ "pytest-asyncio>=0.21.0", "ruff>=0.1.0", "mypy>=1.0.0", + "pre-commit>=3.0.0", "openai>=1.0.0", "anthropic>=0.18.0", "ollama>=0.4.0", # For Ollama integration tests (local LLM, no API key needed) @@ -139,6 +140,7 @@ ignore = [ "E501", # line too long (handled by formatter) "B008", # do not perform function calls in argument defaults "B905", # zip without strict parameter + "UP038", # isinstance(x, (A, B)) is clearer than isinstance(x, A | B) ] [tool.ruff.lint.isort] diff --git a/uv.lock b/uv.lock index 0879a30fd..255c8ce11 100644 --- a/uv.lock +++ b/uv.lock @@ -279,6 +279,15 @@ wheels = [ { url = "https://pypi.netflix.net/packages/19551676290/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900 }, ] +[[package]] +name = "cfgv" +version = "3.5.0" +source = { registry = "https://pypi.netflix.net/simple" } +sdist = { url = "https://pypi.netflix.net/packages/19362044288/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334 } +wheels = [ + { url = "https://pypi.netflix.net/packages/19362044287/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445 }, +] + [[package]] name = "charset-normalizer" version = "3.4.4" @@ -493,6 +502,15 @@ toml = [ { name = "tomli", marker = "python_full_version <= '3.11'" }, ] +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.netflix.net/simple" } +sdist = { url = "https://pypi.netflix.net/packages/18880393968/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605 } +wheels = [ + { url = "https://pypi.netflix.net/packages/18880393967/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047 }, +] + [[package]] name = "distro" version = "1.9.0" @@ -849,7 +867,7 @@ wheels = [ [[package]] name = "headroom-ai" -version = "0.2.14" +version = "0.2.15" source = { editable = "." } dependencies = [ { name = "litellm" }, @@ -885,6 +903,7 @@ dev = [ { name = "mypy" }, { name = "ollama" }, { name = "openai" }, + { name = "pre-commit" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-cov" }, @@ -925,6 +944,7 @@ requires-dist = [ { name = "ollama", marker = "extra == 'dev'", specifier = ">=0.4.0" }, { name = "openai", specifier = ">=2.14.0" }, { name = "openai", marker = "extra == 'dev'", specifier = ">=1.0.0" }, + { name = "pre-commit", marker = "extra == 'dev'", specifier = ">=3.0.0" }, { name = "pydantic", specifier = ">=2.0.0" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0.0" }, { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.21.0" }, @@ -1038,6 +1058,15 @@ wheels = [ { url = "https://pypi.netflix.net/packages/18412911475/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007 }, ] +[[package]] +name = "identify" +version = "2.6.16" +source = { registry = "https://pypi.netflix.net/simple" } +sdist = { url = "https://pypi.netflix.net/packages/19591398969/identify-2.6.16.tar.gz", hash = "sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980", size = 99360 } +wheels = [ + { url = "https://pypi.netflix.net/packages/19591398968/identify-2.6.16-py2.py3-none-any.whl", hash = "sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0", size = 99202 }, +] + [[package]] name = "idna" version = "3.11" @@ -1749,6 +1778,15 @@ wheels = [ { url = "https://pypi.netflix.net/packages/19152095448/nltk-3.9.2-py3-none-any.whl", hash = "sha256:1e209d2b3009110635ed9709a67a1a3e33a10f799490fa71cf4bec218c11c88a", size = 1513404 }, ] +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.netflix.net/simple" } +sdist = { url = "https://pypi.netflix.net/packages/19506210316/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611 } +wheels = [ + { url = "https://pypi.netflix.net/packages/19506210315/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438 }, +] + [[package]] name = "numpy" version = "2.2.6" @@ -2178,6 +2216,15 @@ wheels = [ { url = "https://pypi.netflix.net/packages/19570732229/pathspec-1.0.2-py3-none-any.whl", hash = "sha256:62f8558917908d237d399b9b338ef455a814801a4688bc41074b25feefd93472", size = 54844 }, ] +[[package]] +name = "platformdirs" +version = "4.5.1" +source = { registry = "https://pypi.netflix.net/simple" } +sdist = { url = "https://pypi.netflix.net/packages/19429340046/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715 } +wheels = [ + { url = "https://pypi.netflix.net/packages/19429340045/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731 }, +] + [[package]] name = "pluggy" version = "1.6.0" @@ -2187,6 +2234,22 @@ wheels = [ { url = "https://pypi.netflix.net/packages/18687957486/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538 }, ] +[[package]] +name = "pre-commit" +version = "4.5.1" +source = { registry = "https://pypi.netflix.net/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://pypi.netflix.net/packages/19490339478/pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61", size = 198232 } +wheels = [ + { url = "https://pypi.netflix.net/packages/19490339477/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437 }, +] + [[package]] name = "propcache" version = "0.4.1" @@ -3737,6 +3800,21 @@ wheels = [ { url = "https://pypi.netflix.net/packages/19509782003/uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee", size = 68502 }, ] +[[package]] +name = "virtualenv" +version = "20.36.1" +source = { registry = "https://pypi.netflix.net/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://pypi.netflix.net/packages/19577951673/virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba", size = 6032239 } +wheels = [ + { url = "https://pypi.netflix.net/packages/19577951672/virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f", size = 6008258 }, +] + [[package]] name = "yarl" version = "1.22.0"