Skip to content

Commit

Permalink
chore: Update ruff lint configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
jpmckinney committed Sep 16, 2024
1 parent ae86273 commit a631102
Show file tree
Hide file tree
Showing 14 changed files with 80 additions and 98 deletions.
4 changes: 1 addition & 3 deletions core/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ class CoreAdminSite(admin.AdminSite):
site_title = "Data registry administration"

def get_app_list(self, request):
"""
Sorts the data registry's models in a logical order.
"""
"""Sorts the data registry's models in a logical order."""
order = [
"Collection",
"Issue",
Expand Down
2 changes: 1 addition & 1 deletion core/context_processors.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django.conf import settings


def from_settings(request):
def from_settings(_request):
return {
"fathom": settings.FATHOM,
}
2 changes: 1 addition & 1 deletion data_registry/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class DataRegistryError(Exception):
"""Base class for exceptions from within this module"""
"""Base class for exceptions from within this module."""


class ConfigurationError(DataRegistryError):
Expand Down
41 changes: 14 additions & 27 deletions data_registry/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,15 @@ def format_datetime(dt):

class JobQuerySet(models.QuerySet):
def active(self):
"""
Return a query set of active jobs.
"""
"""Return a query set of active jobs."""
return self.filter(active=True)

def complete(self):
"""
Return a query set of complete jobs.
"""
"""Return a query set of complete jobs."""
return self.filter(status=Job.Status.COMPLETED)

def incomplete(self):
"""
Return a query set of incomplete jobs.
"""
"""Return a query set of incomplete jobs."""
return self.exclude(status=Job.Status.COMPLETED)


Expand Down Expand Up @@ -123,27 +117,21 @@ def __repr__(self):
return f"{self.collection!r}: {self}"

def initiate(self):
"""
Mark the job as started.
"""
"""Mark the job as started."""
self.start = Now()
self.status = Job.Status.RUNNING
self.save()

def complete(self):
"""
Mark the job as ended.
"""
"""Mark the job as ended."""
self.end = Now()
self.status = Job.Status.COMPLETED
self.save()


class CollectionQuerySet(models.QuerySet):
def visible(self):
"""
Return a query set of public collections with active jobs.
"""
"""Return a query set of public collections with active jobs."""
# https://docs.djangoproject.com/en/4.2/ref/models/expressions/#some-examples
active_jobs = Job.objects.active().filter(collection=models.OuterRef("pk"))
return self.filter(models.Exists(active_jobs), public=True)
Expand Down Expand Up @@ -315,6 +303,8 @@ def active_job(self):

def is_out_of_date(self):
"""
Return whether the publication is out-of-date.
A publication is out-of-date if it isn't frozen and has a retrieval frequency other than "never", and either
has never been scheduled or was last scheduled longer ago than the retrieval frequency.
"""
Expand Down Expand Up @@ -372,6 +362,9 @@ class Issue(models.Model):
class Meta:
verbose_name = "quality issue"

def __str__(self):
return f"{self.description[:32]} ({self.id})"


class Task(models.Model):
job = models.ForeignKey("Job", on_delete=models.CASCADE, db_index=True)
Expand Down Expand Up @@ -426,25 +419,19 @@ def __str__(self):
return f"#{self.id}({self.type})"

def initiate(self):
"""
Mark the task as started.
"""
"""Mark the task as started."""
self.start = Now()
self.status = Task.Status.RUNNING
self.save()

def progress(self, *, result="", note=""):
"""
Update the task's progress. If called without arguments, reset the task's progress.
"""
"""Update the task's progress. If called without arguments, reset the task's progress."""
self.result = result
self.note = note
self.save()

def complete(self, *, result, note=""):
"""
Mark the task as ended.
"""
"""Mark the task as ended."""
self.end = Now()
self.status = Task.Status.COMPLETED
self.result = result
Expand Down
4 changes: 1 addition & 3 deletions data_registry/process_manager/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@


def get_task_manager(task: models.Task) -> TaskManager:
"""
Instantiate and return a task manager for the task.
"""
"""Instantiate and return a task manager for the task."""
match task.type:
case models.Task.Type.COLLECT:
return Collect(task)
Expand Down
3 changes: 2 additions & 1 deletion data_registry/process_manager/task/collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import re
import shutil

import requests
from django.conf import settings
from requests.exceptions import HTTPError

Expand Down Expand Up @@ -83,7 +84,7 @@ def get_status(self):
response = self.request("get", scrapy_log_url, error_message="Unable to read Scrapy log")
except RecoverableError as e:
# If the log file doesn't exist, the job can't continue.
if isinstance(e.__cause__, HTTPError) and e.__cause__.response.status_code == 404:
if isinstance(e.__cause__, HTTPError) and e.__cause__.response.status_code == requests.codes.not_found:
raise UnexpectedError("Scrapy log doesn't exist") from e
raise

Expand Down
22 changes: 8 additions & 14 deletions data_registry/process_manager/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def exporter_status_to_task_status(status: TaskStatus) -> models.Task.Status:

def skip_if_not_started(method):
"""
A decorator to return early from a :meth:`~data_registry.process_manager.util.TaskManager.wipe` method if the task
Decorate a :meth:`~data_registry.process_manager.util.TaskManager.wipe` method to return early if the task
hadn't started.
"""

Expand All @@ -40,9 +40,7 @@ def wrapper(self, *args, **kwargs):


class TaskManager(ABC):
"""
Task managers should only update the :class:`~data_registry.models.Job` context and metadata fields.
"""
"""Task managers should only update the :class:`~data_registry.models.Job` context and metadata fields."""

def __init__(self, task: models.Task):
"""
Expand All @@ -55,28 +53,24 @@ def __init__(self, task: models.Task):

@property
def job(self) -> models.Job:
"""
The job of which the task is a part.
"""
"""The job of which the task is a part."""
return self.task.job

@property
def collection(self) -> models.Collection:
"""
The publication on which the task is performed.
"""
"""The publication on which the task is performed."""
return self.task.job.collection

@property
@abstractmethod
def final_output(self) -> bool:
"""
Whether the task produces a final output, like a bulk download.
"""
"""Whether the task produces a final output, like a bulk download."""

def request(self, method, url, *, error_message, **kwargs):
"""
Send a request to an application. If the application returns an error response or is temporarily unavailable,
Send a request to an application.
If the application returns an error response or is temporarily unavailable,
raise :class:`~data_registry.exceptions.RecoverableError`.
:raises RecoverableError:
Expand Down
4 changes: 1 addition & 3 deletions data_registry/templatetags/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,7 @@ def translate_url(context, language):

@register.simple_tag(takes_context=True)
def redirect_to(context):
"""
Remove the ``letter`` query string parameter, to avoid zero results in the new language.
"""
"""Remove the ``letter`` query string parameter, to avoid zero results in the new language."""
request = context["request"]
if "letter" in request.GET:
return request.build_absolute_uri(f"{request.path}?{remove_query_string_parameter(context, 'letter')}")
Expand Down
4 changes: 1 addition & 3 deletions data_registry/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ def collection_queryset(request):

# https://markdown-it-py.readthedocs.io/en/latest/using.html#renderers
def render_blank_link(self, tokens, idx, options, env) -> str:
"""
Set the link to open in a new tab.
"""
"""Set the link to open in a new tab."""
tokens[idx].attrSet("target", "_blank")
return self.renderToken(tokens, idx, options, env)

Expand Down
6 changes: 4 additions & 2 deletions data_registry/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ def index(request):

def search(request):
"""
Search publications.
The filter logic is:
letter AND date_range AND (frequency₁ OR frequency₂ OR …) AND parties_count AND plannings_count AND …
Expand Down Expand Up @@ -284,9 +286,9 @@ def excel_data(request, job_id, job_range=None):
response.status_code,
)

if response.status_code > 201 or "id" not in response.json():
if response.status_code > requests.codes.created or "id" not in response.json():
logger.error("Invalid response from spoonbill %s.", response.text)
return HttpResponse(status=500)
return HttpResponse(status=requests.codes.internal_server_error)

params = urlencode({"lang": language, "url": response.json()["id"]})
return redirect(urljoin(settings.SPOONBILL_URL, f"/#/upload-file?{params}"))
8 changes: 4 additions & 4 deletions exporter/management/commands/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def callback(state, channel, method, properties, input_message):

export.lock()

id = 0
data_id = 0
page = 1
files = {}

Expand All @@ -50,7 +50,7 @@ def callback(state, channel, method, properties, input_message):

while True:
with connections["kingfisher_process"].cursor() as cursor:
logger.debug("Processing page %s with id > %s", page, id)
logger.debug("Processing page %s with data.id > %s", page, data_id)
cursor.execute(
"""
SELECT d.id, d.data, d.data->>'date'
Expand All @@ -61,7 +61,7 @@ def callback(state, channel, method, properties, input_message):
ORDER BY d.id
LIMIT %s
""",
[collection_id, id, settings.EXPORTER_PAGE_SIZE],
[collection_id, data_id, settings.EXPORTER_PAGE_SIZE],
)

records = cursor.fetchall()
Expand All @@ -73,7 +73,7 @@ def callback(state, channel, method, properties, input_message):
files[dump_file] = full

for r in records:
id = r[0]
data_id = r[0]

full.write(r[1])
full.write("\n")
Expand Down
36 changes: 9 additions & 27 deletions exporter/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,47 +127,35 @@ def lockfile(self) -> str:
return self.directory / f"exporter_{self.basename}.lock"

def lock(self) -> None:
"""
Create the lock file.
"""
"""Create the lock file."""
try:
with self.lockfile.open("x"):
pass
except FileExistsError as e:
raise LockFileError(self.lockfile.stat().st_mtime) from e

def unlock(self) -> None:
"""
Delete the lock file.
"""
"""Delete the lock file."""
self.lockfile.unlink(missing_ok=True)

def remove(self):
"""
Delete the export directory recursively.
"""
"""Delete the export directory recursively."""
if self.directory.exists():
shutil.rmtree(self.directory)

@property
def running(self) -> bool:
"""
Return whether the output file is being written.
"""
"""Return whether the output file is being written."""
return self.lockfile.exists()

@property
def completed(self) -> bool:
"""
Return whether the output file has been written.
"""
"""Return whether the output file has been written."""
return self.path.exists()

@property
def status(self) -> Literal["RUNNING", "COMPLETED", "WAITING"]:
"""
Return the status of the export.
"""
"""Return the status of the export."""
if self.running:
return TaskStatus.RUNNING
if self.completed:
Expand All @@ -176,9 +164,7 @@ def status(self) -> Literal["RUNNING", "COMPLETED", "WAITING"]:

@property
def files(self) -> dict:
"""
Return all the available file formats and segments (by year or full).
"""
"""Return all the available file formats and segments (by year or full)."""
files = self.default_files()

for path in self.iterdir():
Expand All @@ -194,16 +180,12 @@ def files(self) -> dict:
return files

def iterdir(self):
"""
Yield path objects of the directory contents.
"""
"""Yield path objects of the directory contents."""
if self.directory.exists():
yield from self.directory.iterdir()

def get_convertible_paths(self):
"""
Yield paths to ``.jsonl.gz`` files.
"""
"""Yield paths to ``.jsonl.gz`` files."""
for path in self.iterdir():
if path.name.endswith(".jsonl.gz") and "_" not in path.name: # don't process YYYY_MM files
yield path
11 changes: 3 additions & 8 deletions manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,9 @@
def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc

from django.core.management import execute_from_command_line

execute_from_command_line(sys.argv)


Expand Down
Loading

0 comments on commit a631102

Please sign in to comment.