Skip to content

Commit

Permalink
Merge pull request #589 from pyinat/uv
Browse files Browse the repository at this point in the history
Convert project & packaging config to uv
  • Loading branch information
JWCook authored Jan 18, 2025
2 parents 1082d8a + b7242d5 commit 32cd325
Show file tree
Hide file tree
Showing 10 changed files with 2,824 additions and 3,373 deletions.
13 changes: 5 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ on:
workflow_dispatch:
env:
LATEST_PY_VERSION: '3.13'
COVERAGE_ARGS: '--cov --cov-report=term --cov-report=xml'
XDIST_ARGS: '--numprocesses=auto'
PYTEST_VERBOSE: 'true'

jobs:
# Run unit tests for each supported python version
Expand All @@ -26,24 +25,22 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- uses: snok/[email protected]
with:
virtualenvs-in-project: true
- uses: yezz123/setup-uv@v4

# Cache packages per python version, and reuse until lockfile changes
- name: Cache python packages
id: cache
uses: actions/cache@v4
with:
path: .venv
key: venv-${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}
key: venv-${{ matrix.python-version }}-${{ hashFiles('uv.lock') }}
- name: Install dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: poetry install -v -E all
run: uv sync

# Run tests with coverage report
- name: Run tests
run: poetry run pytest -rs -x -vv ${{ env.XDIST_ARGS }} ${{ env.COVERAGE_ARGS }}
run: uv run nox -e cov -- xml

# Latest python version: send coverage report to codecov
- name: "Upload coverage report to Codecov"
Expand Down
22 changes: 6 additions & 16 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,30 +27,20 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: ${{ env.LATEST_PY_VERSION }}
- uses: snok/[email protected]
with:
virtualenvs-in-project: true
- uses: yezz123/setup-uv@v4

- name: Set pre-release version
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
env:
pre-release-suffix: ${{ github.event.inputs.pre-release-suffix || 'dev' }}
pre-release-version: ${{ github.event.inputs.pre-release-version || github.run_number }}
run: |
poetry version $(poetry version -s).${{ env.pre-release-suffix }}${{ env.pre-release-version }}
poetry version
PKG_VERSION=$(uvx --from=toml-cli toml get --toml-path=pyproject.toml project.version)
DEV_VERSION=$PKG_VERSION.${{ env.pre-release-suffix }}${{ env.pre-release-version }}
echo "Setting pre-release version to $DEV_VERSION"
uvx --from=toml-cli toml set --toml-path=pyproject.toml project.version $DEV_VERSION
- name: Build package distributions
run: poetry build
run: uvx --from build pyproject-build --installer uv
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

# Notify Docker image repo that there's a new release available
#- name: Repository Dispatch
# if: ${{ startsWith(github.ref, 'refs/tags/v') }}
# uses: peter-evans/repository-dispatch@v1
# with:
# token: ${{ secrets.DOCKERHUB_TRIGGER_TOKEN }}
# repository: JWCook/pyinaturalist-notebook
# event-type: post-release
# client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}'
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ eggs
lib
lib64
parts
scratch
sdist
var
venv/
Expand Down Expand Up @@ -52,6 +53,7 @@ docs/examples
docs/sample_data
docs/models/
docs/modules/
docs/requirements.txt

# Mac OS X
.DS_Store
Expand Down
9 changes: 6 additions & 3 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ build:
os: 'ubuntu-24.04'
tools:
python: '3.12'

jobs:
# Use uv to export optional + documentation dependencies
post_create_environment:
- pip install uv
- uv export -q --no-dev --group docs --no-emit-project -o docs/requirements.txt
python:
install:
- method: pip
path: .
extra_requirements:
- docs
- requirements: docs/requirements.txt
14 changes: 8 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ Contributions are welcome, and they are greatly appreciated! Every
little bit helps, and credit will always be given.

