From ea3bea3cf54e64d53b59ac1eb06b2e079b2fa657 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 12 Mar 2026 13:59:05 -0700 Subject: [PATCH 01/11] chore(deps): Replace pip/requirements with uv Move dependency management from requirements.txt/requirements-dev.txt to pyproject.toml [dependency-groups] managed by uv. Add ruff config to pyproject.toml replacing black/flake8 tool config. Co-Authored-By: Claude Opus 4.6 --- .envrc | 12 +- .python-version | 1 + pyproject.toml | 22 +- requirements-dev.txt | 11 - requirements.txt | 6 - uv.lock | 463 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 486 insertions(+), 29 deletions(-) create mode 100644 .python-version delete mode 100644 requirements-dev.txt delete mode 100644 requirements.txt create mode 100644 uv.lock diff --git a/.envrc b/.envrc index d30a4028..698d20e7 100644 --- a/.envrc +++ b/.envrc @@ -4,13 +4,5 @@ if [[ -f .env ]]; then dotenv .env fi -if [ ! -d .venv ]; then - echo "warning: creating virtualenv for the first time" - python3 -m venv .venv - source .venv/bin/activate - pip install -r requirements.txt - pip install -r requirements-dev.txt -else - source .venv/bin/activate - unset PS1 -fi +PATH_add "$PWD/.venv/bin" +export VIRTUAL_ENV="$PWD/.venv" diff --git a/.python-version b/.python-version new file mode 100644 index 00000000..e4fba218 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/pyproject.toml b/pyproject.toml index 54966a52..abf9869a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,12 +15,17 @@ dependencies = [ "supervisor", ] -[project.optional-dependencies] +[dependency-groups] dev = [ - "black", + "build", + "freezegun", "mypy", "pre-commit", "pytest", + "pytest-cov", + "ruff", + "setuptools>=70", + "shellcheck-py", "types-PyYAML", ] @@ -30,6 +35,8 @@ devservices = "devservices.main:main" [tool.setuptools.packages] find = {} +[[tool.uv.index]] +url = "https://pypi.devinfra.sentry.io/simple" [tool.mypy] python_version = "3.12" @@ -39,3 +46,14 @@ ignore_missing_imports = true [[tool.mypy.overrides]] module = "yaml.*" ignore_missing_imports = true + +[tool.ruff] +target-version = "py311" + +[tool.ruff.lint] +select = ["E", "F", "I"] +ignore = ["E501"] + +[tool.ruff.lint.isort] +force-single-line = true +required-imports = ["from __future__ import annotations"] diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index ae56b7f2..00000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,11 +0,0 @@ ---index-url https://pypi.devinfra.sentry.io/simple -black==24.4.2 -mypy==1.11.2 -pre-commit==3.6.0 -pytest==8.1.1 -pytest-cov==4.1.0 -types-PyYAML==6.0.11 -setuptools==78.1.1 -build==0.8.0 -wheel==0.42.0 -freezegun==1.2.2 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 164227b0..00000000 --- a/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ ---index-url https://pypi.devinfra.sentry.io/simple -pyyaml==6.0.2 -packaging==24.0 -sentry-devenv==1.9.0 -sentry-sdk==2.39.0 -supervisor==4.2.5 diff --git a/uv.lock b/uv.lock new file mode 100644 index 00000000..c0d74b64 --- /dev/null +++ b/uv.lock @@ -0,0 +1,463 @@ +version = 1 +revision = 3 +requires-python = ">=3.11" + +[[package]] +name = "build" +version = "1.4.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +dependencies = [ + { name = "colorama", marker = "os_name == 'nt'" }, + { name = "packaging" }, + { name = "pyproject-hooks" }, +] +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/build-1.4.0-py3-none-any.whl", hash = "sha256:6a07c1b8eb6f2b311b96fcbdbce5dab5fe637ffda0fd83c9cac622e927501596" }, +] + +[[package]] +name = "certifi" +version = "2026.1.4" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c" }, +] + +[[package]] +name = "cfgv" +version = "3.4.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" }, +] + +[[package]] +name = "coverage" +version = "7.6.4" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b" }, + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25" }, + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546" }, + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e" }, + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2" }, + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117" }, + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613" }, + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52" }, + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9" }, + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba" }, + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c" }, + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f" }, + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:195bb15106367d53b0568a0f5cdf6e3b90ab60a618bcc52769585d5384941021" }, + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_31_aarch64.whl", hash = "sha256:4ba20745bbafc23169ddbac67751686f5c062e843482c00d12bce78229f91832" }, + { url = "https://pypi.devinfra.sentry.io/wheels/coverage-7.6.4-cp314-cp314-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_31_x86_64.whl", hash = "sha256:62d663523d03014e6215fcc04ccdc843bb7c4d05eda4720972128f3b83885fb9" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "devservices" +version = "1.2.4" +source = { editable = "." } +dependencies = [ + { name = "packaging" }, + { name = "pyyaml" }, + { name = "sentry-devenv" }, + { name = "sentry-sdk" }, + { name = "supervisor" }, +] + +[package.dev-dependencies] +dev = [ + { name = "build" }, + { name = "freezegun" }, + { name = "mypy" }, + { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "ruff" }, + { name = "setuptools" }, + { name = "shellcheck-py" }, + { name = "types-pyyaml" }, +] + +[package.metadata] +requires-dist = [ + { name = "packaging" }, + { name = "pyyaml" }, + { name = "sentry-devenv" }, + { name = "sentry-sdk" }, + { name = "supervisor" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "build" }, + { name = "freezegun" }, + { name = "mypy" }, + { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "ruff" }, + { name = "setuptools", specifier = ">=70" }, + { name = "shellcheck-py" }, + { name = "types-pyyaml" }, +] + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16" }, +] + +[[package]] +name = "filelock" +version = "3.20.3" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1" }, +] + +[[package]] +name = "freezegun" +version = "1.5.5" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/freezegun-1.5.5-py3-none-any.whl", hash = "sha256:cd557f4a75cf074e84bc374249b9dd491eaeacd61376b9eb3c423282211619d2" }, +] + +[[package]] +name = "identify" +version = "2.6.9" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/identify-2.6.9-py2.py3-none-any.whl", hash = "sha256:c98b4322da415a8e5a70ff6e51fbc2d2932c015532d77e9f8537b4ba7813b150" }, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" }, +] + +[[package]] +name = "librt" +version = "0.7.8" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/librt-0.7.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ddb52499d0b3ed4aa88746aaf6f36a08314677d5c346234c3987ddc506404eac" }, + { url = "https://pypi.devinfra.sentry.io/wheels/librt-0.7.8-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:631599598e2c76ded400c0a8722dec09217c89ff64dc54b060f598ed68e7d2a8" }, + { url = "https://pypi.devinfra.sentry.io/wheels/librt-0.7.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c1ba843ae20db09b9d5c80475376168feb2640ce91cd9906414f23cc267a1ff" }, + { url = "https://pypi.devinfra.sentry.io/wheels/librt-0.7.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:46ef1f4b9b6cc364b11eea0ecc0897314447a66029ee1e55859acb3dd8757c93" }, + { url = "https://pypi.devinfra.sentry.io/wheels/librt-0.7.8-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2991b6c3775383752b3ca0204842743256f3ad3deeb1d0adc227d56b78a9a850" }, + { url = "https://pypi.devinfra.sentry.io/wheels/librt-0.7.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03679b9856932b8c8f674e87aa3c55ea11c9274301f76ae8dc4d281bda55cf62" }, + { url = "https://pypi.devinfra.sentry.io/wheels/librt-0.7.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:44e0c2cbc9bebd074cf2cdbe472ca185e824be4e74b1c63a8e934cea674bebf2" }, + { url = "https://pypi.devinfra.sentry.io/wheels/librt-0.7.8-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:451e7ffcef8f785831fdb791bd69211f47e95dc4c6ddff68e589058806f044c6" }, + { url = "https://pypi.devinfra.sentry.io/wheels/librt-0.7.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3469e1af9f1380e093ae06bedcbdd11e407ac0b303a56bbe9afb1d6824d4982d" }, + { url = "https://pypi.devinfra.sentry.io/wheels/librt-0.7.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7b0803e9008c62a7ef79058233db7ff6f37a9933b8f2573c05b07ddafa226611" }, + { url = "https://pypi.devinfra.sentry.io/wheels/librt-0.7.8-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b9122094e3f24aa759c38f46bd8863433820654927370250f460ae75488b66ea" }, + { url = "https://pypi.devinfra.sentry.io/wheels/librt-0.7.8-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7e03bea66af33c95ce3addf87a9bf1fcad8d33e757bc479957ddbc0e4f7207ac" }, +] + +[[package]] +name = "mypy" +version = "1.19.1" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +dependencies = [ + { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/mypy-1.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e3f276d8493c3c97930e354b2595a44a21348b320d859fb4a2b9f66da9ed27ab" }, + { url = "https://pypi.devinfra.sentry.io/wheels/mypy-1.19.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2abb24cf3f17864770d18d673c85235ba52456b36a06b6afc1e07c1fdcd3d0e6" }, + { url = "https://pypi.devinfra.sentry.io/wheels/mypy-1.19.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a009ffa5a621762d0c926a078c2d639104becab69e79538a494bcccb62cc0331" }, + { url = "https://pypi.devinfra.sentry.io/wheels/mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e" }, + { url = "https://pypi.devinfra.sentry.io/wheels/mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2" }, + { url = "https://pypi.devinfra.sentry.io/wheels/mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8" }, + { url = "https://pypi.devinfra.sentry.io/wheels/mypy-1.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b" }, + { url = "https://pypi.devinfra.sentry.io/wheels/mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e" }, + { url = "https://pypi.devinfra.sentry.io/wheels/mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef" }, + { url = "https://pypi.devinfra.sentry.io/wheels/mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718" }, + { url = "https://pypi.devinfra.sentry.io/wheels/mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b" }, + { url = "https://pypi.devinfra.sentry.io/wheels/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505" }, +] + +[[package]] +name = "nodeenv" +version = "1.9.1" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529" }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08" }, +] + +[[package]] +name = "platformdirs" +version = "4.5.1" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31" }, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" }, +] + +[[package]] +name = "pre-commit" +version = "4.2.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd" }, +] + +[[package]] +name = "pyproject-hooks" +version = "1.2.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913" }, +] + +[[package]] +name = "pytest" +version = "8.3.3" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, +] +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" }, +] + +[[package]] +name = "pytest-cov" +version = "4.1.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pytest" }, +] +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +dependencies = [ + { name = "six" }, +] +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e" }, + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824" }, + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c" }, + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d" }, + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196" }, + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0" }, + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28" }, + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc" }, + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8" }, + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1" }, + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c" }, + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6" }, + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310" }, + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7" }, + { url = "https://pypi.devinfra.sentry.io/wheels/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5" }, +] + +[[package]] +name = "ruff" +version = "0.14.10" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/ruff-0.14.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d85713d522348837ef9df8efca33ccb8bd6fcfc86a2cde3ccb4bc9d28a18003d" }, + { url = "https://pypi.devinfra.sentry.io/wheels/ruff-0.14.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6987ebe0501ae4f4308d7d24e2d0fe3d7a98430f5adfd0f1fead050a740a3a77" }, + { url = "https://pypi.devinfra.sentry.io/wheels/ruff-0.14.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59aabd2e2c4fd614d2862e7939c34a532c04f1084476d6833dddef4afab87e9f" }, +] + +[[package]] +name = "sentry-devenv" +version = "1.28.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +dependencies = [ + { name = "sentry-sdk" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/sentry_devenv-1.28.0-py3-none-any.whl", hash = "sha256:304b603c561c4a0a206c7d1346aebf8ec44e6175f44ecce0b9c1a5848fb3f7ca" }, +] + +[[package]] +name = "sentry-sdk" +version = "2.54.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +dependencies = [ + { name = "certifi" }, + { name = "urllib3" }, +] +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/sentry_sdk-2.54.0-py2.py3-none-any.whl", hash = "sha256:fd74e0e281dcda63afff095d23ebcd6e97006102cdc8e78a29f19ecdf796a0de" }, +] + +[[package]] +name = "setuptools" +version = "80.10.2" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/setuptools-80.10.2-py3-none-any.whl", hash = "sha256:95b30ddfb717250edb492926c92b5221f7ef3fbcc2b07579bcd4a27da21d0173" }, +] + +[[package]] +name = "shellcheck-py" +version = "0.11.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/55/455b097417b3df3d330eff029c72c32f08b25739e3010acb30ad06d268ef/shellcheck_py-0.11.0.1.tar.gz", hash = "sha256:5c620c88901e8f1d3be5934b31ea99e3310065e1245253741eafd0a275c8c9cc", size = 3139, upload-time = "2025-08-09T17:53:42.492Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/27/d75b03e5458cefdb6d3b674566cd20476c3e4d3fe6cc9d68b7e3b854b296/shellcheck_py-0.11.0.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:b6a3fee28efda2e16e38d6e6d59faf7224300256456639727370d404730849e8", size = 6774472, upload-time = "2025-08-09T17:53:34.573Z" }, + { url = "https://files.pythonhosted.org/packages/61/ac/2a84c37171c0cf5a10ea4b0a27d43eb0a1d29bd98b49c2c5ffe17ad24bbe/shellcheck_py-0.11.0.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:6b88d0a244c82ed07e06a53e444da841f69330ca59ae15d4a66c391655dae7a0", size = 11381835, upload-time = "2025-08-09T17:53:36.852Z" }, + { url = "https://files.pythonhosted.org/packages/96/55/250e0e3367613a5c22bd82e33b16b889287d81ab0f7dda67e6514a4cccf4/shellcheck_py-0.11.0.1-py2.py3-none-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1b274df81de5b000ff78db433e7328b87e52e3c38481c60f8e488c3095beef05", size = 3800600, upload-time = "2025-08-09T17:53:38.643Z" }, + { url = "https://files.pythonhosted.org/packages/15/5b/bb14c0a7474463b1aa3c09e866cb172dffc66ed2993b7ea8f1db581e86ee/shellcheck_py-0.11.0.1-py2.py3-none-win_amd64.whl", hash = "sha256:784156289ecb17e91c692cd783ab5152333309588cabb10032a047331c63e759", size = 8027541, upload-time = "2025-08-09T17:53:40.889Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274" }, +] + +[[package]] +name = "supervisor" +version = "4.2.5" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +dependencies = [ + { name = "setuptools" }, +] +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/supervisor-4.2.5-py2.py3-none-any.whl", hash = "sha256:2ecaede32fc25af814696374b79e42644ecaba5c09494c51016ffda9602d0f08" }, +] + +[[package]] +name = "tomli" +version = "2.2.1" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249" }, + { url = "https://pypi.devinfra.sentry.io/wheels/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6" }, + { url = "https://pypi.devinfra.sentry.io/wheels/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a" }, + { url = "https://pypi.devinfra.sentry.io/wheels/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee" }, + { url = "https://pypi.devinfra.sentry.io/wheels/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea" }, + { url = "https://pypi.devinfra.sentry.io/wheels/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8" }, + { url = "https://pypi.devinfra.sentry.io/wheels/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192" }, + { url = "https://pypi.devinfra.sentry.io/wheels/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222" }, + { url = "https://pypi.devinfra.sentry.io/wheels/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7" }, + { url = "https://pypi.devinfra.sentry.io/wheels/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c" }, + { url = "https://pypi.devinfra.sentry.io/wheels/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13" }, + { url = "https://pypi.devinfra.sentry.io/wheels/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281" }, + { url = "https://pypi.devinfra.sentry.io/wheels/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc" }, +] + +[[package]] +name = "types-pyyaml" +version = "6.0.12.20241230" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/types_PyYAML-6.0.12.20241230-py3-none-any.whl", hash = "sha256:fa4d32565219b68e6dee5f67534c722e53c00d1cfc09c435ef04d7353e1e96e6" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4" }, +] + +[[package]] +name = "virtualenv" +version = "20.36.1" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, +] +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f" }, +] From c02162118da4a68bf9b0323086229eef8ebf9d32 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 12 Mar 2026 13:59:13 -0700 Subject: [PATCH 02/11] chore(lint): Switch to local pre-commit hooks with ruff Replace remote pre-commit hooks (black, flake8, reorder-python-imports, mirrors-mypy, shellcheck-py) with local hooks using .venv/bin/ binaries. Ruff replaces black + flake8 + reorder-python-imports. Remove setup.cfg (flake8 config now covered by ruff in pyproject.toml). Co-Authored-By: Claude Opus 4.6 --- .pre-commit-config.yaml | 44 ++++++++++++++++++----------------------- setup.cfg | 6 ------ 2 files changed, 19 insertions(+), 31 deletions(-) delete mode 100644 setup.cfg diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 59988365..273d3d46 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,33 +1,27 @@ repos: - - repo: https://github.com/asottile/reorder-python-imports - rev: v3.12.0 - hooks: - - id: reorder-python-imports - args: [--py311-plus, --add-import, "from __future__ import annotations"] - - repo: https://github.com/psf/black - rev: 23.10.0 - hooks: - - id: black - language_version: python3.12 - - repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 - hooks: - - id: flake8 - language_version: python3.12 - - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.6.1 + - repo: local hooks: + - id: ruff-check + name: ruff check + entry: .venv/bin/ruff check --fix + language: system + types: [python] + - id: ruff-format + name: ruff format + entry: .venv/bin/ruff format + language: system + types: [python] - id: mypy - additional_dependencies: - - "pytest" - - "types-PyYAML" - language_version: python3.12 - - repo: https://github.com/shellcheck-py/shellcheck-py - rev: v0.9.0.6 - hooks: + name: mypy + entry: .venv/bin/mypy + language: system + types: [python] - id: shellcheck + name: shellcheck + entry: .venv/bin/shellcheck + language: system + types: [shell] args: [--norc] - language_version: python3.12 - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.6.0 hooks: diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 487746c7..00000000 --- a/setup.cfg +++ /dev/null @@ -1,6 +0,0 @@ -[flake8] -max-line-length = 100 -extend-ignore = - ## black takes care of that: - # line too long (X > Y characters) - E501 From d8032f16b5c127358386e202e77b12f493c3b6d1 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 12 Mar 2026 13:59:20 -0700 Subject: [PATCH 03/11] ci: Migrate workflows to uv Replace setup-python + pip install with astral-sh/setup-uv + uv sync. Test workflow uses uv sync --python for matrix testing. Build workflow uses uv build for dist and uv export for pyoxidizer requirements. Co-Authored-By: Claude Opus 4.6 --- .github/workflows/build.yml | 19 +++++++++---------- .github/workflows/lint.yml | 10 +++++----- .github/workflows/test.yml | 14 ++++---------- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 83fc8e9f..4fa6ff10 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,15 +14,10 @@ jobs: steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1 - with: - python-version: 3.12 - - - name: Install dev requirements - run: pip install -r requirements-dev.txt + - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.3.1 - name: "Prepare Artifacts" - run: python -m build + run: uv build - name: Cache dist uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 @@ -49,14 +44,18 @@ jobs: with: python-version: 3.12 + - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.3.1 + - name: Install pyoxidizer run: pip install pyoxidizer==0.24.0 - - name: Install dev requirements - run: pip install -r requirements-dev.txt + - name: Export requirements.txt for pyoxidizer + run: uv export --no-dev --no-hashes --no-emit-project -o requirements.txt - name: Generate metadata - run: python -m build --sdist --no-isolation + run: | + uv sync + uv run python -m build --sdist --no-isolation - name: Build binary run: pyoxidizer build --release diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 626bc812..97689915 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,9 +16,9 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - name: Set up Python - uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1 - with: - python-version: 3.12 + - name: Set up uv + uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.3.1 + - name: Install dependencies + run: uv sync - name: Pre-commit - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 + run: uv run pre-commit run --all-files diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index be5ae585..d62520f5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,18 +24,12 @@ jobs: git config --global user.name "test" - name: Checkout repo uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - name: Set up Python - uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1 - with: - python-version: ${{ matrix.python-version }} + - name: Set up uv + uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.3.1 - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install -r requirements-dev.txt - pip install -e . + run: uv sync --python ${{ matrix.python-version }} - name: Run tests - run: pytest --cov --junitxml=junit.xml -o junit_family=legacy + run: uv run pytest --cov --junitxml=junit.xml -o junit_family=legacy - name: Upload results to Codecov uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 with: From 9209471020686423879caae9172d2394d2491dbb Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 12 Mar 2026 14:08:34 -0700 Subject: [PATCH 04/11] macos-15 and a few misc changes --- .envrc | 4 ++++ .github/workflows/build.yml | 13 ++++--------- .github/workflows/test.yml | 2 +- README.md | 8 ++++++++ 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/.envrc b/.envrc index 698d20e7..5d2c5c66 100644 --- a/.envrc +++ b/.envrc @@ -6,3 +6,7 @@ fi PATH_add "$PWD/.venv/bin" export VIRTUAL_ENV="$PWD/.venv" + +if [[ ! -f .git/hooks/pre-commit ]] || ! grep -q pre-commit .git/hooks/pre-commit 2>/dev/null; then + pre-commit install --install-hooks +fi diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4fa6ff10..707343cf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,11 +30,11 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04, macos-14] + os: [ubuntu-22.04, macos-15] include: - os: ubuntu-22.04 asset_name: devservices-linux - - os: macos-14 + - os: macos-15 asset_name: devservices-darwin steps: @@ -42,19 +42,14 @@ jobs: - uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1 with: - python-version: 3.12 + python-version-file: .python-version - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.3.1 - - name: Install pyoxidizer - run: pip install pyoxidizer==0.24.0 - - - name: Export requirements.txt for pyoxidizer - run: uv export --no-dev --no-hashes --no-emit-project -o requirements.txt - - name: Generate metadata run: | uv sync + uv pip install pyoxidizer==0.24.0 uv run python -m build --sdist --no-isolation - name: Build binary diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d62520f5..5140c946 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.11", "3.12"] + python-version: ["3.11.14", "3.12.12"] steps: - name: Configure git run: | diff --git a/README.md b/README.md index d7d2e2a7..02765bd1 100644 --- a/README.md +++ b/README.md @@ -167,3 +167,11 @@ networks: name: devservices external: true ``` + +## Dev + +```sh +uv sync +denv allow +pytest +``` From dad535b279618e8ea261955b2fb5b7bedfcd871f Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 12 Mar 2026 14:14:38 -0700 Subject: [PATCH 05/11] fix(build): Add wheel to dev dependency-group The pyoxidizer binary build uses `python -m build --sdist --no-isolation` which requires wheel to be installed in the venv. Co-Authored-By: Claude Opus 4.6 --- pyproject.toml | 1 + uv.lock | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index abf9869a..77026d7d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ dev = [ "ruff", "setuptools>=70", "shellcheck-py", + "wheel", "types-PyYAML", ] diff --git a/uv.lock b/uv.lock index c0d74b64..704e70c2 100644 --- a/uv.lock +++ b/uv.lock @@ -90,6 +90,7 @@ dev = [ { name = "setuptools" }, { name = "shellcheck-py" }, { name = "types-pyyaml" }, + { name = "wheel" }, ] [package.metadata] @@ -113,6 +114,7 @@ dev = [ { name = "setuptools", specifier = ">=70" }, { name = "shellcheck-py" }, { name = "types-pyyaml" }, + { name = "wheel" }, ] [[package]] @@ -461,3 +463,14 @@ dependencies = [ wheels = [ { url = "https://pypi.devinfra.sentry.io/wheels/virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f" }, ] + +[[package]] +name = "wheel" +version = "0.46.3" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +dependencies = [ + { name = "packaging" }, +] +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/wheel-0.46.3-py3-none-any.whl", hash = "sha256:4b399d56c9d9338230118d705d9737a2a468ccca63d5e813e2a4fc7815d8bc4d" }, +] From 28deb5d50bab4e52700dd1b7e2a6d306228a7dd8 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 12 Mar 2026 14:30:54 -0700 Subject: [PATCH 06/11] fix --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 707343cf..6385ccd8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ on: jobs: dist: name: Create Distribution - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -30,9 +30,9 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04, macos-15] + os: [ubuntu-24.04, macos-15] include: - - os: ubuntu-22.04 + - os: ubuntu-24.04 asset_name: devservices-linux - os: macos-15 asset_name: devservices-darwin @@ -53,7 +53,7 @@ jobs: uv run python -m build --sdist --no-isolation - name: Build binary - run: pyoxidizer build --release + run: uv run pyoxidizer build --release - name: Locate binary id: locate_binary @@ -72,7 +72,7 @@ jobs: upload-artifacts: name: Upload build artifacts - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: [dist, binary] if: github.event_name != 'pull_request' steps: From 33783680cdfabdde0bf5488947dc7a07620b1244 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 12 Mar 2026 14:34:30 -0700 Subject: [PATCH 07/11] fix --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6385ccd8..745383d5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,6 +50,7 @@ jobs: run: | uv sync uv pip install pyoxidizer==0.24.0 + uv export --no-dev --no-hashes --no-emit-project -o requirements.txt uv run python -m build --sdist --no-isolation - name: Build binary From 758fd754f7cb328fd02659b91e905e9d18abd67b Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 12 Mar 2026 15:42:35 -0700 Subject: [PATCH 08/11] upgrade setup-uv and pin python-version --- .envrc | 4 ++++ .github/workflows/build.yml | 4 ++-- .github/workflows/lint.yml | 2 +- .github/workflows/test.yml | 2 +- .python-version | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.envrc b/.envrc index 5d2c5c66..14cccebe 100644 --- a/.envrc +++ b/.envrc @@ -10,3 +10,7 @@ export VIRTUAL_ENV="$PWD/.venv" if [[ ! -f .git/hooks/pre-commit ]] || ! grep -q pre-commit .git/hooks/pre-commit 2>/dev/null; then pre-commit install --install-hooks fi + +if [ ! -d .venv ]; then + uv sync +fi diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 745383d5..a8b2474c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.3.1 + - uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7.5.0 - name: "Prepare Artifacts" run: uv build @@ -44,7 +44,7 @@ jobs: with: python-version-file: .python-version - - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.3.1 + - uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7.5.0 - name: Generate metadata run: | diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 97689915..3d33bd6e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,7 +17,7 @@ jobs: - name: Checkout repo uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up uv - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.3.1 + uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7.5.0 - name: Install dependencies run: uv sync - name: Pre-commit diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5140c946..a0e41e50 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,7 @@ jobs: - name: Checkout repo uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up uv - uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.3.1 + uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7.5.0 - name: Install dependencies run: uv sync --python ${{ matrix.python-version }} - name: Run tests diff --git a/.python-version b/.python-version index e4fba218..763b6264 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.12 +3.12.12 From 80ef8f0cde58ea03c78bd44a536fe1d7556b6825 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 12 Mar 2026 15:42:46 -0700 Subject: [PATCH 09/11] precommit --- devservices/__init__.py | 1 + devservices/commands/down.py | 16 ++++---- devservices/commands/foreground.py | 4 +- devservices/commands/list_dependencies.py | 2 +- devservices/commands/list_services.py | 2 +- devservices/commands/logs.py | 14 +++---- devservices/commands/purge.py | 2 +- devservices/commands/reset.py | 6 +-- devservices/commands/serve.py | 2 +- devservices/commands/status.py | 24 +++++------ devservices/commands/toggle.py | 4 +- devservices/commands/up.py | 16 ++++---- devservices/commands/update.py | 2 +- devservices/configs/service_config.py | 2 +- devservices/utils/console.py | 1 - devservices/utils/dependencies.py | 14 +++---- devservices/utils/docker_compose.py | 4 +- tests/commands/test_down.py | 2 +- tests/commands/test_foreground.py | 2 +- tests/commands/test_logs.py | 2 +- tests/commands/test_serve.py | 2 +- tests/commands/test_status.py | 10 ++--- tests/commands/test_toggle.py | 4 +- tests/commands/test_up.py | 50 +++++++++++++++++------ tests/configs/test_service_config.py | 2 +- tests/utils/test_dependencies.py | 14 ++++--- tests/utils/test_docker.py | 8 ++-- tests/utils/test_docker_compose.py | 2 +- tests/utils/test_services.py | 2 +- 29 files changed, 121 insertions(+), 95 deletions(-) diff --git a/devservices/__init__.py b/devservices/__init__.py index 2b589619..df12642d 100644 --- a/devservices/__init__.py +++ b/devservices/__init__.py @@ -1,4 +1,5 @@ """ DevServices CLI tool for managing Docker Compose services. """ + from __future__ import annotations diff --git a/devservices/commands/down.py b/devservices/commands/down.py index 8f4f6815..b90b0ae0 100644 --- a/devservices/commands/down.py +++ b/devservices/commands/down.py @@ -3,19 +3,19 @@ import concurrent.futures import os import subprocess -from argparse import _SubParsersAction from argparse import ArgumentParser from argparse import Namespace +from argparse import _SubParsersAction from sentry_sdk import capture_exception from sentry_sdk import logger as sentry_logger from devservices.constants import CONFIG_FILE_NAME from devservices.constants import DEPENDENCY_CONFIG_VERSION -from devservices.constants import DependencyType from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY from devservices.constants import DEVSERVICES_DIR_NAME +from devservices.constants import DependencyType from devservices.exceptions import ConfigError from devservices.exceptions import ConfigNotFoundError from devservices.exceptions import DependencyError @@ -25,17 +25,17 @@ from devservices.exceptions import SupervisorError from devservices.utils.console import Console from devservices.utils.console import Status -from devservices.utils.dependencies import construct_dependency_graph from devservices.utils.dependencies import DependencyNode +from devservices.utils.dependencies import InstalledRemoteDependency +from devservices.utils.dependencies import construct_dependency_graph from devservices.utils.dependencies import get_non_shared_remote_dependencies from devservices.utils.dependencies import install_and_verify_dependencies -from devservices.utils.dependencies import InstalledRemoteDependency from devservices.utils.docker_compose import DockerComposeCommand from devservices.utils.docker_compose import get_docker_compose_commands_to_run from devservices.utils.docker_compose import run_cmd +from devservices.utils.services import Service from devservices.utils.services import find_matching_service from devservices.utils.services import get_active_service_names -from devservices.utils.services import Service from devservices.utils.state import ServiceRuntime from devservices.utils.state import State from devservices.utils.state import StateTables @@ -231,9 +231,9 @@ def bring_down_service( # Set the environment variable for the local dependencies directory to be used by docker compose current_env = os.environ.copy() - current_env[ - DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY - ] = relative_local_dependency_directory + current_env[DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY] = ( + relative_local_dependency_directory + ) state = State() # We want to ignore any dependencies that are set to run locally if we are excluding local dependencies diff --git a/devservices/commands/foreground.py b/devservices/commands/foreground.py index 77ea884c..37e7e0bd 100644 --- a/devservices/commands/foreground.py +++ b/devservices/commands/foreground.py @@ -3,15 +3,15 @@ import os import pty import shlex -from argparse import _SubParsersAction from argparse import ArgumentParser from argparse import Namespace +from argparse import _SubParsersAction from sentry_sdk import capture_exception from devservices.constants import CONFIG_FILE_NAME -from devservices.constants import DependencyType from devservices.constants import DEVSERVICES_DIR_NAME +from devservices.constants import DependencyType from devservices.exceptions import ConfigError from devservices.exceptions import ConfigNotFoundError from devservices.exceptions import ServiceNotFoundError diff --git a/devservices/commands/list_dependencies.py b/devservices/commands/list_dependencies.py index 4b5dc7d7..629f4a91 100644 --- a/devservices/commands/list_dependencies.py +++ b/devservices/commands/list_dependencies.py @@ -1,8 +1,8 @@ from __future__ import annotations -from argparse import _SubParsersAction from argparse import ArgumentParser from argparse import Namespace +from argparse import _SubParsersAction from sentry_sdk import capture_exception diff --git a/devservices/commands/list_services.py b/devservices/commands/list_services.py index 462508ef..67ef1c2c 100644 --- a/devservices/commands/list_services.py +++ b/devservices/commands/list_services.py @@ -1,8 +1,8 @@ from __future__ import annotations -from argparse import _SubParsersAction from argparse import ArgumentParser from argparse import Namespace +from argparse import _SubParsersAction from sentry_sdk import capture_exception diff --git a/devservices/commands/logs.py b/devservices/commands/logs.py index b387c919..f96395f2 100644 --- a/devservices/commands/logs.py +++ b/devservices/commands/logs.py @@ -3,19 +3,19 @@ import concurrent.futures import os import subprocess -from argparse import _SubParsersAction from argparse import ArgumentParser from argparse import Namespace +from argparse import _SubParsersAction from sentry_sdk import capture_exception from devservices.constants import CONFIG_FILE_NAME from devservices.constants import DEPENDENCY_CONFIG_VERSION -from devservices.constants import DependencyType from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY from devservices.constants import DEVSERVICES_DIR_NAME from devservices.constants import MAX_LOG_LINES +from devservices.constants import DependencyType from devservices.exceptions import ConfigError from devservices.exceptions import ConfigNotFoundError from devservices.exceptions import DependencyError @@ -24,13 +24,13 @@ from devservices.exceptions import SupervisorConfigError from devservices.exceptions import SupervisorError from devservices.utils.console import Console -from devservices.utils.dependencies import install_and_verify_dependencies from devservices.utils.dependencies import InstalledRemoteDependency +from devservices.utils.dependencies import install_and_verify_dependencies from devservices.utils.docker_compose import get_docker_compose_commands_to_run from devservices.utils.docker_compose import run_cmd +from devservices.utils.services import Service from devservices.utils.services import find_matching_service from devservices.utils.services import get_active_service_names -from devservices.utils.services import Service from devservices.utils.state import State from devservices.utils.state import StateTables from devservices.utils.supervisor import SupervisorManager @@ -142,9 +142,9 @@ def _logs( ) # Set the environment variable for the local dependencies directory to be used by docker compose current_env = os.environ.copy() - current_env[ - DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY - ] = relative_local_dependency_directory + current_env[DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY] = ( + relative_local_dependency_directory + ) docker_compose_commands = get_docker_compose_commands_to_run( service=service, remote_dependencies=list(remote_dependencies), diff --git a/devservices/commands/purge.py b/devservices/commands/purge.py index 712d4427..142b33cd 100644 --- a/devservices/commands/purge.py +++ b/devservices/commands/purge.py @@ -2,9 +2,9 @@ import os import shutil -from argparse import _SubParsersAction from argparse import ArgumentParser from argparse import Namespace +from argparse import _SubParsersAction from devservices.configs.service_config import load_service_config_from_file from devservices.constants import DEPENDENCY_CONFIG_VERSION diff --git a/devservices/commands/reset.py b/devservices/commands/reset.py index f9d376f9..08bc034d 100644 --- a/devservices/commands/reset.py +++ b/devservices/commands/reset.py @@ -1,20 +1,20 @@ from __future__ import annotations -from argparse import _SubParsersAction from argparse import ArgumentParser from argparse import Namespace +from argparse import _SubParsersAction from sentry_sdk import capture_exception from devservices.commands.down import down -from devservices.constants import DependencyType from devservices.constants import DEVSERVICES_ORCHESTRATOR_LABEL +from devservices.constants import DependencyType from devservices.exceptions import DockerDaemonNotRunningError from devservices.exceptions import DockerError from devservices.utils.console import Console from devservices.utils.console import Status -from devservices.utils.dependencies import construct_dependency_graph from devservices.utils.dependencies import DependencyNode +from devservices.utils.dependencies import construct_dependency_graph from devservices.utils.docker import get_matching_containers from devservices.utils.docker import get_volumes_for_containers from devservices.utils.docker import remove_docker_resources diff --git a/devservices/commands/serve.py b/devservices/commands/serve.py index 516b55b1..62cf7dbc 100644 --- a/devservices/commands/serve.py +++ b/devservices/commands/serve.py @@ -3,9 +3,9 @@ import os import pty import shlex -from argparse import _SubParsersAction from argparse import ArgumentParser from argparse import Namespace +from argparse import _SubParsersAction from sentry_sdk import capture_exception diff --git a/devservices/commands/status.py b/devservices/commands/status.py index 76eab92c..1af80f11 100644 --- a/devservices/commands/status.py +++ b/devservices/commands/status.py @@ -4,22 +4,22 @@ import json import os import subprocess -from argparse import _SubParsersAction from argparse import ArgumentParser from argparse import Namespace +from argparse import _SubParsersAction from collections import namedtuple from datetime import timedelta from typing import TypedDict from sentry_sdk import capture_exception -from devservices.constants import Color from devservices.constants import CONFIG_FILE_NAME from devservices.constants import DEPENDENCY_CONFIG_VERSION -from devservices.constants import DependencyType from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY from devservices.constants import DEVSERVICES_DIR_NAME +from devservices.constants import Color +from devservices.constants import DependencyType from devservices.exceptions import ConfigError from devservices.exceptions import ConfigNotFoundError from devservices.exceptions import DependencyError @@ -27,16 +27,16 @@ from devservices.exceptions import ServiceNotFoundError from devservices.exceptions import SupervisorConfigError from devservices.utils.console import Console -from devservices.utils.dependencies import construct_dependency_graph from devservices.utils.dependencies import DependencyGraph from devservices.utils.dependencies import DependencyNode -from devservices.utils.dependencies import install_and_verify_dependencies from devservices.utils.dependencies import InstalledRemoteDependency +from devservices.utils.dependencies import construct_dependency_graph +from devservices.utils.dependencies import install_and_verify_dependencies from devservices.utils.docker_compose import get_docker_compose_commands_to_run from devservices.utils.docker_compose import run_cmd +from devservices.utils.services import Service from devservices.utils.services import find_matching_service from devservices.utils.services import get_active_service_names -from devservices.utils.services import Service from devservices.utils.state import ServiceRuntime from devservices.utils.state import State from devservices.utils.state import StateTables @@ -180,9 +180,9 @@ def get_status_json_results( ) # Set the environment variable for the local dependencies directory to be used by docker compose current_env = os.environ.copy() - current_env[ - DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY - ] = relative_local_dependency_directory + current_env[DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY] = ( + relative_local_dependency_directory + ) docker_compose_commands = get_docker_compose_commands_to_run( service=service, remote_dependencies=list(remote_dependencies), @@ -316,9 +316,9 @@ def parse_docker_compose_status( docker_compose_service_status ) compose_service = docker_compose_service_status_json["Service"] - docker_compose_service_to_status[ - compose_service - ] = docker_compose_service_status_json + docker_compose_service_to_status[compose_service] = ( + docker_compose_service_status_json + ) return docker_compose_service_to_status diff --git a/devservices/commands/toggle.py b/devservices/commands/toggle.py index 48c3f293..ce01f305 100644 --- a/devservices/commands/toggle.py +++ b/devservices/commands/toggle.py @@ -1,8 +1,8 @@ from __future__ import annotations -from argparse import _SubParsersAction from argparse import ArgumentParser from argparse import Namespace +from argparse import _SubParsersAction from sentry_sdk import capture_exception @@ -19,9 +19,9 @@ from devservices.utils.dependencies import construct_dependency_graph from devservices.utils.dependencies import get_non_shared_remote_dependencies from devservices.utils.dependencies import install_and_verify_dependencies +from devservices.utils.services import Service from devservices.utils.services import find_matching_service from devservices.utils.services import get_active_service_names -from devservices.utils.services import Service from devservices.utils.state import ServiceRuntime from devservices.utils.state import State from devservices.utils.state import StateTables diff --git a/devservices/commands/up.py b/devservices/commands/up.py index 1d101d64..885c49d8 100644 --- a/devservices/commands/up.py +++ b/devservices/commands/up.py @@ -3,9 +3,9 @@ import concurrent.futures import os import subprocess -from argparse import _SubParsersAction from argparse import ArgumentParser from argparse import Namespace +from argparse import _SubParsersAction from sentry_sdk import capture_exception from sentry_sdk import logger as sentry_logger @@ -14,10 +14,10 @@ from devservices.constants import CONFIG_FILE_NAME from devservices.constants import DEPENDENCY_CONFIG_VERSION -from devservices.constants import DependencyType from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY from devservices.constants import DEVSERVICES_DIR_NAME +from devservices.constants import DependencyType from devservices.exceptions import ConfigError from devservices.exceptions import ConfigNotFoundError from devservices.exceptions import ContainerHealthcheckFailedError @@ -29,17 +29,17 @@ from devservices.exceptions import SupervisorError from devservices.utils.console import Console from devservices.utils.console import Status -from devservices.utils.dependencies import construct_dependency_graph from devservices.utils.dependencies import DependencyNode -from devservices.utils.dependencies import install_and_verify_dependencies from devservices.utils.dependencies import InstalledRemoteDependency +from devservices.utils.dependencies import construct_dependency_graph +from devservices.utils.dependencies import install_and_verify_dependencies from devservices.utils.docker import check_all_containers_healthy from devservices.utils.docker_compose import DockerComposeCommand from devservices.utils.docker_compose import get_container_names_for_project from devservices.utils.docker_compose import get_docker_compose_commands_to_run from devservices.utils.docker_compose import run_cmd -from devservices.utils.services import find_matching_service from devservices.utils.services import Service +from devservices.utils.services import find_matching_service from devservices.utils.state import ServiceRuntime from devservices.utils.state import State from devservices.utils.state import StateTables @@ -318,9 +318,9 @@ def bring_up_docker_compose_services( ) # Set the environment variable for the local dependencies directory to be used by docker compose current_env = os.environ.copy() - current_env[ - DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY - ] = relative_local_dependency_directory + current_env[DEVSERVICES_DEPENDENCIES_CACHE_DIR_KEY] = ( + relative_local_dependency_directory + ) dependency_graph = construct_dependency_graph(service, modes=modes) starting_order = dependency_graph.get_starting_order() sorted_remote_dependencies = sorted( diff --git a/devservices/commands/update.py b/devservices/commands/update.py index 52bc035d..04de7ad4 100644 --- a/devservices/commands/update.py +++ b/devservices/commands/update.py @@ -2,9 +2,9 @@ import platform import sys -from argparse import _SubParsersAction from argparse import ArgumentParser from argparse import Namespace +from argparse import _SubParsersAction from importlib import metadata from devservices.constants import DEVSERVICES_DOWNLOAD_URL diff --git a/devservices/configs/service_config.py b/devservices/configs/service_config.py index 44dc8b2e..0932a9f3 100644 --- a/devservices/configs/service_config.py +++ b/devservices/configs/service_config.py @@ -8,8 +8,8 @@ from supervisor.options import ServerOptions from devservices.constants import CONFIG_FILE_NAME -from devservices.constants import DependencyType from devservices.constants import DEVSERVICES_DIR_NAME +from devservices.constants import DependencyType from devservices.exceptions import ConfigNotFoundError from devservices.exceptions import ConfigParseError from devservices.exceptions import ConfigValidationError diff --git a/devservices/utils/console.py b/devservices/utils/console.py index 7531802c..af3a66fd 100644 --- a/devservices/utils/console.py +++ b/devservices/utils/console.py @@ -9,7 +9,6 @@ from devservices.constants import Color - ANIMATION_FRAMES = ("⠟", "⠯", "⠷", "⠾", "⠽", "⠻") diff --git a/devservices/utils/dependencies.py b/devservices/utils/dependencies.py index aa039088..bff00592 100644 --- a/devservices/utils/dependencies.py +++ b/devservices/utils/dependencies.py @@ -7,8 +7,8 @@ import tempfile import time from collections import deque -from concurrent.futures import as_completed from concurrent.futures import ThreadPoolExecutor +from concurrent.futures import as_completed from dataclasses import dataclass from typing import TextIO from typing import TypeGuard @@ -18,16 +18,16 @@ from sentry_sdk import set_context from devservices.configs.service_config import Dependency -from devservices.configs.service_config import load_service_config_from_file from devservices.configs.service_config import RemoteConfig from devservices.configs.service_config import ServiceConfig +from devservices.configs.service_config import load_service_config_from_file from devservices.constants import CONFIG_FILE_NAME from devservices.constants import DEPENDENCY_CONFIG_VERSION from devservices.constants import DEPENDENCY_GIT_PARTIAL_CLONE_CONFIG_OPTIONS -from devservices.constants import DependencyType from devservices.constants import DEVSERVICES_DEPENDENCIES_CACHE_DIR from devservices.constants import DEVSERVICES_DIR_NAME from devservices.constants import LOGGER_NAME +from devservices.constants import DependencyType from devservices.exceptions import ConfigNotFoundError from devservices.exceptions import ConfigParseError from devservices.exceptions import ConfigValidationError @@ -38,9 +38,9 @@ from devservices.exceptions import ModeDoesNotExistError from devservices.exceptions import UnableToCloneDependencyError from devservices.utils.file_lock import lock +from devservices.utils.services import Service from devservices.utils.services import find_matching_service from devservices.utils.services import get_active_service_names -from devservices.utils.services import Service from devservices.utils.state import ServiceRuntime from devservices.utils.state import State from devservices.utils.state import StateTables @@ -316,9 +316,9 @@ def get_non_shared_remote_dependencies( started_service_dependencies: dict[str, Dependency] = dict() for started_service_mode in started_service_modes: for dependency_name in started_service.config.modes[started_service_mode]: - started_service_dependencies[ - dependency_name - ] = started_service.config.dependencies[dependency_name] + started_service_dependencies[dependency_name] = ( + started_service.config.dependencies[dependency_name] + ) installed_remote_dependencies = get_installed_remote_dependencies( list(started_service_dependencies.values()) diff --git a/devservices/utils/docker_compose.py b/devservices/utils/docker_compose.py index 29a64b23..2cc4988e 100644 --- a/devservices/utils/docker_compose.py +++ b/devservices/utils/docker_compose.py @@ -8,8 +8,8 @@ import shlex import subprocess import time -from typing import cast from typing import NamedTuple +from typing import cast from packaging import version from sentry_sdk import logger as sentry_logger @@ -26,8 +26,8 @@ from devservices.exceptions import DockerComposeInstallationError from devservices.utils.console import Console from devservices.utils.dependencies import InstalledRemoteDependency -from devservices.utils.docker import check_docker_daemon_running from devservices.utils.docker import ContainerNames +from devservices.utils.docker import check_docker_daemon_running from devservices.utils.install_binary import install_binary from devservices.utils.services import Service diff --git a/tests/commands/test_down.py b/tests/commands/test_down.py index 307ca35a..529312df 100644 --- a/tests/commands/test_down.py +++ b/tests/commands/test_down.py @@ -14,8 +14,8 @@ from devservices.configs.service_config import RemoteConfig from devservices.configs.service_config import ServiceConfig from devservices.constants import CONFIG_FILE_NAME -from devservices.constants import DependencyType from devservices.constants import DEVSERVICES_DIR_NAME +from devservices.constants import DependencyType from devservices.exceptions import ConfigError from devservices.exceptions import ServiceNotFoundError from devservices.exceptions import SupervisorError diff --git a/tests/commands/test_foreground.py b/tests/commands/test_foreground.py index fc6b4f47..0ca0ce83 100644 --- a/tests/commands/test_foreground.py +++ b/tests/commands/test_foreground.py @@ -8,9 +8,9 @@ import pytest from devservices.commands.foreground import foreground -from devservices.constants import Color from devservices.constants import CONFIG_FILE_NAME from devservices.constants import DEVSERVICES_DIR_NAME +from devservices.constants import Color from devservices.exceptions import ConfigError from devservices.exceptions import ServiceNotFoundError from devservices.exceptions import SupervisorConfigError diff --git a/tests/commands/test_logs.py b/tests/commands/test_logs.py index 5e80e7a0..1583579d 100644 --- a/tests/commands/test_logs.py +++ b/tests/commands/test_logs.py @@ -11,9 +11,9 @@ from devservices.commands.logs import _supervisor_logs from devservices.commands.logs import logs from devservices.configs.service_config import load_service_config_from_file -from devservices.constants import Color from devservices.constants import CONFIG_FILE_NAME from devservices.constants import DEVSERVICES_DIR_NAME +from devservices.constants import Color from devservices.exceptions import DependencyError from devservices.exceptions import DockerComposeError from devservices.exceptions import SupervisorError diff --git a/tests/commands/test_serve.py b/tests/commands/test_serve.py index a93b9768..3bcb5a6b 100644 --- a/tests/commands/test_serve.py +++ b/tests/commands/test_serve.py @@ -9,9 +9,9 @@ import pytest from devservices.commands.serve import serve -from devservices.constants import Color from devservices.constants import CONFIG_FILE_NAME from devservices.constants import DEVSERVICES_DIR_NAME +from devservices.constants import Color from testing.utils import create_config_file diff --git a/tests/commands/test_status.py b/tests/commands/test_status.py index 5e5a3f95..9a0d9079 100644 --- a/tests/commands/test_status.py +++ b/tests/commands/test_status.py @@ -8,6 +8,7 @@ import pytest +from devservices.commands.status import ServiceStatusOutput from devservices.commands.status import format_uptime from devservices.commands.status import generate_service_status_details from devservices.commands.status import generate_service_status_tree @@ -16,14 +17,13 @@ from devservices.commands.status import handle_started_service from devservices.commands.status import parse_docker_compose_status from devservices.commands.status import process_service_with_local_runtime -from devservices.commands.status import ServiceStatusOutput from devservices.commands.status import status from devservices.configs.service_config import Dependency from devservices.configs.service_config import ServiceConfig -from devservices.constants import Color from devservices.constants import CONFIG_FILE_NAME -from devservices.constants import DependencyType from devservices.constants import DEVSERVICES_DIR_NAME +from devservices.constants import Color +from devservices.constants import DependencyType from devservices.exceptions import DependencyError from devservices.exceptions import DockerComposeError from devservices.exceptions import ServiceNotFoundError @@ -210,9 +210,7 @@ def test_generate_service_status_details_missing_status() -> None: dependency, process_statuses, docker_compose_service_to_status, "" ) assert result == ( - f"{Color.BOLD}test-service{Color.RESET}:\n" - " Type: container\n" - " Status: N/A" + f"{Color.BOLD}test-service{Color.RESET}:\n Type: container\n Status: N/A" ) diff --git a/tests/commands/test_toggle.py b/tests/commands/test_toggle.py index ac9f7909..0a06adee 100644 --- a/tests/commands/test_toggle.py +++ b/tests/commands/test_toggle.py @@ -17,8 +17,8 @@ from devservices.configs.service_config import RemoteConfig from devservices.configs.service_config import ServiceConfig from devservices.constants import CONFIG_FILE_NAME -from devservices.constants import DependencyType from devservices.constants import DEVSERVICES_DIR_NAME +from devservices.constants import DependencyType from devservices.exceptions import CannotToggleNonRemoteServiceError from devservices.exceptions import ConfigNotFoundError from devservices.exceptions import ConfigParseError @@ -26,8 +26,8 @@ from devservices.exceptions import DockerComposeError from devservices.exceptions import InvalidDependencyConfigError from devservices.exceptions import ServiceNotFoundError -from devservices.utils.dependencies import install_and_verify_dependencies from devservices.utils.dependencies import InstalledRemoteDependency +from devservices.utils.dependencies import install_and_verify_dependencies from devservices.utils.docker_compose import DockerComposeCommand from devservices.utils.services import Service from devservices.utils.state import ServiceRuntime diff --git a/tests/commands/test_up.py b/tests/commands/test_up.py index b13db1bf..3dc91393 100644 --- a/tests/commands/test_up.py +++ b/tests/commands/test_up.py @@ -14,9 +14,9 @@ from devservices.configs.service_config import Dependency from devservices.configs.service_config import ServiceConfig from devservices.constants import CONFIG_FILE_NAME -from devservices.constants import DependencyType from devservices.constants import DEVSERVICES_DIR_NAME from devservices.constants import HEALTHCHECK_TIMEOUT +from devservices.constants import DependencyType from devservices.exceptions import ConfigError from devservices.exceptions import ContainerHealthcheckFailedError from devservices.exceptions import DependencyError @@ -1005,7 +1005,9 @@ def test_up_mode_simple( assert "Retrieving dependencies" in captured.out.strip() assert ( "Starting dependencies with local runtimes..." not in captured.out.strip() - ), "This shouldn't be printed since we don't have any dependencies with local runtimes" + ), ( + "This shouldn't be printed since we don't have any dependencies with local runtimes" + ) assert ( "Starting 'example-service' dependencies in mode: 'test'" in captured.out.strip() @@ -1094,7 +1096,9 @@ def test_up_mode_does_not_exist( assert "Retrieving dependencies" not in captured.out.strip() assert ( "Starting dependencies with local runtimes..." not in captured.out.strip() - ), "This shouldn't be printed since we don't have any dependencies with local runtimes" + ), ( + "This shouldn't be printed since we don't have any dependencies with local runtimes" + ) assert ( "Starting 'example-service' dependencies in mode: 'test'" not in captured.out.strip() @@ -1209,7 +1213,9 @@ def test_up_multiple_modes( ) assert ( "Starting dependencies with local runtimes..." not in captured.out.strip() - ), "This shouldn't be printed since we don't have any dependencies with local runtimes" + ), ( + "This shouldn't be printed since we don't have any dependencies with local runtimes" + ) assert "Retrieving dependencies" in captured.out.strip() assert "Starting redis" in captured.out.strip() @@ -1380,7 +1386,9 @@ def test_up_multiple_modes_overlapping_running_service( assert "Retrieving dependencies" in captured.out.strip() assert ( "Starting dependencies with local runtimes..." not in captured.out.strip() - ), "This shouldn't be printed since we don't have any dependencies with local runtimes" + ), ( + "This shouldn't be printed since we don't have any dependencies with local runtimes" + ) assert "Starting clickhouse" in captured.out.strip() @@ -1756,7 +1764,9 @@ def test_up_dependency_set_to_local( assert ( "Starting dependencies with local runtimes..." not in captured.out.strip() - ), "This shouldn't be printed since we don't have any dependencies with local runtimes" + ), ( + "This shouldn't be printed since we don't have any dependencies with local runtimes" + ) assert ( captured.out.strip().count( "Skipping 'local-runtime-service' as it is set to run locally" @@ -2069,7 +2079,9 @@ def test_up_nested_dependency_set_to_local( assert ( "Starting dependencies with local runtimes..." not in captured.out.strip() - ), "This shouldn't be printed since we don't have any dependencies with local runtimes" + ), ( + "This shouldn't be printed since we don't have any dependencies with local runtimes" + ) assert ( captured.out.strip().count( "Skipping 'local-runtime-service' as it is set to run locally" @@ -2083,7 +2095,9 @@ def test_up_nested_dependency_set_to_local( assert ( "Skipping 'local-runtime-service' as it is set to run locally" not in captured.out.strip() - ), "This shouldn't be printed since local-runtime-service is being brought up" + ), ( + "This shouldn't be printed since local-runtime-service is being brought up" + ) @mock.patch("devservices.utils.state.State.update_service_entry") @@ -2267,7 +2281,9 @@ def test_up_does_not_bring_up_nested_dependency_if_set_to_local_and_mode_does_no assert ( "Skipping 'local-runtime-service' as it is set to run locally" not in captured.out.strip() - ), "This shouldn't be printed since local-runtime-service is not being brought up" + ), ( + "This shouldn't be printed since local-runtime-service is not being brought up" + ) @mock.patch("devservices.utils.state.State.update_service_entry") @@ -2453,11 +2469,15 @@ def test_up_does_not_bring_up_dependency_if_set_to_local_and_mode_does_not_conta captured = capsys.readouterr() assert ( "Starting dependencies with local runtimes..." not in captured.out.strip() - ), "This shouldn't be printed since other-service isn't being brought up in a mode that includes local-runtime-service" + ), ( + "This shouldn't be printed since other-service isn't being brought up in a mode that includes local-runtime-service" + ) assert ( "Skipping 'local-runtime-service' as it is set to run locally" not in captured.out.strip() - ), "This shouldn't be printed since other-service isn't being brought up in a mode that includes local-runtime-service" + ), ( + "This shouldn't be printed since other-service isn't being brought up in a mode that includes local-runtime-service" + ) @mock.patch("devservices.utils.state.State.remove_service_entry") @@ -2546,7 +2566,9 @@ def test_up_supervisor_program( assert "Retrieving dependencies" in captured.out.strip() assert ( "Starting dependencies with local runtimes..." not in captured.out.strip() - ), "This shouldn't be printed since we don't have any dependencies with local runtimes" + ), ( + "This shouldn't be printed since we don't have any dependencies with local runtimes" + ) assert ( "Starting 'example-service' dependencies in mode: 'default'" in captured.out.strip() @@ -2642,7 +2664,9 @@ def test_up_supervisor_program_error( assert "Retrieving dependencies" in captured.out.strip() assert ( "Starting dependencies with local runtimes..." not in captured.out.strip() - ), "This shouldn't be printed since we don't have any dependencies with local runtimes" + ), ( + "This shouldn't be printed since we don't have any dependencies with local runtimes" + ) assert ( "Starting 'example-service' dependencies in mode: 'default'" in captured.out.strip() diff --git a/tests/configs/test_service_config.py b/tests/configs/test_service_config.py index 57d5dae7..e25fc892 100644 --- a/tests/configs/test_service_config.py +++ b/tests/configs/test_service_config.py @@ -431,7 +431,7 @@ def test_load_service_config_from_file_invalid_yaml(tmp_path: Path) -> None: load_service_config_from_file(str(tmp_path)) assert ( str(e.value) - == f"Error parsing config file: mapping values are not allowed here\n in \"{tmp_path / 'devservices' / 'config.yml'}\", line 2, column 12" + == f'Error parsing config file: mapping values are not allowed here\n in "{tmp_path / "devservices" / "config.yml"}", line 2, column 12' ) diff --git a/tests/utils/test_dependencies.py b/tests/utils/test_dependencies.py index 99131b9f..2e6ed24b 100644 --- a/tests/utils/test_dependencies.py +++ b/tests/utils/test_dependencies.py @@ -15,26 +15,26 @@ from devservices.constants import CONFIG_FILE_NAME from devservices.constants import DEPENDENCY_CONFIG_VERSION from devservices.constants import DEPENDENCY_GIT_PARTIAL_CLONE_CONFIG_OPTIONS -from devservices.constants import DependencyType from devservices.constants import DEVSERVICES_DIR_NAME +from devservices.constants import DependencyType from devservices.exceptions import DependencyError from devservices.exceptions import DependencyNotInstalledError from devservices.exceptions import FailedToSetGitConfigError from devservices.exceptions import InvalidDependencyConfigError from devservices.exceptions import ModeDoesNotExistError from devservices.exceptions import ServiceNotFoundError -from devservices.utils.dependencies import construct_dependency_graph from devservices.utils.dependencies import DependencyNode +from devservices.utils.dependencies import GitConfigManager +from devservices.utils.dependencies import InstalledRemoteDependency +from devservices.utils.dependencies import construct_dependency_graph from devservices.utils.dependencies import get_installed_remote_dependencies from devservices.utils.dependencies import get_non_shared_remote_dependencies -from devservices.utils.dependencies import GitConfigManager from devservices.utils.dependencies import install_and_verify_dependencies from devservices.utils.dependencies import install_dependencies from devservices.utils.dependencies import install_dependency -from devservices.utils.dependencies import InstalledRemoteDependency from devservices.utils.dependencies import verify_local_dependencies -from devservices.utils.services import get_active_service_names from devservices.utils.services import Service +from devservices.utils.services import get_active_service_names from devservices.utils.state import ServiceRuntime from devservices.utils.state import State from devservices.utils.state import StateTables @@ -3417,7 +3417,9 @@ def test_construct_dependency_graph_complex( DependencyNode( name="grandparent-service", dependency_type=DependencyType.SERVICE ) - ), "Grandparent service should come before complex service in the starting order" + ), ( + "Grandparent service should come before complex service in the starting order" + ) @mock.patch( diff --git a/tests/utils/test_docker.py b/tests/utils/test_docker.py index ccfc2d98..06f8729c 100644 --- a/tests/utils/test_docker.py +++ b/tests/utils/test_docker.py @@ -7,17 +7,17 @@ import pytest from freezegun import freeze_time -from devservices.constants import Color from devservices.constants import DEVSERVICES_ORCHESTRATOR_LABEL from devservices.constants import DOCKER_NETWORK_NAME from devservices.constants import HEALTHCHECK_INTERVAL from devservices.constants import HEALTHCHECK_TIMEOUT +from devservices.constants import Color from devservices.exceptions import ContainerHealthcheckFailedError from devservices.exceptions import DockerDaemonNotRunningError from devservices.exceptions import DockerError +from devservices.utils.docker import ContainerNames from devservices.utils.docker import check_all_containers_healthy from devservices.utils.docker import check_docker_daemon_running -from devservices.utils.docker import ContainerNames from devservices.utils.docker import get_matching_containers from devservices.utils.docker import get_matching_networks from devservices.utils.docker import get_volumes_for_containers @@ -390,7 +390,9 @@ def test_wait_for_healthy_initial_check_failed_then_success( mock_status = mock.Mock() mock_check_output.side_effect = ["unhealthy", "healthy"] - with (freeze_time("2024-05-14 00:00:00") as frozen_time,): + with ( + freeze_time("2024-05-14 00:00:00") as frozen_time, + ): mock_sleep.side_effect = lambda _: frozen_time.tick(timedelta(seconds=1)) wait_for_healthy( ContainerNames(name="devservices-container1", short_name="container1"), diff --git a/tests/utils/test_docker_compose.py b/tests/utils/test_docker_compose.py index 8a85698d..e6db2099 100644 --- a/tests/utils/test_docker_compose.py +++ b/tests/utils/test_docker_compose.py @@ -16,8 +16,8 @@ from devservices.exceptions import DockerDaemonNotRunningError from devservices.utils.dependencies import InstalledRemoteDependency from devservices.utils.docker import ContainerNames -from devservices.utils.docker_compose import check_docker_compose_version from devservices.utils.docker_compose import DockerComposeCommand +from devservices.utils.docker_compose import check_docker_compose_version from devservices.utils.docker_compose import get_container_names_for_project from devservices.utils.docker_compose import get_docker_compose_commands_to_run from devservices.utils.docker_compose import get_docker_compose_version diff --git a/tests/utils/test_services.py b/tests/utils/test_services.py index 1f5a136f..777d1b7a 100644 --- a/tests/utils/test_services.py +++ b/tests/utils/test_services.py @@ -9,9 +9,9 @@ from devservices.configs.service_config import ServiceConfig from devservices.exceptions import ConfigParseError from devservices.exceptions import ServiceNotFoundError +from devservices.utils.services import Service from devservices.utils.services import find_matching_service from devservices.utils.services import get_local_services -from devservices.utils.services import Service from testing.utils import create_mock_git_repo From cc57fbe3b08609113eb4d2f4833cdca3c8c96ecb Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 12 Mar 2026 15:44:24 -0700 Subject: [PATCH 10/11] 3.12.13 --- .github/workflows/test.yml | 2 +- .python-version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a0e41e50..ce59e5ee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.11.14", "3.12.12"] + python-version: ["3.11.14", "3.12.13"] steps: - name: Configure git run: | diff --git a/.python-version b/.python-version index 763b6264..28d9a01b 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.12.12 +3.12.13 From 161ab84530f330f21b82690f3cc186368c3f83bb Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Thu, 12 Mar 2026 16:02:05 -0700 Subject: [PATCH 11/11] fixes --- .envrc | 8 ++++---- .github/workflows/build.yml | 4 ---- README.md | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/.envrc b/.envrc index 14cccebe..600c1e0f 100644 --- a/.envrc +++ b/.envrc @@ -7,10 +7,10 @@ fi PATH_add "$PWD/.venv/bin" export VIRTUAL_ENV="$PWD/.venv" -if [[ ! -f .git/hooks/pre-commit ]] || ! grep -q pre-commit .git/hooks/pre-commit 2>/dev/null; then - pre-commit install --install-hooks -fi - if [ ! -d .venv ]; then uv sync fi + +if [[ ! -f .git/hooks/pre-commit ]] || ! grep -q pre-commit .git/hooks/pre-commit 2>/dev/null; then + pre-commit install --install-hooks +fi diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a8b2474c..57202545 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,10 +40,6 @@ jobs: steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1 - with: - python-version-file: .python-version - - uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7.5.0 - name: Generate metadata diff --git a/README.md b/README.md index 02765bd1..91fdfda8 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,6 @@ networks: ```sh uv sync -denv allow +direnv allow pytest ```