diff --git a/bmds_ui/analysis/api.py b/bmds_ui/analysis/api.py
index 1a2c3015..6fcdea08 100644
--- a/bmds_ui/analysis/api.py
+++ b/bmds_ui/analysis/api.py
@@ -52,7 +52,7 @@ def patch_inputs(self, request, *args, **kwargs):
try:
validators.validate_input(data, partial=partial)
except ValidationError as err:
- raise exceptions.ValidationError(err.message)
+ raise exceptions.ValidationError(err.message) from None
instance.reset_execution()
instance.inputs = data
@@ -207,7 +207,7 @@ def _run_analysis(self, request) -> PolyKAdjustment:
try:
settings = pydantic_validate(request.data, schema.PolyKInput)
except ValidationError as err:
- raise exceptions.ValidationError(err.message)
+ raise exceptions.ValidationError(err.message) from None
return settings.calculate()
def create(self, request, *args, **kwargs):
diff --git a/bmds_ui/analysis/serializers.py b/bmds_ui/analysis/serializers.py
index 2b2b01f7..9759c107 100644
--- a/bmds_ui/analysis/serializers.py
+++ b/bmds_ui/analysis/serializers.py
@@ -65,5 +65,5 @@ def validate_inputs(self, value):
try:
validators.validate_input(value)
except ValueError as err:
- raise serializers.ValidationError(err)
+ raise serializers.ValidationError("Validation failed") from err
return value
diff --git a/bmds_ui/common/templatetags/bs4.py b/bmds_ui/common/templatetags/bs4.py
index 8b12c5bd..6ad26d93 100644
--- a/bmds_ui/common/templatetags/bs4.py
+++ b/bmds_ui/common/templatetags/bs4.py
@@ -8,8 +8,7 @@
from django import template
from django.utils import timezone
-from django.utils.html import escapejs
-from django.utils.safestring import mark_safe
+from django.utils.html import escapejs, format_html
from plotly.graph_objs._figure import Figure
register = template.Library()
@@ -39,7 +38,7 @@ def render(self, context):
@register.simple_tag
def icon(name: str):
- return mark_safe(f'')
+ return format_html('', name=name)
@register.simple_tag()
@@ -48,18 +47,18 @@ def plotly(fig: Figure) -> str | None:
if fig is None:
return ""
id = uuid4()
- return mark_safe(
- dedent(
- f"""
+ return format_html(
+ dedent("""
Loading...
"""
- )
+ """),
+ id=id,
+ json=escapejs(fig.to_json()),
)
diff --git a/bmds_ui/common/validation.py b/bmds_ui/common/validation.py
index ee34f8b7..8b044b11 100644
--- a/bmds_ui/common/validation.py
+++ b/bmds_ui/common/validation.py
@@ -23,4 +23,4 @@ def pydantic_validate(data: Any, model: type[T]) -> T:
try:
return model.model_validate(data)
except PydanticValidationError as err:
- raise ValidationError(err.json())
+ raise ValidationError(err.json()) from None
diff --git a/bmds_ui/common/views.py b/bmds_ui/common/views.py
index 7ed1d3b4..c884f544 100644
--- a/bmds_ui/common/views.py
+++ b/bmds_ui/common/views.py
@@ -214,11 +214,11 @@ def uuid_or_404(value: str) -> UUID:
try:
return UUID(value)
except ValueError:
- raise Http404()
+ raise Http404() from None
def int_or_404(value: str) -> int:
try:
return int(value)
except ValueError:
- raise Http404()
+ raise Http404() from None
diff --git a/bmds_ui/desktop/components/database_form.py b/bmds_ui/desktop/components/database_form.py
index e5f15792..9e5e75b2 100644
--- a/bmds_ui/desktop/components/database_form.py
+++ b/bmds_ui/desktop/components/database_form.py
@@ -43,14 +43,14 @@ def additional_path_checks(path: Path):
try:
path.exists()
except PermissionError:
- raise ValueError(f"Permission denied: {path}")
+ raise ValueError(f"Permission denied: {path}") from None
# create parent path if it doesn't already exist
if not path.parent.exists():
try:
path.parent.mkdir(parents=True)
except Exception:
- raise ValueError(f"Cannot create path {path.parent}")
+ raise ValueError(f"Cannot create path {path.parent}") from None
# check path is writable
if not path.exists():
@@ -59,7 +59,7 @@ def additional_path_checks(path: Path):
f.write("test")
f.flush()
except Exception:
- raise ValueError(f"Cannot write to {path.parent}")
+ raise ValueError(f"Cannot write to {path.parent}") from None
# check existing database is loadable and writeable
if path.exists():
@@ -70,7 +70,7 @@ def additional_path_checks(path: Path):
conn.commit()
conn.close()
except (sqlite3.DatabaseError, sqlite3.OperationalError):
- raise ValueError(f"Cannot edit database {path}. Is this a sqlite database?")
+ raise ValueError(f"Cannot edit database {path}. Is this a sqlite database?") from None
class NullWidget(Widget):
diff --git a/bmds_ui/desktop/config.py b/bmds_ui/desktop/config.py
index e2202b2a..fe69e25c 100644
--- a/bmds_ui/desktop/config.py
+++ b/bmds_ui/desktop/config.py
@@ -159,9 +159,7 @@ def get(cls) -> DesktopConfig:
try:
cls._config = DesktopConfig.model_validate_json(cls._config_path.read_text())
except ValidationError as err:
- raise DesktopException(
- f"Cannot parse configuration: {cls._config_path}\n\nSpecific error:{err}"
- )
+ raise DesktopException(f"Cannot parse configuration: {cls._config_path}") from err
return cls._config
@classmethod
diff --git a/pyproject.toml b/pyproject.toml
index 9c728622..ae32a672 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -112,16 +112,12 @@ omit = [
]
[tool.ruff]
+exclude = ["scripts"]
line-length = 100
-target-version = "py311"
-
-[tool.ruff.lint]
-select = ["F", "E", "W", "I", "UP", "S", "B", "T20", "RUF"]
-ignore = ["E501", "B904", "B007", "S308", "S113", "S314"]
-unfixable = ["F401", "F841"]
-
-[tool.ruff.lint.isort]
-known-first-party = ["bmds_ui", "pybmds"]
+lint.select = ["F", "E", "W", "I", "UP", "S", "B", "T20", "ERA", "NPY", "RUF", "PTH"]
+lint.ignore = ["E501"]
+lint.unfixable = ["F401", "F841"]
+lint.isort.known-first-party = ["bmds_ui", "pybmds"]
[tool.ruff.lint.per-file-ignores]
"test_*.py" = ["S101", "S106"]
diff --git a/tests/analysis/test_executor.py b/tests/analysis/test_executor.py
index 5ed921a1..b4d0b05e 100644
--- a/tests/analysis/test_executor.py
+++ b/tests/analysis/test_executor.py
@@ -72,14 +72,14 @@ def _expected_degree(session, n: int):
degrees = set([model.settings.degree for model in session.frequentist.models])
assert degrees == set(list(range(1, n + 1)))
- # degree = 1
+ # check when degree = 1
data = deepcopy(complete_dichotomous)
data["models"] = {"frequentist_restricted": ["Multistage"]}
data["dataset_options"][0]["degree"] = 1
session = AnalysisSession.create(data, 0, 0)
_expected_degree(session, 1)
- # degree = 2
+ # check when degree = 2
data = deepcopy(complete_dichotomous)
data["models"] = {"frequentist_restricted": ["Multistage"]}
data["dataset_options"][0]["degree"] = 2
diff --git a/tests/common/test_api.py b/tests/common/test_api.py
index 84e66c6a..913d9919 100644
--- a/tests/common/test_api.py
+++ b/tests/common/test_api.py
@@ -45,7 +45,7 @@ def test_throttle(self):
# success - admin
url = reverse("api:healthcheck-throttle")
- for i in range(5):
+ for _ in range(5):
resp = admin.get(url)
assert resp.status_code == 200
assert "identity" in resp.data
diff --git a/tests/common/test_diagnostics.py b/tests/common/test_diagnostics.py
index c3c4281e..dcb81208 100644
--- a/tests/common/test_diagnostics.py
+++ b/tests/common/test_diagnostics.py
@@ -6,7 +6,6 @@
@pytest.fixture
-@pytest.mark.django_db
def admin_client():
client = Client()
client.login(username="admin@bmdsonline.org", password="pw")
diff --git a/tests/common/test_worker_health.py b/tests/common/test_worker_health.py
index 192cd779..3b3f6762 100644
--- a/tests/common/test_worker_health.py
+++ b/tests/common/test_worker_health.py
@@ -19,7 +19,7 @@ def test_worker_healthcheck():
# has recent data; should be healthy
worker.MAX_SIZE = 5
- for i in range(worker.MAX_SIZE + 2):
+ for _ in range(worker.MAX_SIZE + 2):
worker.push()
assert worker.healthy() is True
assert worker.series().size == worker.MAX_SIZE
diff --git a/tests/desktop/test_config.py b/tests/desktop/test_config.py
index d49d9135..fcbbc50f 100644
--- a/tests/desktop/test_config.py
+++ b/tests/desktop/test_config.py
@@ -14,4 +14,4 @@ def test_get_version_path():
def test_get_app_home():
assert "bmds" in str(config.get_app_home())
- assert Path(".") == config.get_app_home(path_str=".")
+ assert Path() == config.get_app_home(path_str=".")