-
-
Notifications
You must be signed in to change notification settings - Fork 35
Add docstring linting (D-class rules) to ruff configuration #247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| """Core functionality for the OpenML server API.""" |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,7 +3,7 @@ | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def _str_to_num(string: str) -> int | float | str: | ||||||||||||||||||||||||||||||||||
| """Tries to convert the string to integer, otherwise float, otherwise returns the input.""" | ||||||||||||||||||||||||||||||||||
| """Try to convert the string to integer, otherwise float, otherwise returns the input.""" | ||||||||||||||||||||||||||||||||||
| if string.isdigit(): | ||||||||||||||||||||||||||||||||||
| return int(string) | ||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||
|
|
@@ -13,8 +13,10 @@ def _str_to_num(string: str) -> int | float | str: | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def nested_str_to_num(obj: Any) -> Any: | ||||||||||||||||||||||||||||||||||
| """Recursively tries to convert all strings in the object to numbers. | ||||||||||||||||||||||||||||||||||
| For dictionaries, only the values will be converted.""" | ||||||||||||||||||||||||||||||||||
| """Recursively try to convert all strings in the object to numbers. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| For dictionaries, only the values will be converted. | ||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||
|
Comment on lines
15
to
+19
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: Docstring for nested_str_to_num under-describes behavior for non-dict containers. Please also document how non-dict containers are handled (e.g., that lists/tuples/sets are fully traversed and all string elements are converted where possible) so the helper’s behavior is clear at call sites.
Suggested change
|
||||||||||||||||||||||||||||||||||
| if isinstance(obj, str): | ||||||||||||||||||||||||||||||||||
| return _str_to_num(obj) | ||||||||||||||||||||||||||||||||||
| if isinstance(obj, Mapping): | ||||||||||||||||||||||||||||||||||
|
|
@@ -25,8 +27,10 @@ def nested_str_to_num(obj: Any) -> Any: | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def nested_num_to_str(obj: Any) -> Any: | ||||||||||||||||||||||||||||||||||
| """Recursively tries to convert all numbers in the object to strings. | ||||||||||||||||||||||||||||||||||
| For dictionaries, only the values will be converted.""" | ||||||||||||||||||||||||||||||||||
| """Recursively try to convert all numbers in the object to strings. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| For dictionaries, only the values will be converted. | ||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||
| if isinstance(obj, str): | ||||||||||||||||||||||||||||||||||
| return obj | ||||||||||||||||||||||||||||||||||
| if isinstance(obj, Mapping): | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| """Database access for the OpenML server API.""" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| """API routers for the OpenML server API.""" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| """Routers for the MLDCAT-AP API.""" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| """Routers for the OpenML API.""" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| """Pydantic schemas for the OpenML server API.""" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| """Dataset schemas for the OpenML server API.""" | ||
|
|
||
| from enum import StrEnum | ||
|
|
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,6 @@ | ||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||
| Based on MLDCAT-AP 1.0.0: https://semiceu.github.io/MLDCAT-AP/releases/1.0.0/ | ||||||||||||||||||||||||||||||
| """MLDCAT-AP schema definitions based on MLDCAT-AP 1.0.0. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| See: https://semiceu.github.io/MLDCAT-AP/releases/1.0.0/ | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| This is an application profile, aimed to extend the use of DCAT-AP, | ||||||||||||||||||||||||||||||
| originally envisaged for the description of a machine learning process, | ||||||||||||||||||||||||||||||
|
|
@@ -18,7 +19,7 @@ | |||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| class JsonLDQualifiedLiteral(BaseModel): | ||||||||||||||||||||||||||||||
| """Base class for all JSON-LD objects""" | ||||||||||||||||||||||||||||||
| """Base class for all JSON-LD objects.""" | ||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
📝 Proposed fix- """Base class for all JSON-LD objects."""
+ """A JSON-LD qualified literal pairing an explicit type with a string value."""📝 Committable suggestion
Suggested change
🤖 Prompt for AI AgentsIncorrect docstring copy-pasted from
📝 Proposed fix- """Base class for all JSON-LD objects."""
+ """A JSON-LD qualified literal with an explicit type and value."""📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| type_: str = Field(serialization_alias="@type") | ||||||||||||||||||||||||||||||
| value: str = Field(serialization_alias="@value") | ||||||||||||||||||||||||||||||
|
|
@@ -30,7 +31,7 @@ class JsonLDQualifiedLiteral(BaseModel): | |||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| class JsonLDObject(BaseModel, ABC): | ||||||||||||||||||||||||||||||
| """Base class for all JSON-LD objects""" | ||||||||||||||||||||||||||||||
| """Base class for all JSON-LD objects.""" | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| id_: str = Field(serialization_alias="@id") | ||||||||||||||||||||||||||||||
| type_: str = Field(serialization_alias="@type") | ||||||||||||||||||||||||||||||
|
|
@@ -48,7 +49,7 @@ class JsonLDObjectReference[T: JsonLDObject](BaseModel): | |||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @classmethod | ||||||||||||||||||||||||||||||
| def to(cls, json_ld_object: T) -> JsonLDObjectReference[T]: | ||||||||||||||||||||||||||||||
| """Create a reference to `json_ld_object`""" | ||||||||||||||||||||||||||||||
| """Create a reference to `json_ld_object`.""" | ||||||||||||||||||||||||||||||
| return cls(id_=json_ld_object.id_) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @model_serializer | ||||||||||||||||||||||||||||||
|
|
@@ -57,7 +58,7 @@ def ser_model(self) -> str: | |||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| class AccessRights(StrEnum): | ||||||||||||||||||||||||||||||
| """Recommend values for 'access rights' within DCAT-AP context""" | ||||||||||||||||||||||||||||||
| """Recommend values for 'access rights' within DCAT-AP context.""" | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # https://op.europa.eu/en/web/eu-vocabularies/dataset/-/resource?uri=http://publications.europa.eu/resource/dataset/access-right | ||||||||||||||||||||||||||||||
| PUBLIC = "PUBLIC" | ||||||||||||||||||||||||||||||
|
|
@@ -66,9 +67,10 @@ class AccessRights(StrEnum): | |||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| class Agent(JsonLDObject): | ||||||||||||||||||||||||||||||
| """Any entity carrying out actions with respect to the (Core) entities Catalogue, | ||||||||||||||||||||||||||||||
| Datasets, Data Services and Distributions. If the Agent is an organisation, | ||||||||||||||||||||||||||||||
| the use of the Organization Ontology is recommended. | ||||||||||||||||||||||||||||||
| """Any entity carrying out actions with respect to the (Core) entities. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Catalogue, Datasets, Data Services and Distributions. If the Agent is an | ||||||||||||||||||||||||||||||
| organisation, the use of the Organization Ontology is recommended. | ||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||
|
Comment on lines
69
to
74
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick (typo): Agent docstring reads as two separate sentences where the second is a fragment. Consider reflowing to something like:
Suggested change
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| type_: Literal["Agent"] = Field(default="Agent", serialization_alias="@type") | ||||||||||||||||||||||||||||||
|
|
@@ -81,6 +83,7 @@ class Agent(JsonLDObject): | |||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| class MD5Checksum(JsonLDObject): | ||||||||||||||||||||||||||||||
| """A value that allows the contents of a file to be authenticated. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| This class allows the results of a variety of checksum and cryptographic | ||||||||||||||||||||||||||||||
| message digest algorithms to be represented. | ||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| from datetime import datetime | ||
| from datetime import UTC, datetime | ||
| from http import HTTPStatus | ||
|
|
||
| import httpx | ||
|
|
@@ -494,11 +494,8 @@ def test_create_task_study(py_api: TestClient) -> None: | |
| } | ||
| new_study = study.json() | ||
|
|
||
| creation_date = datetime.strptime( | ||
| new_study.pop("creation_date"), | ||
| "%Y-%m-%dT%H:%M:%S", | ||
| ) | ||
| assert creation_date.date() == datetime.now().date() | ||
| creation_date = datetime.fromisoformat(new_study.pop("creation_date")) | ||
| assert creation_date.date() == datetime.now(UTC).date() | ||
|
Comment on lines
+497
to
+498
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (testing): Add an explicit assertion that Since this change is about enforcing timezone-aware datetimes, this regression test should also assert that the returned value is explicitly timezone-aware and in UTC, not just that the date matches. For example: creation_date = datetime.fromisoformat(new_study.pop("creation_date"))
assert creation_date.tzinfo is UTC
assert creation_date.date() == datetime.now(UTC).date()This ensures the API contract (UTC-aware datetime) is verified, rather than only the calendar date. Suggested implementation: from datetime import datetime, UTC
import httpx
}
new_study = study.json() new_study = study.json()
creation_date = datetime.fromisoformat(new_study.pop("creation_date"))
assert creation_date.tzinfo is UTC
assert creation_date.date() == datetime.now(UTC).date()
Comment on lines
+497
to
+498
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n tests/routers/openml/study_test.py | sed -n '490,510p'Repository: openml/server-api Length of output: 795 🏁 Script executed: # Find Pydantic models related to Study
rg -t py "class.*Study" --max-count=20Repository: openml/server-api Length of output: 252 🏁 Script executed: # Look for any custom datetime serializers or Pydantic config
rg -t py "json_encoders|ConfigDict|model_config|datetime" tests/routers/openml/study_test.py -A 2 -B 2Repository: openml/server-api Length of output: 326 🌐 Web query:
💡 Result: In Pydantic v2, What you get by default (UTC-aware)If your value is already UTC-aware ( Enforce “UTC (and optionally
|
||
| assert new_study == expected | ||
|
|
||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
fd --type f --extension py . tests/Repository: openml/server-api
Length of output: 991
Change glob pattern to recursively match nested test files.
The pattern
"tests/*"only matches files directly in thetests/directory. However, the repository contains nested test files at multiple levels (e.g.,tests/routers/openml/study_test.py,tests/database/flows_test.py,tests/routers/openml/migration/datasets_migration_test.py). The D (docstring) rules will incorrectly fire on these nested files instead of being suppressed. Use"tests/**"for recursive coverage.🔧 Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents