diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml new file mode 100644 index 00000000..a4065625 --- /dev/null +++ b/.github/workflows/python-test.yml @@ -0,0 +1,100 @@ +name: Python Tests +on: + push: + branches: + - main + pull_request: + paths: + - python/** + - rust/lance-graph/** + - .github/workflows/python-test.yml + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: "-C debuginfo=1" + +jobs: + test: + runs-on: ubuntu-24.04 + timeout-minutes: 30 + strategy: + matrix: + python-version: ["3.11"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Setup Rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + - uses: Swatinem/rust-cache@v2 + with: + workspaces: python + - name: Install dependencies + run: | + sudo apt update + sudo apt install -y protobuf-compiler + - name: Install uv + uses: astral-sh/setup-uv@v3 + - name: Create virtual environment and install dependencies + working-directory: python + run: | + uv venv + source .venv/bin/activate + uv pip install maturin[patchelf] + uv pip install -e .[tests] + - name: Build Python extension + working-directory: python + run: | + source .venv/bin/activate + maturin develop + - name: Run tests + working-directory: python + run: | + source .venv/bin/activate + pytest python/tests/ -v + - name: Run doctests + working-directory: python + run: | + source .venv/bin/activate + if [ -f python/lance_graph/__init__.py ]; then + python -m doctest python/lance_graph/__init__.py || echo "No doctests found" + fi + + lint: + runs-on: ubuntu-24.04 + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + - name: Install uv + uses: astral-sh/setup-uv@v3 + - name: Install dependencies + working-directory: python + run: | + uv venv + source .venv/bin/activate + uv pip install -e .[dev] + - name: Run ruff format check + working-directory: python + run: | + source .venv/bin/activate + ruff format --check python/ + - name: Run ruff lint + working-directory: python + run: | + source .venv/bin/activate + ruff check python/ + - name: Run pyright type check + working-directory: python + run: | + source .venv/bin/activate + pyright \ No newline at end of file diff --git a/README.md b/README.md index d01aee1d..5b6d0d0b 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,11 @@ cargo test ```bash cd python uv venv --python 3.11 .venv # create the local virtualenv +source .venv/bin/activate # activate the virtual environment +uv pip install maturin[patchelf] # install build tool uv pip install -e '.[tests]' # editable install with test extras -uv run --extra tests pytest python/python/tests/test_graph.py +maturin develop # build and install the Rust extension +pytest python/tests/ -v # run the test suite ``` > If another virtual environment is already active, run `deactivate` (or @@ -59,11 +62,19 @@ result = query.execute({"Person": people}) print(result.to_pydict()) # {'name': ['Bob', 'David'], 'age': [34, 42]} ``` -Optional linters and type checks: +### Development workflow + +For linting and type checks: ```bash -uv run --extra dev ruff check python -uv run --extra dev pyright +# Install dev dependencies and run linters +uv pip install -e '.[dev]' +ruff format python/ # format code +ruff check python/ # lint code +pyright # type check + +# Or run individual tests +pytest python/tests/test_graph.py::test_basic_node_selection -v ``` The Python README (`python/README.md`) contains additional details if you are diff --git a/python/README.md b/python/README.md index 936bc6a4..0230dcd4 100644 --- a/python/README.md +++ b/python/README.md @@ -9,15 +9,31 @@ to manage dependencies inside a project-local `.venv`. ```bash cd python uv venv --python 3.11 .venv +source .venv/bin/activate +uv pip install maturin[patchelf] uv pip install -e '.[tests]' -uv run --extra tests pytest python/python/tests/test_graph.py +maturin develop +pytest python/tests/ -v ``` -For linting and type checks install the optional `dev` extra: +## Development workflow + +For linting and type checks: ```bash -uv run --extra dev ruff check python -uv run --extra dev pyright +# Install dev dependencies +uv pip install -e '.[dev]' + +# Run linters and type checker +ruff format python/ # format code +ruff check python/ # lint code +pyright # type check + +# Run specific tests +pytest python/tests/test_graph.py::test_basic_node_selection -v + +# Rebuild extension after Rust changes +maturin develop ``` > If another virtual environment is already active, run `deactivate` (or diff --git a/python/python/lance_graph/__init__.py b/python/python/lance_graph/__init__.py index da3e9edd..df588096 100644 --- a/python/python/lance_graph/__init__.py +++ b/python/python/lance_graph/__init__.py @@ -5,7 +5,10 @@ import importlib.util import sys from pathlib import Path -from types import ModuleType +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from types import ModuleType def _load_bindings() -> ModuleType: diff --git a/python/python/tests/test_graph.py b/python/python/tests/test_graph.py index 404dbc5c..9635b5b1 100644 --- a/python/python/tests/test_graph.py +++ b/python/python/tests/test_graph.py @@ -3,7 +3,6 @@ import pyarrow as pa import pytest - from lance_graph import CypherQuery, GraphConfig