Skip to content

Commit

Permalink
style: update ruff and drop black (#283)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsstevenson authored Jul 16, 2024
1 parent cb7c609 commit 451b87a
Show file tree
Hide file tree
Showing 32 changed files with 489 additions and 468 deletions.
15 changes: 8 additions & 7 deletions .github/workflows/backend_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: black
uses: psf/black@stable
- name: Setup Python
uses: actions/setup-python@v5
with:
src: "./server"
python-version: "3.11"

- name: ruff
uses: chartboost/ruff-action@v1
with:
src: "./server"
- name: Install dependencies
run: python3 -m pip install "server/.[dev]"

- name: Check style
run: python3 -m ruff check server/ && python3 -m ruff format --check server/
10 changes: 3 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,12 @@ repos:
- id: end-of-file-fixer
- id: check-merge-conflict
- id: detect-aws-credentials
- repo: https://github.com/psf/black
rev: 23.7.0
hooks:
- id: black
language_version: python3.11
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.286
rev: v0.5.0
hooks:
- id: ruff-format
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
args: [--fix, --exit-non-zero-on-fix, --config=server/pyproject.toml]
- repo: https://github.com/pre-commit/mirrors-eslint
rev: "v8.20.0"
hooks:
Expand Down
118 changes: 90 additions & 28 deletions server/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,42 +69,104 @@ root = "../."
addopts = "--cov=src --cov-report term-missing"
testpaths = ["tests"]

[tool.black]
line-length = 88

[tool.ruff]
# pycodestyle (E, W)
# Pyflakes (F)
# flake8-annotations (ANN)
# flake8-quotes (Q)
# pydocstyle (D)
# pep8-naming (N)
# isort (I)
select = ["E", "W", "F", "ANN", "Q", "D", "N", "I"]

fixable = ["I"]
src = ["curfu"]

[tool.ruff.lint]
select = [
"F", # https://docs.astral.sh/ruff/rules/#pyflakes-f
"E", "W", # https://docs.astral.sh/ruff/rules/#pycodestyle-e-w
"I", # https://docs.astral.sh/ruff/rules/#isort-i
"N", # https://docs.astral.sh/ruff/rules/#pep8-naming-n
"D", # https://docs.astral.sh/ruff/rules/#pydocstyle-d
"UP", # https://docs.astral.sh/ruff/rules/#pyupgrade-up
"ANN", # https://docs.astral.sh/ruff/rules/#flake8-annotations-ann
"ASYNC", # https://docs.astral.sh/ruff/rules/#flake8-async-async
"S", # https://docs.astral.sh/ruff/rules/#flake8-bandit-s
"B", # https://docs.astral.sh/ruff/rules/#flake8-bugbear-b
"A", # https://docs.astral.sh/ruff/rules/#flake8-builtins-a
"C4", # https://docs.astral.sh/ruff/rules/#flake8-comprehensions-c4
"DTZ", # https://docs.astral.sh/ruff/rules/#flake8-datetimez-dtz
"T10", # https://docs.astral.sh/ruff/rules/#flake8-datetimez-dtz
"EM", # https://docs.astral.sh/ruff/rules/#flake8-errmsg-em
"LOG", # https://docs.astral.sh/ruff/rules/#flake8-logging-log
"G", # https://docs.astral.sh/ruff/rules/#flake8-logging-format-g
"INP", # https://docs.astral.sh/ruff/rules/#flake8-no-pep420-inp
"PIE", # https://docs.astral.sh/ruff/rules/#flake8-pie-pie
"T20", # https://docs.astral.sh/ruff/rules/#flake8-print-t20
"PT", # https://docs.astral.sh/ruff/rules/#flake8-pytest-style-pt
"Q", # https://docs.astral.sh/ruff/rules/#flake8-quotes-q
"RSE", # https://docs.astral.sh/ruff/rules/#flake8-raise-rse
"RET", # https://docs.astral.sh/ruff/rules/#flake8-return-ret
"SLF", # https://docs.astral.sh/ruff/rules/#flake8-self-slf
"SIM", # https://docs.astral.sh/ruff/rules/#flake8-simplify-sim
"ARG", # https://docs.astral.sh/ruff/rules/#flake8-unused-arguments-arg
"PTH", # https://docs.astral.sh/ruff/rules/#flake8-use-pathlib-pth
"PGH", # https://docs.astral.sh/ruff/rules/#pygrep-hooks-pgh
"PERF", # https://docs.astral.sh/ruff/rules/#perflint-perf
"FURB", # https://docs.astral.sh/ruff/rules/#refurb-furb
"RUF", # https://docs.astral.sh/ruff/rules/#ruff-specific-rules-ruf
]
fixable = [
"I",
"F401",
"D",
"UP",
"ANN",
"B",
"C4",
"LOG",
"G",
"PIE",
"PT",
"RSE",
"SIM",
"PERF",
"FURB",
"RUF"
]
# ANN003 - missing-type-kwargs
# ANN101 - missing-type-self
# ANN102 - missing-type-cls
# D203 - one-blank-line-before-class
# D205 - blank-line-after-summary
# D206 - indent-with-spaces*
# D213 - multi-line-summary-second-line
# D300 - triple-single-quotes*
# D400 - ends-in-period
# D415 - ends-in-punctuation
# ANN101 - missing-type-self
# ANN003 - missing-type-kwargs
# E501 - line-too-long
ignore = ["D205", "D400", "D415", "ANN101", "ANN003", "E501"]

[tool.ruff.flake8-quotes]
docstring-quotes = "double"
# E111 - indentation-with-invalid-multiple*
# E114 - indentation-with-invalid-multiple-comment*
# E117 - over-indented*
# E501 - line-too-long*
# W191 - tab-indentation*
# S321 - suspicious-ftp-lib-usage
# *ignored for compatibility with formatter
ignore = [
"ANN003", "ANN101", "ANN102",
"D203", "D205", "D206", "D213", "D300", "D400", "D415",
"E111", "E114", "E117", "E501",
"W191",
"S321",
]

[tool.ruff.per-file-ignores]
[tool.ruff.lint.per-file-ignores]
# ANN001 - missing-type-function-argument
# ANN2 - missing-return-type
# ANN102 - missing-type-cls
# N805 - invalid-first-argument-name-for-method
# F821 - undefined-name
# S101 - assert
# B011 - assert-false
# F401 - unused-import
"tests/*" = ["ANN001", "ANN2", "ANN102"]
"setup.py" = ["F821"]
# N805 - invalid-first-argument-name-for-method
# D301 - escape-sequence-in-docstring
# INP001 - implicit-namespace-package
# ARG001 - unused-function-argument
# B008 - function-call-in-default-argument
"**/tests/*" = ["ANN001", "ANN2", "ANN102", "S101", "B011", "INP001", "ARG001"]
"*__init__.py" = ["F401"]
"curfu/schemas.py" = ["ANN201", "N805", "ANN001"]
"curfu/routers/*" = ["D301"]
"curfu/cli.py" = ["D301"]
"**/src/curfu/schemas.py" = ["ANN201", "N805", "ANN001"]
"**/src/curfu/routers/*" = ["D301", "B008"]
"**/src/curfu/cli.py" = ["D301"]

[tool.ruff.format]
docstring-code-format = true
8 changes: 3 additions & 5 deletions server/src/curfu/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Fusion curation interface."""

import logging
from importlib.metadata import PackageNotFoundError, version
from os import environ
Expand All @@ -17,7 +18,7 @@
# establish environment-dependent params
if "FUSION_EB_PROD" in environ:
environ["FUSION_EB_PROD"] = "true"
LOG_FN = "/tmp/curfu.log"
LOG_FN = "/tmp/curfu.log" # noqa: S108
else:
LOG_FN = "curfu.log"

Expand Down Expand Up @@ -50,10 +51,7 @@
UTA_DB_URL = "postgresql://uta_admin@localhost:5433/uta/uta_20210129"

# get local seqrepo location
if "SEQREPO_DATA_PATH" not in environ:
SEQREPO_DATA_PATH = f"{APP_ROOT}/data/seqrepo/latest"
else:
SEQREPO_DATA_PATH = environ["SEQREPO_DATA_PATH"]
SEQREPO_DATA_PATH = environ.get("SEQREPO_DATA_PATH", f"{APP_ROOT}/data/seqrepo/latest")


class LookupServiceError(Exception):
Expand Down
27 changes: 7 additions & 20 deletions server/src/curfu/cli.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Provide command-line interface to application and associated utilities."""

import os
from pathlib import Path
from typing import Optional

import click

Expand All @@ -21,8 +21,8 @@ def serve(port: int) -> None:
"""
# calling uvicorn.run() doesn't get logs printed to console --
# performing a syscall for now until a more elegant solution appears
os.system(
f"uvicorn curfu.main:app --reload --port={port} --reload-dir={str(APP_ROOT.absolute())}"
os.system( # noqa: S605
f"uvicorn curfu.main:app --reload --port={port} --reload-dir={APP_ROOT.absolute()!s}"
)


Expand Down Expand Up @@ -57,29 +57,16 @@ def devtools() -> None:
"--uniprot", "-u", help="Path to uniprot_sprot_YYYYMMDD.xml", default=None
)
def domains(
types: str, protein2ipr: Optional[str], refs: Optional[str], uniprot: Optional[str]
types: str, protein2ipr: str | None, refs: str | None, uniprot: str | None
) -> None:
"""Build domain mappings for use in Fusion Curation app.
\f
:param str types: comma-separated list
"""
types_split = set(types.lower().replace(" ", "").split(","))

if protein2ipr:
protein2ipr_path = Path(protein2ipr)
else:
protein2ipr_path = None

if uniprot:
uniprot_path = Path(uniprot)
else:
uniprot_path = None

if refs:
refs_path = Path(refs)
else:
refs_path = None

protein2ipr_path = Path(protein2ipr) if protein2ipr else None
uniprot_path = Path(uniprot) if uniprot else None
refs_path = Path(refs) if refs else None
build_gene_domain_maps(
interpro_types=types_split,
protein_ipr_path=protein2ipr_path,
Expand Down
5 changes: 3 additions & 2 deletions server/src/curfu/devtools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Utility functions for application setup."""

import ftplib
from typing import Callable
from collections.abc import Callable

from curfu import logger

Expand All @@ -18,7 +19,7 @@ def ftp_download(domain: str, path: str, fname: str, callback: Callable) -> None
ftp.retrbinary(f"RETR {fname}", callback)
except ftplib.all_errors as e:
logger.error(f"FTP download failed: {e}")
raise Exception(e)
raise Exception(e) from e


# default interpro entry types to try to gather for domains
Expand Down
1 change: 1 addition & 0 deletions server/src/curfu/devtools/build_client_types.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Provide client type generation tooling."""

from pathlib import Path

from pydantic2ts.cli.script import generate_typescript_defs
Expand Down
17 changes: 10 additions & 7 deletions server/src/curfu/devtools/build_gene_suggest.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""Provide tools to build backend data relating to gene identification."""

import csv
from datetime import datetime as dt
import datetime
from pathlib import Path
from timeit import default_timer as timer
from typing import Dict, List, Optional

import click
from biocommons.seqrepo.seqrepo import SeqRepo
Expand All @@ -25,7 +25,7 @@ def __init__(self) -> None:
self.sr = SeqRepo(SEQREPO_DATA_PATH)
self.genes = []

def _get_chromosome(self, record: Dict) -> Optional[str]:
def _get_chromosome(self, record: dict) -> str | None:
"""Extract readable chromosome identifier from gene extensions.
:param record: stored normalized record
Expand All @@ -42,7 +42,7 @@ def _get_chromosome(self, record: Dict) -> Optional[str]:
return None

@staticmethod
def _make_list_column(values: List[str]) -> str:
def _make_list_column(values: list[str]) -> str:
"""Convert a list of strings into a comma-separated string, filtering out
non-alphabetic values.
Expand All @@ -62,12 +62,13 @@ def _make_list_column(values: List[str]) -> str:
:param values: A list of strings to be converted into a comma-separated string.
:return: A comma-separated string containing unique, alphabetic values from the
input list.
"""
unique = {v.upper() for v in values}
filtered = {v for v in unique if any(char.isalpha() for char in v)}
return ",".join(filtered)

def _process_gene_record(self, record: Dict) -> None:
def _process_gene_record(self, record: dict) -> None:
"""Add the gene record to processed suggestions.
:param record: gene record object retrieved from DB
Expand Down Expand Up @@ -117,8 +118,10 @@ def _save_suggest_file(self, output_dir: Path) -> None:
"chromosome",
"strand",
]
today = dt.strftime(dt.today(), "%Y%m%d")
with open(output_dir / f"gene_suggest_{today}.csv", "w") as csvfile:
today = datetime.datetime.strftime(
datetime.datetime.now(tz=datetime.timezone.utc), "%Y%m%d"
)
with (output_dir / f"gene_suggest_{today}.csv").open("w") as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for row in self.genes:
Expand Down
Loading

0 comments on commit 451b87a

Please sign in to comment.