Skip to content

Commit

Permalink
Merge pull request #536 from UW-GAC/maint/use-ruff
Browse files Browse the repository at this point in the history
Switch to ruff
  • Loading branch information
amstilp authored Apr 26, 2024
2 parents 4000048 + 950674a commit f207995
Show file tree
Hide file tree
Showing 33 changed files with 288 additions and 794 deletions.
23 changes: 8 additions & 15 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,15 @@ repos:
- id: end-of-file-fixer
- id: check-yaml

- repo: https://github.com/psf/black
rev: 22.3.0
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.4.2
hooks:
- id: black

- repo: https://github.com/timothycrosley/isort
rev: 5.12.0
hooks:
- id: isort

- repo: https://github.com/PyCQA/flake8
rev: 7.0.0
hooks:
- id: flake8
args: ['--config=setup.cfg']
additional_dependencies: [flake8-isort]
# Run the linter.
- id: ruff
args: [ --fix ]
# Run the formatter.
- id: ruff-format

- repo: https://github.com/gitleaks/gitleaks
rev: v8.16.1
Expand Down
20 changes: 20 additions & 0 deletions .ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
line-length = 120
exclude = [
"**/migrations/**",
"*/static/CACHE/*",
"venv",
"docs",
]

[lint]
extend-select = [
"E",
"F",
"W", # pycodestyle warnings
"I", # isort
"DJ", # flake8-django
"E501", # line-too-long
]

[lint.isort]
known-first-party = ["gregor_django", "config", ]
12 changes: 3 additions & 9 deletions config/settings/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Base settings to build other settings files upon.
"""

from pathlib import Path

import environ
Expand Down Expand Up @@ -129,9 +130,7 @@
]
# https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"
},
{"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"},
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
Expand Down Expand Up @@ -257,12 +256,7 @@
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"verbose": {
"format": "%(levelname)s %(asctime)s %(module)s "
"%(process)d %(thread)d %(message)s"
}
},
"formatters": {"verbose": {"format": "%(levelname)s %(asctime)s %(module)s " "%(process)d %(thread)d %(message)s"}},
"handlers": {
"console": {
"level": "DEBUG",
Expand Down
4 changes: 1 addition & 3 deletions config/settings/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@
# EMAIL
# ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
EMAIL_BACKEND = env(
"DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend"
)
EMAIL_BACKEND = env("DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend")

# WhiteNoise
# ------------------------------------------------------------------------------
Expand Down
19 changes: 4 additions & 15 deletions config/settings/production.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,11 @@
# in our apache configuration. Having in both places causes duplicate header
SECURE_HSTS_SECONDS = 0
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-include-subdomains
SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool(
"DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS", default=True
)
SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool("DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS", default=True)
# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-preload
SECURE_HSTS_PRELOAD = env.bool("DJANGO_SECURE_HSTS_PRELOAD", default=True)
# https://docs.djangoproject.com/en/dev/ref/middleware/#x-content-type-options-nosniff
SECURE_CONTENT_TYPE_NOSNIFF = env.bool(
"DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True
)
SECURE_CONTENT_TYPE_NOSNIFF = env.bool("DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True)
# Since we have disabled HSTS above we get a warning when running check --deploy
# we are manually silencing this as we have verified apache is enforcing
# https://docs.djangoproject.com/en/dev/ref/checks/#security
Expand All @@ -79,9 +75,7 @@
# EMAIL
# ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email
DEFAULT_FROM_EMAIL = env(
"DJANGO_DEFAULT_FROM_EMAIL", default="gac-django <[email protected]>"
)
DEFAULT_FROM_EMAIL = env("DJANGO_DEFAULT_FROM_EMAIL", default="gac-django <[email protected]>")
# https://docs.djangoproject.com/en/dev/ref/settings/#server-email
SERVER_EMAIL = env("DJANGO_SERVER_EMAIL", default=DEFAULT_FROM_EMAIL)
# https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix
Expand Down Expand Up @@ -130,12 +124,7 @@
"()": "maintenance_mode.logging.RequireNotMaintenanceMode503",
},
},
"formatters": {
"verbose": {
"format": "%(levelname)s %(asctime)s %(module)s "
"%(process)d %(thread)d %(message)s"
}
},
"formatters": {"verbose": {"format": "%(levelname)s %(asctime)s %(module)s " "%(process)d %(thread)d %(message)s"}},
"handlers": {
"mail_admins": {
"level": "ERROR",
Expand Down
4 changes: 1 addition & 3 deletions config/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@

urlpatterns = [
path("", TemplateView.as_view(template_name="pages/home.html"), name="home"),
path(
"about/", TemplateView.as_view(template_name="pages/about.html"), name="about"
),
path("about/", TemplateView.as_view(template_name="pages/about.html"), name="about"),
# Django Admin, use {% url 'admin:index' %}
path(settings.ADMIN_URL, admin.site.urls),
# User management
Expand Down
1 change: 1 addition & 0 deletions config/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
framework.
"""

