diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ee289de..fe5ee154 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,31 +21,35 @@ env: FORCE_COLOR: 3 jobs: + cache-pixi-lock: + uses: Parcels-code/Parcels/.github/workflows/cache-pixi-lock.yml@58cdd6185b3af03785c567914a070288ffd804e0 + tests: - name: tests (${{ matrix.runs-on }} | Python ${{ matrix.python-version }}) + name: "Unit tests: ${{ matrix.runs-on }} | pixi run -e ${{ matrix.pixi-environment }} tests" runs-on: ${{ matrix.runs-on }} + needs: cache-pixi-lock strategy: fail-fast: false matrix: - python-version: ["3.10", "3.12"] + pixi-environment: ["test-py310", "test-py312"] runs-on: [ubuntu-latest, windows-latest, macos-14] steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: mamba-org/setup-micromamba@v2 + - uses: actions/cache/restore@v4 with: - environment-name: ship - environment-file: environment.yml - create-args: >- - python=${{matrix.python-version}} - - - run: pip install . --no-deps + path: pixi.lock + key: ${{ needs.cache-pixi-lock.outputs.cache-id }} + - uses: prefix-dev/setup-pixi@v0.9.0 + with: + cache: true + cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - name: Test package - run: >- - python -m pytest -ra --cov --cov-report=xml --cov-report=term + run: + pixi run -e ${{ matrix.pixi-environment }} tests -ra --cov --cov-report=xml --cov-report=term --durations=20 - name: Upload coverage report @@ -53,24 +57,23 @@ jobs: with: token: ${{ secrets.CODECOV_TOKEN }} typechecking: - name: mypy + name: "TypeChecking: pixi run typing" runs-on: ubuntu-latest + needs: cache-pixi-lock steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: mamba-org/setup-micromamba@v2 + - uses: actions/cache/restore@v4 with: - environment-name: ship - environment-file: environment.yml - create-args: >- - python=3.12 - - - run: pip install . --no-deps - - run: conda install lxml # dep for report generation + path: pixi.lock + key: ${{ needs.cache-pixi-lock.outputs.cache-id }} + - uses: prefix-dev/setup-pixi@v0.9.0 + with: + cache: true + cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - name: Typechecking - run: | - mypy --install-types --non-interactive src/virtualship --html-report mypy-report + run: pixi run typing --non-interactive --html-report mypy-report - name: Upload test results if: ${{ always() }} # Upload even on mypy error uses: actions/upload-artifact@v4 diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 1c13b28a..a8b751be 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,18 +1,17 @@ -# Read the Docs configuration file -# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details - version: 2 -sphinx: - configuration: docs/conf.py build: - os: ubuntu-22.04 + os: ubuntu-lts-latest tools: - python: mambaforge-22.9 + python: "latest" # just so RTD stops complaining jobs: - pre_build: - - pip install . - - sphinx-build -b linkcheck docs/ _build/linkcheck - - sphinx-apidoc -o docs/api/ --module-first --no-toc --force src/virtualship - -conda: - environment: environment.yml + create_environment: + - asdf plugin add pixi + - asdf install pixi latest + - asdf global pixi latest + install: + - pixi install -e docs + build: + html: + - pixi run -e docs sphinx-build -T -b html docs $READTHEDOCS_OUTPUT/html +sphinx: + configuration: docs/conf.py diff --git a/README.md b/README.md index b9a59e70..2444bc70 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ +[![Pixi Badge](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/prefix-dev/pixi/main/assets/badge/v0.json)](https://pixi.sh) [![Anaconda-release](https://anaconda.org/conda-forge/virtualship/badges/version.svg)](https://anaconda.org/conda-forge/virtualship/) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/virtualship) [![DOI](https://zenodo.org/badge/682478059.svg)](https://doi.org/10.5281/zenodo.14013931) diff --git a/docs/contributing/index.md b/docs/contributing/index.md index 27d6d40c..171d714e 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -8,36 +8,66 @@ We have a design document providing a conceptual overview of VirtualShip. This d ### Development installation -We use `conda` to manage our development installation. Make sure you have `conda` installed by following [the instructions here](https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html) and then run the following commands: +```{note} +VirtualShip uses [Pixi](https://pixi.sh) to manage environments and run developer tooling. Pixi is a modern alternative to Conda and also includes other powerful tooling useful for a project like VirtualShip. It is our sole development workflow - we do not offer a Conda development workflow. Give Pixi a try, you won't regret it! +``` + +To get started contributing to VirtualShip: + +**Step 1:** [Install Pixi](https://pixi.sh/latest/). + +**Step 2:** [Fork the repository](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo#forking-a-repository) + +**Step 3:** Clone your fork and `cd` into the repository. + +**Step 4:** Install the Pixi environment ```bash -conda create -n ship python=3.10 -conda activate ship -conda env update --file environment.yml -pip install -e . --no-deps --no-build-isolation +pixi install ``` -This creates an environment, and installs all the dependencies that you need for development, including: +Now you have a development installation of VirtualShip, as well as a bunch of developer tooling to run tests, check code quality, and build the documentation! Simple as that. + +### Pixi workflows + +You can use the following Pixi commands to run common development tasks. -- core dependencies -- development dependencies (e.g., for testing) -- documentation dependencies +**Testing** -then installs the package in editable mode. +- `pixi run tests` - Run the full test suite using pytest with coverage reporting +- `pixi run tests-notebooks` - Run notebook tests -### Useful commands +**Documentation** -The following commands are useful for local development: +- `pixi run docs` - Build the documentation using Sphinx +- `pixi run docs-watch` - Build and auto-rebuild documentation when files change (useful for live editing) -- `pytest` to run tests -- `pre-commit run --all-files` to run pre-commit checks -- `pre-commit install` (optional) to install pre-commit hooks - - this means that every time you commit, pre-commit checks will run on the files you changed -- `sphinx-autobuild docs docs/_build` to build and serve the documentation -- `sphinx-apidoc -o docs/api/ --module-first --no-toc --force src/virtualship` (optional) to generate the API documentation -- `sphinx-build -b linkcheck docs/ _build/linkcheck` to check for broken links in the documentation +**Code quality** -The running of these commands is useful for local development and quick iteration, but not _vital_ as they will be run automatically in the CI pipeline (`pre-commit` by pre-commit.ci, `pytest` by GitHub Actions, and `sphinx` by ReadTheDocs). +- `pixi run lint` - Run pre-commit hooks on all files (includes formatting, linting, and other code quality checks) +- `pixi run typing` - Run mypy type checking on the codebase + +**Different environments** + +VirtualShip supports testing against different environments (e.g., different Python versions) with different feature sets. In CI we test against these environments, and you can too locally. For example: + +- `pixi run -e test-py310 tests` - Run tests using Python 3.10 +- `pixi run -e test-py311 tests` - Run tests using Python 3.11 +- `pixi run -e test-py312 tests` - Run tests using Python 3.12 + +The name of the workflow on GitHub contains the command you have to run locally to recreate the workflow - making it super easy to reproduce CI failures locally. + +**Typical development workflow** + +1. Make your code changes +2. Run `pixi run lint` to ensure code formatting and style compliance +3. Run `pixi run tests` to verify your changes don't break existing functionality +4. If you've added new features, run `pixi run typing` to check type annotations +5. If you've modified documentation, run `pixi run docs` to build and verify the docs + +```{tip} +You can run `pixi info` to see all available environments and `pixi task list` to see all available tasks across environments. +``` ## For maintainers @@ -52,5 +82,5 @@ The running of these commands is useful for local development and quick iteratio When adding a dependency, make sure to modify the following files where relevant: -- `environment.yml` for core and development dependencies (important for the development environment, and CI) +- `pixi.toml` for core and development dependencies (important for the development environment, and CI) - `pyproject.toml` for core dependencies (important for the pypi package, this should propagate through automatically to `recipe/meta.yml` in the conda-forge feedstock) diff --git a/environment.yml b/environment.yml deleted file mode 100644 index e15b21d0..00000000 --- a/environment.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: ship -channels: - - conda-forge -dependencies: - - click - - parcels >3.1.0 - - pyproj >= 3, < 4 - - sortedcontainers == 2.4.0 - - opensimplex == 0.4.5 - - numpy >=1, < 2 - - pydantic >=2, <3 - - pip - - pyyaml - - copernicusmarine >= 2.2.2 - - openpyxl - - yaspin - - textual - - # linting - - pre-commit - - mypy - - # Testing - - pytest - - pytest-cov - - pytest-asyncio - - codecov - - seabird - - setuptools - - # Docs - - sphinx>=7.0 - - myst-parser>=0.13 - - nbsphinx - - ipykernel - - pandoc - - sphinx-copybutton - # - sphinx-autodoc-typehints # https://github.com/OceanParcels/virtualship/pull/125#issuecomment-2668766302 - - pydata-sphinx-theme - - sphinx-autobuild diff --git a/pixi.toml b/pixi.toml new file mode 100644 index 00000000..8164d2d4 --- /dev/null +++ b/pixi.toml @@ -0,0 +1,95 @@ +[workspace] +name = "VirtualShip" +preview = ["pixi-build"] +channels = ["conda-forge"] +platforms = ["win-64", "linux-64", "osx-64", "osx-arm64"] + +[package] +name = "virtualship" +version = "dynamic" # dynamic versioning needs better support in pixi https://github.com/prefix-dev/pixi/issues/2923#issuecomment-2598460666 . Putting `version = "dynamic"` here for now until pixi recommends something else. +license = "MIT" # can remove this once https://github.com/prefix-dev/pixi-build-backends/issues/397 is resolved + +[package.build] +backend = { name = "pixi-build-python", version = "==0.4.0" } + +[package.host-dependencies] +setuptools = "*" +setuptools_scm = "*" + +[environments] +test-latest = { features = ["test"], solve-group = "test" } +test-py310 = { features = ["test", "py310"] } +test-py311 = { features = ["test", "py311"] } +test-py312 = { features = ["test", "py312"] } +test-notebooks = { features = ["test", "notebooks"], solve-group = "test" } +docs = { features = ["docs"], solve-group = "docs" } +typing = { features = ["typing"], solve-group = "typing" } +pre-commit = { features = ["pre-commit"], no-default-feature = true } + +[dependencies] # keep section in sync with pyproject.toml dependencies +python = ">=3.10" +click = "*" +parcels = ">3.1.0" +pyproj = ">=3,<4" +sortedcontainers = "==2.4.0" +opensimplex = "==0.4.5" +numpy = ">=1,<2" +pydantic = ">=2,<3" +pyyaml = "*" +copernicusmarine = ">=2.2.2" +yaspin = "*" +textual = "*" +virtualship = { path = "." } + +[feature.py310.dependencies] +python = "3.10.*" + +[feature.py311.dependencies] +python = "3.11.*" + +[feature.py312.dependencies] +python = "3.12.*" + +[feature.test.dependencies] +pytest = "*" +pytest-cov = "*" +pytest-asyncio = "*" +seabird = "*" +openpyxl = "*" + +[feature.test.tasks] +tests = "pytest" + +[feature.notebooks.dependencies] +nbval = "*" +ipykernel = "*" + +[feature.notebooks.tasks] +tests-notebooks = "pytest --nbval-lax docs/" + +[feature.docs.dependencies] +sphinx = ">=7.0" +myst-parser = ">=0.13" +nbsphinx = "*" +ipykernel = "*" +pandoc = "*" +sphinx-copybutton = "*" +pydata-sphinx-theme = "*" +sphinx-autobuild = "*" + +[feature.docs.tasks] +docs = "sphinx-build docs docs/_build" +docs-watch = "sphinx-autobuild docs docs/_build" + +[feature.pre-commit.dependencies] +pre_commit = "*" + +[feature.pre-commit.tasks] +lint = "pre-commit run --all-files" + +[feature.typing.dependencies] +mypy = "*" +lxml = "*" + +[feature.typing.tasks] +typing = "mypy src/virtualship --install-types"