From 8306787e206fa7b4d9f143e16137351f31dedc32 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 5 Mar 2026 10:50:08 +0100 Subject: [PATCH] Add ruff rules for Pylint, Refurb, and type hints --- .pre-commit-config.yaml | 2 +- pyproject.toml | 34 ++++++++++++++++------------------ src/datastar_py/attributes.py | 12 ++++++------ src/datastar_py/sse.py | 6 +++--- 4 files changed, 26 insertions(+), 28 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4b49217..97da3d8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.15.2 + rev: v0.15.4 hooks: # Run the linter. - id: ruff-check diff --git a/pyproject.toml b/pyproject.toml index 61d0868..f1254f9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,23 +59,20 @@ dev = [ [tool.ruff] line-length = 99 lint.select = [ - # Annotations - "ANN", - # flake8-bugbear - "B", - "D", - # pycodestyle - "E", - # Pyflakes - "F", - # isort - "I", - # Ruff specific - "RUF", - # flake8-simplify - "SIM", - # pyupgrade - "UP", + "ANN", # annotations + "B", # flake8-bugbear + "D", # pydocstyle + "DTZ", # flake8-datetimez + "E", # pycodestyle + "F", # Pyflakes + "FURB", # refurb + "I", # isort + "PL", # Pylint + "PYI", # flake8-pyi + "RUF", # Ruff-specific rules + "SIM", # flake8-simplify + "SLOT", # flake8-slots + "UP", # pyupgrade ] lint.ignore = [ "D100", # undocumented-public-module @@ -90,5 +87,6 @@ lint.ignore = [ "D415", # Duplicate of D400 "E501", ] -lint.per-file-ignores."examples/**/*.py" = [ "ANN" ] +lint.per-file-ignores."examples/**/*.py" = [ "ANN", "DTZ005", "PLC0415" ] lint.fixable = [ "ALL" ] +lint.pylint.allow-magic-value-types = [ "int", "str" ] diff --git a/src/datastar_py/attributes.py b/src/datastar_py/attributes.py index 7732a88..27391a6 100644 --- a/src/datastar_py/attributes.py +++ b/src/datastar_py/attributes.py @@ -127,13 +127,13 @@ def signals( :param expressions_: If True, the values of the signals will be evaluated as expressions rather than literals. """ - signals = {**(signals_dict if signals_dict else {}), **signals} + signals = {**(signals_dict or {}), **signals} val = _js_object(signals) if expressions_ else json.dumps(signals) return SignalsAttr(value=val, alias=self._alias) def computed(self, computed_dict: Mapping | None = None, /, **computed: str) -> BaseAttr: """Create signals that are computed based on an expression.""" - computed = {**(computed_dict if computed_dict else {}), **computed} + computed = {**(computed_dict or {}), **computed} first, *rest = ( BaseAttr("computed", key=sig, value=expr, alias=self._alias) for sig, expr in computed.items() @@ -152,7 +152,7 @@ def ignore(self) -> IgnoreAttr: def attr(self, attr_dict: Mapping | None = None, /, **attrs: str) -> BaseAttr: """Set the value of any HTML attributes to expressions, and keep them in sync.""" - attrs = {**(attr_dict if attr_dict else {}), **attrs} + attrs = {**(attr_dict or {}), **attrs} return BaseAttr("attr", value=_js_object(attrs), alias=self._alias) def bind(self, signal_name: str) -> BaseAttr: @@ -161,7 +161,7 @@ def bind(self, signal_name: str) -> BaseAttr: def class_(self, class_dict: Mapping | None = None, /, **classes: str) -> BaseAttr: """Add or removes classes to or from an element based on expressions.""" - classes = {**(class_dict if class_dict else {}), **classes} + classes = {**(class_dict or {}), **classes} return BaseAttr("class", value=_js_object(classes), alias=self._alias) def init(self, expression: str) -> InitAttr: @@ -216,7 +216,7 @@ def show(self, expression: str) -> BaseAttr: def style(self, style_dict: Mapping | None = None, /, **styles: str) -> BaseAttr: """Set the value of inline CSS styles on an element based on an expression, and keeps them in sync.""" - styles = {**(style_dict if style_dict else {}), **styles} + styles = {**(style_dict or {}), **styles} return BaseAttr("style", value=_js_object(styles), alias=self._alias) def text(self, expression: str) -> BaseAttr: @@ -633,7 +633,7 @@ def threshold(self, threshold: int) -> Self: class OnIntervalAttr(BaseAttr, ViewtransitionMod): _attr = "on-interval" - def duration(self, duration: int | float | str, *, leading: bool = False) -> Self: + def duration(self, duration: float | str, *, leading: bool = False) -> Self: """Set the interval duration.""" self._mods["duration"] = [str(duration)] if leading: diff --git a/src/datastar_py/sse.py b/src/datastar_py/sse.py index c5f7577..8b00042 100644 --- a/src/datastar_py/sse.py +++ b/src/datastar_py/sse.py @@ -5,7 +5,7 @@ from itertools import chain from typing import Literal, Protocol, TypeAlias, overload, runtime_checkable -import datastar_py.consts as consts +from datastar_py import consts from datastar_py.attributes import _escape SSE_HEADERS: dict[str, str] = { @@ -28,7 +28,7 @@ def __html__(self) -> str: ... class DatastarEvent(str): - pass + __slots__ = () # 0..N datastar events @@ -83,7 +83,7 @@ def patch_elements( retry_duration: int | None = None, ) -> DatastarEvent: ... @classmethod - def patch_elements( + def patch_elements( # noqa: PLR0913 too many arguments cls, elements: str | _HtmlProvider | None = None, selector: str | None = None,