import os
import sys
from pathlib import Path
Expand Down
7 changes: 1 addition & 6 deletions gregor_django/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
__version__ = "0.1.0"
__version_info__ = tuple(
[
int(num) if num.isdigit() else num
for num in __version__.replace("-", ".", 1).split(".")
]
)
__version_info__ = tuple([int(num) if num.isdigit() else num for num in __version__.replace("-", ".", 1).split(".")])
1 change: 0 additions & 1 deletion gregor_django/drupal_oauth_provider/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ class CustomAccount(ProviderAccount):


class CustomProvider(OAuth2Provider):

id = DRUPAL_PROVIDER_ID
name = OVERRIDE_NAME
account_class = CustomAccount
Expand Down
4 changes: 1 addition & 3 deletions gregor_django/drupal_oauth_provider/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,4 @@ def test_custom_provider_has_scope(self):
}
]
with override_settings(SOCIALACCOUNT_PROVIDERS=custom_provider_settings):
CustomProvider(request).get_provider_managed_scope_status(
scopes_granted=["X"]
)
CustomProvider(request).get_provider_managed_scope_status(scopes_granted=["X"])
17 changes: 4 additions & 13 deletions gregor_django/drupal_oauth_provider/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,9 @@ def _get_public_key_jwk(self, headers):
return keys[0]

def get_public_key(self, headers):

public_key_jwk = self._get_public_key_jwk(headers)
try:
public_key = jwt.algorithms.RSAAlgorithm.from_jwk(
json.dumps(public_key_jwk)
)
public_key = jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(public_key_jwk))
except Exception as e:
logger.error(f"[get_public_key] failed to convert jwk to public key {e}")
else:
Expand Down Expand Up @@ -83,9 +80,7 @@ def get_scopes_from_token(self, id_token, headers):
logger.error(f"Invalid id_token {e} {id_token.token}")
raise OAuth2Error("Invalid id_token") from e
except Exception as e:
logger.error(
f"Other exception parsing token {e} header {unverified_header} token {id_token}"
)
logger.error(f"Other exception parsing token {e} header {unverified_header} token {id_token}")
raise OAuth2Error("Error when decoding token {e}")
else:
scopes = token_payload.get("scope")
Expand All @@ -96,9 +91,7 @@ def complete_login(self, request, app, token, **kwargs):
headers = {"Authorization": "Bearer {0}".format(token.token)}

scopes_granted = self.get_scopes_from_token(token, headers)
managed_scope_status = self.get_provider().get_provider_managed_scope_status(
scopes_granted
)
managed_scope_status = self.get_provider().get_provider_managed_scope_status(scopes_granted)

resp = requests.get(self.profile_url, headers=headers)
resp.raise_for_status()
Expand All @@ -110,9 +103,7 @@ def complete_login(self, request, app, token, **kwargs):
)
extra_data["scopes_granted"] = scopes_granted
extra_data["managed_scope_status"] = managed_scope_status
social_login = self.get_provider().sociallogin_from_response(
request, extra_data
)
social_login = self.get_provider().sociallogin_from_response(request, extra_data)

