Skip to content

Commit

Permalink
switch to uv (#229)
Browse files Browse the repository at this point in the history
* use uv

* py311

* uv export

* linting

* tests

* change ci

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* version latest

* uv sync step

* add token

* rename job

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
tlambert03 and pre-commit-ci[bot] authored Feb 15, 2025
1 parent 28eb1fe commit 0e2b4a2
Show file tree
Hide file tree
Showing 58 changed files with 10,684 additions and 5,661 deletions.
57 changes: 24 additions & 33 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ concurrency:

jobs:
# With no caching at all the entire ci process takes 4m 30s to complete!
pytest:
test:
runs-on: ubuntu-latest

services:
redis:
image: redis:6
Expand All @@ -32,59 +31,51 @@ jobs:
- 5432:5432
env:
POSTGRES_PASSWORD: postgres

env:
CELERY_BROKER_URL: "redis://localhost:6379/0"
# postgres://user:password@host:port/database
DATABASE_URL: "postgres://postgres:postgres@localhost:5432/postgres"

UV_FROZEN: 1
steps:
- name: Checkout Code Repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
- name: Set up uv
uses: astral-sh/setup-uv@v1
with:
python-version: "3.11.4"
cache: pip
cache-dependency-path: |
backend/requirements/base.txt
backend/requirements/local.txt
version: latest
enable-cache: true

- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: latest
run_install: false

- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT

- uses: actions/cache@v4
name: Setup pnpm cache
- name: Install Node.js
uses: actions/setup-node@v4
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: ${{ runner.os }}-pnpm-store-
node-version-file: package.json
cache: "pnpm"

- name: Install Dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r backend/requirements/local.txt
pnpm install
- name: Install node Dependencies
run: pnpm install

- run: uv sync

- name: setup-chromedriver
uses: nanasess/setup-chromedriver@v2

- name: Test with pytest
working-directory: backend
- name: Configure headless display
run: |
export DISPLAY=:99
chromedriver --url-base=/wd/hub &
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional
pytest --color=yes -v --cov --cov-report=xml --cov-report=term-missing
echo "DISPLAY=:99.0" >> $GITHUB_ENV
Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
sleep 3
- name: Test
run: uv run pytest --color=yes -v --cov --cov-report=xml --cov-report=term-missing

- name: coverage
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
20 changes: 13 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ ci:
skip: []
submodules: false

exclude: '^docs/|/migrations/'
default_stages: [commit]
exclude: "^docs/|/migrations/"
default_stages: [pre-commit]

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
Expand All @@ -20,6 +20,12 @@ repos:
- id: check-docstring-first
- id: detect-private-key

- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.6.0
hooks:
- id: uv-export
args: ["--group", "prod", "--no-dev", "--frozen", "--output-file=requirements.txt"]

# - repo: https://github.com/pre-commit/mirrors-prettier
# rev: v3.0.0-alpha.9-for-vscode
# hooks:
Expand All @@ -33,14 +39,14 @@ repos:
# - id: djlint-django

- repo: https://github.com/adamchainz/django-upgrade
rev: '1.21.0'
rev: "1.23.1"
hooks:
- id: django-upgrade
args: ['--target-version', '4.2']
args: ["--target-version", "4.2"]

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.6.7'
rev: "v0.9.6"
hooks:
- id: ruff
args: ['--fix']
args: ["--fix", "--unsafe-fixes"]
- id: ruff-format
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.11
5 changes: 3 additions & 2 deletions backend/config/api_router.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import proteins.api.urls
from django.conf import settings
from fpbase.users.api.views import UserViewSet
from rest_framework.routers import DefaultRouter, SimpleRouter

import proteins.api.urls
from fpbase.users.api.views import UserViewSet

if settings.DEBUG:
router = DefaultRouter()
else:
Expand Down
2 changes: 1 addition & 1 deletion backend/config/settings/production.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@
"disable_existing_loggers": True,
"root": {"level": "WARNING"},
"formatters": {
"verbose": {"format": "%(levelname)s %(asctime)s %(module)s " "%(process)d %(thread)d %(message)s"},
"verbose": {"format": "%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s"},
},
"handlers": {
"console": {
Expand Down
5 changes: 3 additions & 2 deletions backend/config/urls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import fpbase.views
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
Expand All @@ -10,6 +9,9 @@
from django.views.generic import TemplateView
from django.views.generic.base import RedirectView
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
from graphene_django.views import GraphQLView

import fpbase.views
from fpbase.sitemaps import (
AuthorsSitemap,
MicroscopeSitemap,
Expand All @@ -19,7 +21,6 @@
ReferencesSitemap,
StaticSitemap,
)
from graphene_django.views import GraphQLView
from references.views import ReferenceListView

sitemaps = {
Expand Down
1 change: 1 addition & 0 deletions backend/favit/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.apps import apps
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseBadRequest, HttpResponseNotAllowed, JsonResponse

from fpbase.util import is_ajax, uncache_protein_page

from .models import Favorite
Expand Down
2 changes: 1 addition & 1 deletion backend/fpbase/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def friendly_email(self):

def send_email(self):
EmailMessage(
f'FPbase contact from {self.cleaned_data["name"]}',
f"FPbase contact from {self.cleaned_data['name']}",
self.cleaned_data["message"],
to=[a[1] for a in settings.ADMINS],
headers={"Reply-To": self.friendly_email()},
Expand Down
1 change: 1 addition & 0 deletions backend/fpbase/schema.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import graphene

import proteins.schema
import references.schema

Expand Down
1 change: 1 addition & 0 deletions backend/fpbase/sitemaps.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.contrib.sitemaps import Sitemap
from django.urls import reverse

from proteins.models import Microscope, Organism, Protein, ProteinCollection
from references.models import Author, Reference

Expand Down
14 changes: 5 additions & 9 deletions backend/fpbase/tests/test_end2end.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
import pytest
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from django.urls import reverse
from proteins.factories import MicroscopeFactory, OpticalConfigWithFiltersFactory, ProteinFactory
from proteins.models.protein import Protein
from proteins.util.blast import _get_binary
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.wait import WebDriverWait

from proteins.factories import MicroscopeFactory, OpticalConfigWithFiltersFactory, ProteinFactory
from proteins.models.protein import Protein
from proteins.util.blast import _get_binary

SEQ = "MVSKGEELFTGVVPILVELDGDVNGHKFSVSGEGEGDATYGKLTLKFICTTGKLPVPWPTLVTTLTYGVQCFS"
# reverse translation of DGDVNGHKFSVSGEGEGDATYGKLTLKFICT
cDNA = "gatggcgatgtgaacggccataaatttagcgtgagcggcgaaggcgaaggcgatgcgacctatggcaaactgaccctgaaatttatttgcacc"
Expand Down Expand Up @@ -48,13 +49,8 @@ def _load_reverse(self, url_name, **kwargs):

def _assert_no_console_errors(self):
logs = self.browser.get_log("browser")
acceptable_errors = (
"GPU stall due to ReadPixels",
"favicon.ico",
"Failed to decode downloaded font",
)
for lg in logs:
if all(err not in lg["message"] for err in acceptable_errors):
if lg["level"] == "SEVERE":
raise AssertionError(f"Console errors occurred: {logs}")

def test_spectra(self):
Expand Down
1 change: 1 addition & 0 deletions backend/fpbase/tests/test_schema.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json

from graphene_django.utils.testing import GraphQLTestCase

from proteins import models

from ..schema import schema
Expand Down
2 changes: 1 addition & 1 deletion backend/fpbase/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
from django.views.decorators.cache import cache_page
from django.views.generic import TemplateView
from django.views.generic.edit import FormView
from proteins.models import Protein, Spectrum
from sentry_sdk import last_event_id

from fpbase.forms import ContactForm
from proteins.models import Protein, Spectrum


class HomeView(TemplateView):
Expand Down
8 changes: 4 additions & 4 deletions backend/fpseq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

__all__ = [
"FPSeq",
"from_fpbase",
"SkbSequence",
"ParasailAlignment",
"align_seqs",
"Mutation",
"MutationSet",
"ParasailAlignment",
"SkbSequence",
"align_seqs",
"from_fpbase",
"get_mutations",
"mutate_sequence",
"protein_weight",
Expand Down
7 changes: 3 additions & 4 deletions backend/fpseq/skbio_protein.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def _munge_to_sequence(self, other, method):
if isinstance(other, SkbSequence):
if type(other) is not type(self):
raise TypeError(
f"Cannot use {self.__class__.__name__} and " f"{other.__class__.__name__} together with `{method}`"
f"Cannot use {self.__class__.__name__} and {other.__class__.__name__} together with `{method}`"
)
else:
return other
Expand Down Expand Up @@ -216,8 +216,7 @@ def __getitem__(self, indexable):

if isinstance(indexable, np.ndarray) and indexable.dtype == bool and len(indexable) != len(self):
raise IndexError(
"An boolean vector index must be the same length"
" as the sequence (%d, not %d)." % (len(self), len(indexable))
f"An boolean vector index must be the same length as the sequence ({len(self)}, not {len(indexable)})."
)

if isinstance(indexable, np.ndarray) and indexable.size == 0:
Expand Down Expand Up @@ -362,6 +361,6 @@ def _slices_from_iter(array, indexables):
elif _is_single_index(i):
i = _single_index_to_slice(i)
else:
raise IndexError("Cannot slice sequence from iterable " f"containing {i!r}.")
raise IndexError(f"Cannot slice sequence from iterable containing {i!r}.")

yield array[i]
2 changes: 1 addition & 1 deletion backend/proteins/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
from django.forms import TextInput
from django.urls import reverse
from django.utils.safestring import mark_safe
from fpbase.util import uncache_protein_page
from mptt.admin import MPTTModelAdmin
from reversion.admin import VersionAdmin
from reversion_compare.admin import CompareVersionAdmin

from fpbase.util import uncache_protein_page
from proteins.models import (
BleachMeasurement,
Camera,
Expand Down
7 changes: 4 additions & 3 deletions backend/proteins/extrest/entrez.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from Bio import Entrez, SeqIO
from django.core.cache import cache

from references.helpers import pmid2doi

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -129,9 +130,9 @@ def fetch_ipg_sequence(protein_name=None, uid=None):
assert len(record) == 1, "More than one record returned from protein database"
record = record[0]
prot_seq = record["GBSeq_sequence"].upper()
assert len(prot_seq) == int(
seq_len
), f"Protein database sequence different length {len(prot_seq)} than IPG database{int(seq_len)}"
assert len(prot_seq) == int(seq_len), (
f"Protein database sequence different length {len(prot_seq)} than IPG database{int(seq_len)}"
)
return (ipg_uid, prot_seq)


Expand Down
2 changes: 1 addition & 1 deletion backend/proteins/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import factory.fuzzy
import numpy as np
from django.utils.text import slugify
from fpseq import FPSeq

from fpseq import FPSeq
from proteins.util.helpers import wave_to_hex

from .models import Filter, FilterPlacement, Microscope, OpticalConfig, Protein, Spectrum, State
Expand Down
4 changes: 2 additions & 2 deletions backend/proteins/forms/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from django.forms.models import inlineformset_factory # ,BaseInlineFormSet
from django.utils.safestring import mark_safe
from django.utils.text import slugify
from references.models import Reference # breaks application modularity

from proteins.models import (
BleachMeasurement,
Expand All @@ -18,6 +17,7 @@
StateTransition,
)
from proteins.validators import protein_sequence_validator, validate_doi
from references.models import Reference # breaks application modularity


def popover_html(label, content, side="right"):
Expand Down Expand Up @@ -390,7 +390,7 @@ def clean(self):
parent = self.cleaned_data.get("parent")
mutation = self.cleaned_data.get("mutation")
if (parent and not mutation) or (mutation and not parent):
raise forms.ValidationError("Both parent and mutation are " "required when providing lineage information")
raise forms.ValidationError("Both parent and mutation are required when providing lineage information")

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Expand Down
Loading

0 comments on commit 0e2b4a2

Please sign in to comment.