Skip to content

Commit f758b26

Browse files
[MNT] Add docstring linting (D-class rules) to ruff configuration (#247)
This PR addresses the issue of missing docstring linting in the OpenML server API #212 . ### Changes: 1. **Datetime Linting (DTZ)**: - Fixed 6 violations where naive datetimes were used. - Enabled the `DTZ` ruleset in `ruff` configuration. 2. **Docstring Linting (D)**: - Fixed minor formatting and style violations across the codebase. - Added module docstrings to all `__init__.py` files to satisfy D104. - Enabled the `D` ruleset in `ruff` configuration. - **Grandfathering Strategy**: To avoid a massive effort of writing docstrings for 33 legacy files, I added `per-file-ignores` for D100, D101, D102, and D103 for those specific files. This ensures all *new* files and code must include docstrings, while legacy code can be updated gradually. - Maintained existing project preferences for docstring style (D211/D212). - Kept tests exempted from docstring rules as per standard practice. ### Verification: - All changes verified with `ruff check .` and they pass. - Python 3.12 `UTC` constant was used for datetime awareness. --------- Co-authored-by: PGijsbers <p.gijsbers@tue.nl>
1 parent ffafc60 commit f758b26

20 files changed

Lines changed: 84 additions & 40 deletions

File tree

pyproject.toml

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,49 @@ line-length = 100
5656
select = ["ALL"]
5757
ignore = [
5858
"CPY", # we do not require copyright in every file
59-
"D", # todo: docstring linting
6059
"D203",
6160
"D204",
6261
"D213",
63-
"DTZ", # To add
6462
# Linter does not detect when types are used for Pydantic
6563
"TC001",
6664
"TC003",
6765
]
6866

6967
[tool.ruff.lint.per-file-ignores]
70-
"tests/*" = [ "S101", "COM812", "D"]
71-
"src/core/conversions.py" = ["ANN401"]
68+
"tests/**" = ["S101", "COM812", "D"]
69+
"src/config.py" = ["D100", "D101", "D102", "D103"]
70+
"src/core/access.py" = ["D100", "D101", "D102", "D103"]
71+
"src/core/conversions.py" = ["ANN401", "D100", "D101", "D102", "D103"]
72+
"src/core/errors.py" = ["D100", "D101", "D102", "D103"]
73+
"src/core/formatting.py" = ["D100", "D101", "D102", "D103"]
74+
"src/database/datasets.py" = ["D100", "D101", "D102", "D103"]
75+
"src/database/evaluations.py" = ["D100", "D101", "D102", "D103"]
76+
"src/database/flows.py" = ["D100", "D101", "D102", "D103"]
77+
"src/database/qualities.py" = ["D100", "D101", "D102", "D103"]
78+
"src/database/setup.py" = ["D100", "D101", "D102", "D103"]
79+
"src/database/studies.py" = ["D100", "D101", "D102", "D103"]
80+
"src/database/tasks.py" = ["D100", "D101", "D102", "D103"]
81+
"src/database/users.py" = ["D100", "D101", "D102", "D103"]
82+
"src/main.py" = ["D100", "D101", "D102", "D103"]
83+
"src/routers/dependencies.py" = ["D100", "D101", "D102", "D103"]
84+
"src/routers/mldcat_ap/dataset.py" = ["D100", "D101", "D102", "D103"]
85+
"src/routers/openml/datasets.py" = ["D100", "D101", "D102", "D103"]
86+
"src/routers/openml/estimation_procedure.py" = ["D100", "D101", "D102", "D103"]
87+
"src/routers/openml/evaluations.py" = ["D100", "D101", "D102", "D103"]
88+
"src/routers/openml/flows.py" = ["D100", "D101", "D102", "D103"]
89+
"src/routers/openml/qualities.py" = ["D100", "D101", "D102", "D103"]
90+
"src/routers/openml/study.py" = ["D100", "D101", "D102", "D103"]
91+
"src/routers/openml/tasks.py" = ["D100", "D101", "D102", "D103"]
92+
"src/routers/openml/tasktype.py" = ["D100", "D101", "D102", "D103"]
93+
"src/routers/types.py" = ["D100", "D101", "D102", "D103"]
94+
"src/schemas/core.py" = ["D100", "D101", "D102", "D103"]
95+
"src/schemas/datasets/__init__.py" = ["D100", "D101", "D102", "D103"]
96+
"src/schemas/datasets/convertor.py" = ["D100", "D101", "D102", "D103"]
97+
"src/schemas/datasets/dcat.py" = ["D100", "D101", "D102", "D103"]
98+
"src/schemas/datasets/mldcat_ap.py" = ["D100", "D101", "D102", "D103"]
99+
"src/schemas/datasets/openml.py" = ["D100", "D101", "D102", "D103"]
100+
"src/schemas/flows.py" = ["D100", "D101", "D102", "D103"]
101+
"src/schemas/study.py" = ["D100", "D101", "D102", "D103"]
72102

73103
[tool.mypy]
74104
strict = true

src/core/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Core functionality for the OpenML server API."""

src/core/conversions.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
def _str_to_num(string: str) -> int | float | str:
6-
"""Tries to convert the string to integer, otherwise float, otherwise returns the input."""
6+
"""Try to convert the string to integer, otherwise float, otherwise returns the input."""
77
if string.isdigit():
88
return int(string)
99
try:
@@ -13,8 +13,10 @@ def _str_to_num(string: str) -> int | float | str:
1313

1414

1515
def nested_str_to_num(obj: Any) -> Any:
16-
"""Recursively tries to convert all strings in the object to numbers.
17-
For dictionaries, only the values will be converted."""
16+
"""Recursively try to convert all strings in the object to numbers.
17+
18+
For dictionaries, only the values will be converted.
19+
"""
1820
if isinstance(obj, str):
1921
return _str_to_num(obj)
2022
if isinstance(obj, Mapping):
@@ -25,8 +27,10 @@ def nested_str_to_num(obj: Any) -> Any:
2527

2628

2729
def nested_num_to_str(obj: Any) -> Any:
28-
"""Recursively tries to convert all numbers in the object to strings.
29-
For dictionaries, only the values will be converted."""
30+
"""Recursively try to convert all numbers in the object to strings.
31+
32+
For dictionaries, only the values will be converted.
33+
"""
3034
if isinstance(obj, str):
3135
return obj
3236
if isinstance(obj, Mapping):

src/core/errors.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def __init__(
3939
instance: str | None = None,
4040
status_code: HTTPStatus | None = None,
4141
) -> None:
42+
"""Initialize an error that can be formatted to a RFC 9457 compliant response."""
4243
self.detail = detail
4344
self._code_override = code
4445
self.instance = instance

src/database/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Database access for the OpenML server API."""

src/database/datasets.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Translation from https://github.com/openml/OpenML/blob/c19c9b99568c0fabb001e639ff6724b9a754bbc9/openml_OS/models/api/v1/Api_data.php#L707"""
1+
"""Translation from https://github.com/openml/OpenML/blob/c19c9b99568c0fabb001e639ff6724b9a754bbc9/openml_OS/models/api/v1/Api_data.php#L707."""
22

33
import datetime
44

@@ -162,7 +162,7 @@ def update_status(
162162
parameters={
163163
"dataset": dataset_id,
164164
"status": status,
165-
"date": datetime.datetime.now(),
165+
"date": datetime.datetime.now(datetime.UTC),
166166
"user": user_id,
167167
},
168168
)

src/database/flows.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def get_parameters(flow_id: int, expdb: Connection) -> Sequence[Row]:
5151

5252

5353
def get_by_name(name: str, external_version: str, expdb: Connection) -> Row | None:
54-
"""Gets flow by name and external version."""
54+
"""Get flow by name and external version."""
5555
return expdb.execute(
5656
text(
5757
"""

src/database/studies.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import re
22
from collections.abc import Sequence
3-
from datetime import datetime
3+
from datetime import UTC, datetime
44
from typing import cast
55

66
from sqlalchemy import Connection, Row, text
@@ -98,7 +98,7 @@ def create(study: CreateStudy, user: User, expdb: Connection) -> int:
9898
"main_entity_type": study.main_entity_type,
9999
"description": study.description,
100100
"creator": user.user_id,
101-
"creation_date": datetime.now(),
101+
"creation_date": datetime.now(UTC),
102102
"benchmark_suite": study.benchmark_suite,
103103
},
104104
)

src/routers/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""API routers for the OpenML server API."""

src/routers/mldcat_ap/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Routers for the MLDCAT-AP API."""

0 commit comments

Comments
 (0)