return social_login

Expand Down
16 changes: 6 additions & 10 deletions gregor_django/gregor_anvil/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ class AccountAdapter(BaseAccountAdapter):
def get_autocomplete_queryset(self, queryset, q):
"""Filter to Accounts where the email or the associated user name matches the query `q`."""
if q:
queryset = queryset.filter(
Q(email__icontains=q) | Q(user__name__icontains=q)
)
queryset = queryset.filter(Q(email__icontains=q) | Q(user__name__icontains=q))
return queryset

def get_autocomplete_label(self, account):
Expand Down Expand Up @@ -78,7 +76,9 @@ class ResourceWorkspaceAdapter(BaseWorkspaceAdapter):

type = "resource"
name = "Resource workspace"
description = "Workspaces that contain general Consortium resources (e.g., examples of using AnVIL, working with data, etc.)" # noqa: E501
description = (
"Workspaces that contain general Consortium resources (e.g., examples of using AnVIL, working with data, etc.)" # noqa: E501
)
list_table_class_view = tables.DefaultWorkspaceTable
list_table_class_staff_view = tables.DefaultWorkspaceTable
workspace_data_model = models.ResourceWorkspace
Expand Down Expand Up @@ -111,9 +111,7 @@ class CombinedConsortiumDataWorkspaceAdapter(BaseWorkspaceAdapter):
list_table_class_staff_view = tables.CombinedConsortiumDataWorkspaceTable
workspace_data_model = models.CombinedConsortiumDataWorkspace
workspace_data_form_class = forms.CombinedConsortiumDataWorkspaceForm
workspace_detail_template_name = (
"gregor_anvil/combinedconsortiumdataworkspace_detail.html"
)
workspace_detail_template_name = "gregor_anvil/combinedconsortiumdataworkspace_detail.html"
workspace_form_class = WorkspaceForm


Expand Down Expand Up @@ -155,9 +153,7 @@ class DCCProcessedDataWorkspaceAdapter(BaseWorkspaceAdapter):
list_table_class_staff_view = tables.DCCProcessedDataWorkspaceTable
workspace_data_model = models.DCCProcessedDataWorkspace
workspace_data_form_class = forms.DCCProcessedDataWorkspaceForm
workspace_detail_template_name = (
"gregor_anvil/dccprocesseddataworkspace_detail.html"
)
workspace_detail_template_name = "gregor_anvil/dccprocesseddataworkspace_detail.html"
workspace_form_class = WorkspaceForm


Expand Down
4 changes: 1 addition & 3 deletions gregor_django/gregor_anvil/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,7 @@ class Meta:
class DCCProcessingWorkspaceForm(Bootstrap5MediaFormMixin, forms.ModelForm):
"""Form for a DCCProcessingWorkspace object."""

ERROR_UPLOAD_CYCLE = (
"upload_cycle must match upload_cycle of all upload_workspaces."
)
ERROR_UPLOAD_CYCLE = "upload_cycle must match upload_cycle of all upload_workspaces."

class Meta:
model = models.DCCProcessingWorkspace
Expand Down
29 changes: 9 additions & 20 deletions gregor_django/gregor_anvil/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,32 +103,28 @@ class Meta:
def __str__(self):
return "U{cycle:02d}".format(cycle=self.cycle)

def get_absolute_url(self):
"""Return the absolute url for this object."""
return reverse("gregor_anvil:upload_cycles:detail", args=[self.cycle])

def clean(self):
"""Custom cleaning methods."""
# End date must be after start date.
if self.start_date and self.end_date and self.start_date >= self.end_date:
raise ValidationError("end_date must be after start_date!")

def get_absolute_url(self):
"""Return the absolute url for this object."""
return reverse("gregor_anvil:upload_cycles:detail", args=[self.cycle])