## Installation
To set up for local development (requires [poetry](https://python-poetry.org)):
To set up for local development (requires [uv](https://docs.astral.sh/uv)):
```bash
$ git clone https://github.com/pyinat/pyinaturalist.git
$ cd pyinaturalist
$ poetry install -v -E docs
$ uv sync --all-extras --all-groups
```

## Contribution Guidelines
Expand All @@ -20,8 +20,10 @@ Here are some general guidelines for submitting a pull request:
- Submit the PR to be merged into the `main` branch.

### Tests
We use the [pytest](https://docs.pytest.org/en/latest/) framework for unit testing.
Just run the `pytest` command to run locally.
To run all tests and linting:
```sh
uv run nox
```

#### Testing supported python versions
For PRs, GitHub Actions will run these tests for each supported python version.
Expand All @@ -43,7 +45,7 @@ For PRs, please include docstrings for all functions and classes.

To build the docs locally:
```bash
$ nox -e docs
$ uv run nox -e docs
```

To preview:
Expand All @@ -56,7 +58,7 @@ $ xdg-open docs/_build/html/index.html

You can also use [sphinx-autobuild](https://github.com/executablebooks/sphinx-autobuild) to rebuild the docs and live reload in the browser whenever doc contents change:
```bash
$ nox -e livedocs
$ uv run nox -e livedocs
```

Project documentation is generated using [Sphinx](https://www.sphinx-doc.org),
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 Jordan Cook
Copyright (c) 2025 Jordan Cook

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
68 changes: 44 additions & 24 deletions noxfile.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
"""Notes:
* 'test' command: nox will use poetry.lock to determine dependency versions
* 'test' command: nox will create new virtualenvs per python version
* 'lint' command: tools and environments are managed by pre-commit
* All other commands: the current environment will be used instead of creating new ones
* All other commands: will use the project virtualenv managed by uv
"""

from os import getenv
from os.path import join
from shutil import rmtree

import nox
from nox_poetry import session

nox.options.reuse_existing_virtualenvs = True
nox.options.sessions = ['lint', 'cov']

LIVE_DOCS_PORT = 8181
LIVE_DOCS_IGNORE = ['*.csv', '*.ipynb', '*.pyc', '*.tmp', '**/modules/*']
LIVE_DOCS_WATCH = ['pyinaturalist', 'examples']
DEFAULT_COVERAGE_FORMATS = ['html', 'term']
DOC_BUILD_DIR = join('docs', '_build', 'html')
CLEAN_DIRS = [
'dist',
'build',
Expand All @@ -25,56 +27,74 @@
]


@session(python=['3.8', '3.9', '3.10', '3.11', '3.12', '3.13'])
def install_deps(session):
"""Install project and test dependencies using uv"""
session.env['UV_PROJECT_ENVIRONMENT'] = session.virtualenv.location
session.run_install(
'uv',
'sync',
'--frozen',
'--all-extras',
)


@nox.session(python=['3.8', '3.9', '3.10', '3.11', '3.12', '3.13'], venv_backend='uv')
def test(session):
"""Run tests for a specific python version"""
test_paths = session.posargs or ['test']
session.install('.', 'pytest', 'pytest-sugar', 'pytest-xdist', 'requests-mock')
install_deps(session)
session.run('pytest', '-n', 'auto', *test_paths)


@session(python=False)
@nox.session(python=False)
def clean(session):
"""Clean up temporary build + documentation files"""
for dir in CLEAN_DIRS:
print(f'Removing {dir}')
rmtree(dir, ignore_errors=True)


@session(python=False)
@session(python=False, name='cov')
@nox.session(python=False, name='cov')
def coverage(session):
"""Run tests and generate coverage report"""
cmd = 'pytest -n auto --cov --cov-report=term --cov-report=html'
session.run(*cmd.split(' '))
cmd = ['pytest', '--numprocesses=auto', '--cov']

# Add coverage formats
cov_formats = session.posargs or DEFAULT_COVERAGE_FORMATS
cmd += [f'--cov-report={f}' for f in cov_formats]

# Add verbose flag, if set by environment
if getenv('PYTEST_VERBOSE'):
cmd += ['--verbose']
session.run(*cmd)


@session(python=False)
@nox.session(python=False)
def docs(session):
"""Build Sphinx documentation"""
cmd = 'sphinx-build docs docs/_build/html -j auto'
session.run(*cmd.split(' '))
session.run('sphinx-build', 'docs', DOC_BUILD_DIR, '-j', 'auto')


@session(python=False)
@nox.session(python=False)
def livedocs(session):
"""Auto-build docs with live reload in browser.
Add `-- open` to also open the browser after starting.
"""
args = ['-a']
args += [f'--watch {pattern}' for pattern in LIVE_DOCS_WATCH]
args += [f'--ignore {pattern}' for pattern in LIVE_DOCS_IGNORE]
args += [f'--port {LIVE_DOCS_PORT}', '-j auto']
cmd = ['sphinx-autobuild', 'docs', DOC_BUILD_DIR]
cmd += ['-a']
cmd += ['--port', str(LIVE_DOCS_PORT), '-j', 'auto']
for pattern in LIVE_DOCS_WATCH:
cmd += ['--watch', pattern]
for pattern in LIVE_DOCS_IGNORE:
cmd += ['--ignore', pattern]
if session.posargs == ['open']:
args.append('--open-browser')
cmd.append('--open-browser')

clean(session)
cmd = 'sphinx-autobuild docs docs/_build/html ' + ' '.join(args)
session.run(*cmd.split(' '))
session.run(*cmd)


@session(python=False)
@nox.session(python=False)
def lint(session):
"""Run linters and code formatters via pre-commit"""
cmd = 'pre-commit run --all-files'
session.run(*cmd.split(' '))
session.run('pre-commit', 'run', '--all-files')
Loading

0 comments on commit 32cd325

Please sign in to comment.