diff --git a/.github/actions/python-maturin/pre-merge/action.yml b/.github/actions/python-maturin/pre-merge/action.yml index 65b0d40af7..3376fc3eca 100644 --- a/.github/actions/python-maturin/pre-merge/action.yml +++ b/.github/actions/python-maturin/pre-merge/action.yml @@ -83,6 +83,10 @@ runs: echo "Running mypy on SDK..." uv run mypy --explicit-package-bases "$DIR_SDK" echo "mypy version: $(uv run mypy --version)" + + echo "Running pyrefly on SDK..." + uv run pyrefly check + echo "pyrefly version: $(uv run pyrefly --version)" shell: bash - name: Build Python wheel with coverage instrumentation diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8e7909a540..b52434e80c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -87,6 +87,20 @@ repos: files: ^(foreign|bdd|examples)/python/(pyproject\.toml|uv\.lock)$ pass_filenames: false + - id: uv-audit + name: uv audit (python dependencies) + entry: ./scripts/ci/uv-audit.sh + language: system + files: ^(foreign|bdd|examples)/python/(pyproject\.toml|uv\.lock)$ + pass_filenames: false + + - id: pyrefly + name: pyrefly (python sdk) + entry: ./scripts/ci/pyrefly-check.sh + language: system + files: ^foreign/python/(tests/.*\.py|apache_iggy\.pyi|pyproject\.toml)$ + pass_filenames: false + - id: version-consistency name: version consistency entry: ./scripts/extract-version.sh diff --git a/bdd/python/uv.lock b/bdd/python/uv.lock index d630ddefe9..14aec10804 100644 --- a/bdd/python/uv.lock +++ b/bdd/python/uv.lock @@ -18,6 +18,8 @@ requires-dist = [ { name = "maturin", marker = "extra == 'dev'", specifier = ">=1.2,<2.0" }, { name = "mypy", marker = "extra == 'all'", specifier = ">=1.5.0,<2.0" }, { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.5.0,<2.0" }, + { name = "pyrefly", marker = "extra == 'all'", specifier = ">=1.0.0,<2.0" }, + { name = "pyrefly", marker = "extra == 'dev'", specifier = ">=1.0.0,<2.0" }, { name = "pytest", marker = "extra == 'all'", specifier = ">=9.0.3,<10.0" }, { name = "pytest", marker = "extra == 'testing'", specifier = ">=9.0.3,<10.0" }, { name = "pytest-asyncio", marker = "extra == 'all'", specifier = ">=0.24.0,<2.0" }, diff --git a/examples/python/uv.lock b/examples/python/uv.lock index b4119c736f..6f707a58b4 100644 --- a/examples/python/uv.lock +++ b/examples/python/uv.lock @@ -18,6 +18,8 @@ requires-dist = [ { name = "maturin", marker = "extra == 'dev'", specifier = ">=1.2,<2.0" }, { name = "mypy", marker = "extra == 'all'", specifier = ">=1.5.0,<2.0" }, { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.5.0,<2.0" }, + { name = "pyrefly", marker = "extra == 'all'", specifier = ">=1.0.0,<2.0" }, + { name = "pyrefly", marker = "extra == 'dev'", specifier = ">=1.0.0,<2.0" }, { name = "pytest", marker = "extra == 'all'", specifier = ">=9.0.3,<10.0" }, { name = "pytest", marker = "extra == 'testing'", specifier = ">=9.0.3,<10.0" }, { name = "pytest-asyncio", marker = "extra == 'all'", specifier = ">=0.24.0,<2.0" }, diff --git a/foreign/python/pyproject.toml b/foreign/python/pyproject.toml index e5c6506da9..208c4f11e7 100644 --- a/foreign/python/pyproject.toml +++ b/foreign/python/pyproject.toml @@ -78,6 +78,10 @@ include = [ ] }, ] +[tool.uv] +exclude-newer = "7 days" +exclude-newer-package = { urllib3 = false, pyrefly = false } + [project.optional-dependencies] # Core testing dependencies testing = [ @@ -97,6 +101,7 @@ dev = [ "black>=23.0,<27.0", "isort>=5.12.0,<6.0", "mypy>=1.5.0,<2.0", + "pyrefly>=1.0.0,<2.0", "ruff>=0.1.0,<1.0", ] @@ -113,9 +118,17 @@ all = [ "black>=23.0,<27.0", "isort>=5.12.0,<6.0", "mypy>=1.5.0,<2.0", + "pyrefly>=1.0.0,<2.0", "ruff>=0.1.0,<1.0", ] +[tool.pyrefly] +python-version = "3.10.0" +preset = "legacy" +project-includes = ["tests", "apache_iggy.pyi"] +disable-search-path-heuristics = true +search-path = ["."] + [tool.pytest.ini_options] asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "session" diff --git a/foreign/python/uv.lock b/foreign/python/uv.lock index 857bf74f69..1c1a85fe6c 100644 --- a/foreign/python/uv.lock +++ b/foreign/python/uv.lock @@ -2,6 +2,14 @@ version = 1 revision = 3 requires-python = ">=3.10" +[options] +exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for backwards compatibility when using relative exclude-newer values. +exclude-newer-span = "P7D" + +[options.exclude-newer-package] +pyrefly = false +urllib3 = false + [[package]] name = "apache-iggy" version = "0.8.0" @@ -14,6 +22,7 @@ all = [ { name = "loguru" }, { name = "maturin" }, { name = "mypy" }, + { name = "pyrefly" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-cov" }, @@ -27,6 +36,7 @@ dev = [ { name = "isort" }, { name = "maturin" }, { name = "mypy" }, + { name = "pyrefly" }, { name = "ruff" }, ] testing = [ @@ -51,6 +61,8 @@ requires-dist = [ { name = "maturin", marker = "extra == 'dev'", specifier = ">=1.2,<2.0" }, { name = "mypy", marker = "extra == 'all'", specifier = ">=1.5.0,<2.0" }, { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.5.0,<2.0" }, + { name = "pyrefly", marker = "extra == 'all'", specifier = ">=1.0.0,<2.0" }, + { name = "pyrefly", marker = "extra == 'dev'", specifier = ">=1.0.0,<2.0" }, { name = "pytest", marker = "extra == 'all'", specifier = ">=9.0.3,<10.0" }, { name = "pytest", marker = "extra == 'testing'", specifier = ">=9.0.3,<10.0" }, { name = "pytest-asyncio", marker = "extra == 'all'", specifier = ">=0.24.0,<2.0" }, @@ -642,6 +654,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] +[[package]] +name = "pyrefly" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9f/3a/9045b0097ac58979c7c30a4fa0e673db942d4adbc7b6d439bd54ae58c441/pyrefly-1.0.0.tar.gz", hash = "sha256:5c2b810ffcebd84be71de5df1223651edee951653a66935c6f091e957c452455", size = 5677995, upload-time = "2026-05-12T20:12:46.812Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/c6/90788819bac9c61dd7bacba53b79f3c12d47ccbe5e51b3d6d89f2387e1d2/pyrefly-1.0.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e355a0908555348ed4b9585ef25c76ff566673e345c866c325f1633f44d890b6", size = 13122950, upload-time = "2026-05-12T20:12:20.711Z" }, + { url = "https://files.pythonhosted.org/packages/82/91/a3cf2a1e87d336eaa804a1e6fc93266faf6dc2a97eecdbc7eae289628022/pyrefly-1.0.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a7038efc3a40f8294edee339895633cf22db268c0d434cdbcbefc34f78a9ecc3", size = 12599494, upload-time = "2026-05-12T20:12:23.495Z" }, + { url = "https://files.pythonhosted.org/packages/cd/ab/74d1e11e737e99b1c003ecc5d7d2e846c4ea1f328966bfdbbd0ac63fad0a/pyrefly-1.0.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da331ca515ed1c08791da2b5f664cf9c1294c48fd802133262e7d5d51e0f4416", size = 12995507, upload-time = "2026-05-12T20:12:25.951Z" }, + { url = "https://files.pythonhosted.org/packages/7c/ac/2df0899f8464c97e5d995f994c97c5cb5b0f58610432aa90d26d924e1db5/pyrefly-1.0.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c74219d8f3e63cdaa5501a0b21d1c9d37011820f9606728d0ed06f09ae86a878", size = 13947693, upload-time = "2026-05-12T20:12:29.188Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3e/b247c24321e36f04b7d51f9ccf3df93e5009e4b29939524b36ec2e17dc2a/pyrefly-1.0.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0d05543b1bb6ee6d64149eb5d6b2fb15aa72d3962d6a97abca0afaca8b0c131", size = 13925803, upload-time = "2026-05-12T20:12:31.904Z" }, + { url = "https://files.pythonhosted.org/packages/61/16/cfa2d61a4aa1e1f7bca48bb37acd01c6a09db4864b16a54f9587092765ff/pyrefly-1.0.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1382d5b1fcdb49a4de9f34d112d2bddf290a78ff93ee8149492ad5f1077ddffc", size = 13470398, upload-time = "2026-05-12T20:12:35.302Z" }, + { url = "https://files.pythonhosted.org/packages/cb/2b/6372c7dddb326223e24a46b17efd0d4bd7b4fe22c821e523157577eed2d2/pyrefly-1.0.0-py3-none-win32.whl", hash = "sha256:aa8b5d0e47080e3202a2547b39f7a5a61d2c781c712b3b67884f745ca2c759d2", size = 12222643, upload-time = "2026-05-12T20:12:38.618Z" }, + { url = "https://files.pythonhosted.org/packages/be/ad/1d23be700b6b2ddaeb362360c7145917a8edbbf7240ae428d40541772fce/pyrefly-1.0.0-py3-none-win_amd64.whl", hash = "sha256:c8abcb0f2082e83c890375128f9cff4aa4d3f210b85eea7b3046c1ae764e77f5", size = 13146369, upload-time = "2026-05-12T20:12:41.423Z" }, + { url = "https://files.pythonhosted.org/packages/8c/38/16589134f3012fd097a10dcc85771555f1a5fb76e04b682597180743af30/pyrefly-1.0.0-py3-none-win_arm64.whl", hash = "sha256:d150fa9e40e8392832be81c3bcfc0497c146674ce4d0f8e04e1ec29e775ffb8c", size = 12538326, upload-time = "2026-05-12T20:12:43.996Z" }, +] + [[package]] name = "pytest" version = "9.0.3" diff --git a/scripts/ci/pyrefly-check.sh b/scripts/ci/pyrefly-check.sh new file mode 100755 index 0000000000..377bf7efd2 --- /dev/null +++ b/scripts/ci/pyrefly-check.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +set -euo pipefail + +RED='\033[0;31m' +YELLOW='\033[1;33m' +NC='\033[0m' + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" + +if ! command -v uv >/dev/null 2>&1; then + echo -e "${RED}Error: uv is required but not installed${NC}" + echo -e "${YELLOW}Install with: curl -LsSf https://astral.sh/uv/install.sh | sh${NC}" + echo -e "${YELLOW}Or use: brew install uv${NC}" + exit 127 +fi + +cd "$REPO_ROOT/foreign/python" +uv run pyrefly check diff --git a/scripts/ci/uv-audit.sh b/scripts/ci/uv-audit.sh new file mode 100755 index 0000000000..0717cdc6bb --- /dev/null +++ b/scripts/ci/uv-audit.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +set -euo pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$REPO_ROOT" + +if ! command -v uv >/dev/null 2>&1; then + echo -e "${RED}Error: uv is required but not installed${NC}" + echo -e "${YELLOW}Install with: curl -LsSf https://astral.sh/uv/install.sh | sh${NC}" + echo -e "${YELLOW}Or use: brew install uv${NC}" + exit 127 +fi + +PYTHON_DIRS=( + "foreign/python" + "bdd/python" + "examples/python" +) + +FAILED=0 + +for dir in "${PYTHON_DIRS[@]}"; do + if [ ! -f "$dir/uv.lock" ]; then + continue + fi + + echo -e "${GREEN}uv audit: $dir${NC}" + if ! (cd "$dir" && uv audit --frozen --preview-features audit); then + FAILED=1 + fi +done + +if [ "$FAILED" -ne 0 ]; then + echo "" + echo -e "${RED}uv audit reported vulnerabilities (see output above)${NC}" + exit 1 +fi