def get_partner_upload_workspaces(self):
"""Return a queryset of PartnerUploadWorkspace objects that are included in this upload cycle.
For a given PartnerGroup and ConsentGroup, the workspace with the highest version that also has a date_completed
that is before the end_date of this upload cycle is included.
"""
qs = PartnerUploadWorkspace.objects.filter(
date_completed__lte=self.end_date
).order_by("-version")
qs = PartnerUploadWorkspace.objects.filter(date_completed__lte=self.end_date).order_by("-version")
# This is not ideal, but we can't use .distinct on fields.
pks_to_keep = []
for partner_group in PartnerGroup.objects.all():
for consent_group in ConsentGroup.objects.all():
instance = qs.filter(
partner_group=partner_group, consent_group=consent_group
).first()
instance = qs.filter(partner_group=partner_group, consent_group=consent_group).first()
if instance:
pks_to_keep.append(instance.pk)
return qs.filter(pk__in=pks_to_keep)
Expand Down Expand Up @@ -216,9 +212,7 @@ class ReleaseWorkspace(TimeStampedModel, BaseWorkspaceData):
on_delete=models.PROTECT,
)
upload_cycle = models.ForeignKey(UploadCycle, on_delete=models.PROTECT)
full_data_use_limitations = models.TextField(
help_text="The full data use limitations for this workspace."
)
full_data_use_limitations = models.TextField(help_text="The full data use limitations for this workspace.")
dbgap_version = models.IntegerField(
verbose_name=" dbGaP version",
validators=[MinValueValidator(1)],
Expand All @@ -245,21 +239,16 @@ class Meta:
]

def get_dbgap_accession(self):
return "phs{phs:06d}.v{v}.p{p}".format(
phs=self.phs, v=self.dbgap_version, p=self.dbgap_participant_set
)
return "phs{phs:06d}.v{v}.p{p}".format(phs=self.phs, v=self.dbgap_version, p=self.dbgap_participant_set)


class DCCProcessingWorkspace(TimeStampedModel, BaseWorkspaceData):

upload_cycle = models.ForeignKey(
UploadCycle,
on_delete=models.PROTECT,
help_text="Upload cycle associated with this workspace.",
)
purpose = models.TextField(
help_text="The type of processing that is done in this workspace."
)
purpose = models.TextField(help_text="The type of processing that is done in this workspace.")


class DCCProcessedDataWorkspace(TimeStampedModel, BaseWorkspaceData):
Expand Down
16 changes: 4 additions & 12 deletions gregor_django/gregor_anvil/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,12 @@ def render_consortium_access(self, record):
except ManagedGroup.DoesNotExist:
has_consortium_access = False
else:
has_consortium_access = record.is_in_authorization_domain(
group
) and record.is_shared(group)
has_consortium_access = record.is_in_authorization_domain(group) and record.is_shared(group)

if has_consortium_access:
icon = "check-circle-fill"
color = "green"
value = format_html(
"""<i class="bi bi-{}" style="color: {};"></i>""".format(icon, color)
)
value = format_html("""<i class="bi bi-{}" style="color: {};"></i>""".format(icon, color))
else:
value = ""
return value
Expand Down Expand Up @@ -187,9 +183,7 @@ class WorkspaceReportTable(tables.Table):

workspace_type = tables.columns.Column(orderable=False)
n_total = tables.columns.Column(verbose_name="Total number", orderable=False)
n_shared = tables.columns.Column(
verbose_name="Number shared with consortium", orderable=False
)
n_shared = tables.columns.Column(verbose_name="Number shared with consortium", orderable=False)

class Meta:
model = Workspace
Expand All @@ -200,9 +194,7 @@ def render_workspace_type(self, value):
return adapter_names[value] + "s"


class CombinedConsortiumDataWorkspaceTable(
WorkspaceConsortiumAccessTable, tables.Table
):
class CombinedConsortiumDataWorkspaceTable(WorkspaceConsortiumAccessTable, tables.Table):
"""A table for Workspaces that includes fields from CombinedConsortiumDataWorkspace."""

name = tables.columns.Column(linkify=True)
Expand Down
Loading

0 comments on commit f207995

Please sign in to comment.