Skip to content

Commit aaf81ae

Browse files
jooolaapricote
andauthored
refactor: convert type comments to type hints (#255)
The converts the type comments into type hints, and adds a few extra typing fixes. Also improved readability by breaking down long typed argument lists on multiple lines. Removing the types from the docstrings will be done in a future PR or gradually while improving the docstrings. * refactor: remove unused results_list_attribute_name * test: add mypy linter * ci: add lint job * chore: convert type comments to annotations * style: break down large arg list on multiline * refactor: fix type hints * chore: fix server type hint Co-authored-by: Julian Tölle <julian.toelle97@gmail.com> * chore: fix type hints * docs: add note about new lint task --------- Co-authored-by: Julian Tölle <julian.toelle97@gmail.com>
1 parent fd01384 commit aaf81ae

40 files changed

Lines changed: 1470 additions & 983 deletions

File tree

.github/workflows/lint.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,19 @@ jobs:
2121

2222
- name: Run pre-commit
2323
run: pre-commit run --all-files --show-diff-on-failure
24+
25+
lint:
26+
runs-on: ubuntu-latest
27+
steps:
28+
- uses: actions/checkout@v3
29+
30+
- name: Setup python
31+
uses: actions/setup-python@v4
32+
with:
33+
python-version: 3.x
34+
35+
- name: Install dependencies
36+
run: make venv
37+
38+
- name: Run lint
39+
run: make lint

.gitlab-ci.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ include:
77
stages:
88
- test
99

10+
lint:
11+
stage: test
12+
13+
image: python:3.11-alpine
14+
before_script:
15+
- make venv
16+
script:
17+
- make lint
18+
1019
test:
1120
stage: test
1221

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ venv:
55
python3 -m venv venv
66
venv/bin/pip install -e .[docs,test]
77

8+
lint: venv
9+
venv/bin/mypy hcloud
10+
811
test: venv
912
venv/bin/pytest -v
1013

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ Build the documentation and open it in your browser:
7575
make docs
7676
```
7777

78+
Lint the code:
79+
80+
```sh
81+
make lint
82+
```
83+
7884
Run tests using the current `python3` version:
7985

8086
```sh

hcloud/_client.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def request(
187187
url: str,
188188
tries: int = 1,
189189
**kwargs,
190-
) -> bytes | dict:
190+
) -> dict:
191191
"""Perform a request to the Hetzner Cloud API, wrapper around requests.request
192192
193193
:param method: HTTP Method to perform the Request
@@ -211,6 +211,7 @@ def request(
211211

212212
if not response.ok:
213213
if content:
214+
assert isinstance(content, dict)
214215
if content["error"]["code"] == "rate_limit_exceeded" and tries < 5:
215216
time.sleep(tries * self._retry_wait_time)
216217
tries = tries + 1
@@ -220,4 +221,5 @@ def request(
220221
else:
221222
self._raise_exception_from_response(response)
222223

223-
return content
224+
# TODO: return an empty dict instead of an empty string when content == "".
225+
return content # type: ignore[return-value]

hcloud/_exceptions.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
22

3+
from typing import Any
4+
35

46
class HCloudException(Exception):
57
"""There was an error while using the hcloud library"""
@@ -8,7 +10,7 @@ class HCloudException(Exception):
810
class APIException(HCloudException):
911
"""There was an error while performing an API Request"""
1012

11-
def __init__(self, code, message, details):
13+
def __init__(self, code: int | str, message: str, details: Any):
1214
super().__init__(message)
1315
self.code = code
1416
self.message = message

hcloud/actions/client.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
import time
4-
from typing import TYPE_CHECKING, NamedTuple
4+
from typing import TYPE_CHECKING, Any, NamedTuple
55

66
from ..core import BoundModelBase, ClientEntityBase, Meta
77
from .domain import Action, ActionFailedException, ActionTimeoutException
@@ -15,7 +15,7 @@ class BoundAction(BoundModelBase):
1515

1616
model = Action
1717

18-
def wait_until_finished(self, max_retries=100):
18+
def wait_until_finished(self, max_retries: int = 100) -> None:
1919
"""Wait until the specific action has status="finished" (set Client.poll_interval to specify a delay between checks)
2020
2121
:param max_retries: int
@@ -43,8 +43,7 @@ class ActionsPageResult(NamedTuple):
4343
class ActionsClient(ClientEntityBase):
4444
_client: Client
4545

46-
def get_by_id(self, id):
47-
# type: (int) -> BoundAction
46+
def get_by_id(self, id: int) -> BoundAction:
4847
"""Get a specific action by its ID.
4948
5049
:param id: int
@@ -56,12 +55,11 @@ def get_by_id(self, id):
5655

5756
def get_list(
5857
self,
59-
status=None, # type: Optional[List[str]]
60-
sort=None, # type: Optional[List[str]]
61-
page=None, # type: Optional[int]
62-
per_page=None, # type: Optional[int]
63-
):
64-
# type: (...) -> PageResults[List[BoundAction]]
58+
status: list[str] | None = None,
59+
sort: list[str] | None = None,
60+
page: int | None = None,
61+
per_page: int | None = None,
62+
) -> ActionsPageResult:
6563
"""Get a list of actions from this account
6664
6765
:param status: List[str] (optional)
@@ -74,7 +72,7 @@ def get_list(
7472
Specifies how many results are returned by page
7573
:return: (List[:class:`BoundAction <hcloud.actions.client.BoundAction>`], :class:`Meta <hcloud.core.domain.Meta>`)
7674
"""
77-
params = {}
75+
params: dict[str, Any] = {}
7876
if status is not None:
7977
params["status"] = status
8078
if sort is not None:
@@ -90,8 +88,11 @@ def get_list(
9088
]
9189
return ActionsPageResult(actions, Meta.parse_meta(response))
9290

93-
def get_all(self, status=None, sort=None):
94-
# type: (Optional[List[str]], Optional[List[str]]) -> List[BoundAction]
91+
def get_all(
92+
self,
93+
status: list[str] | None = None,
94+
sort: list[str] | None = None,
95+
) -> list[BoundAction]:
9596
"""Get all actions of the account
9697
9798
:param status: List[str] (optional)

hcloud/actions/domain.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
from __future__ import annotations
22

3+
from typing import TYPE_CHECKING
4+
35
from dateutil.parser import isoparse
46

57
from .._exceptions import HCloudException
68
from ..core import BaseDomain
79

10+
if TYPE_CHECKING:
11+
from .client import BoundAction
12+
813

914
class Action(BaseDomain):
1015
"""Action Domain
@@ -39,14 +44,14 @@ class Action(BaseDomain):
3944

4045
def __init__(
4146
self,
42-
id,
43-
command=None,
44-
status=None,
45-
progress=None,
46-
started=None,
47-
finished=None,
48-
resources=None,
49-
error=None,
47+
id: int,
48+
command: str | None = None,
49+
status: str | None = None,
50+
progress: int | None = None,
51+
started: str | None = None,
52+
finished: str | None = None,
53+
resources: list[dict] | None = None,
54+
error: dict | None = None,
5055
):
5156
self.id = id
5257
self.command = command
@@ -62,7 +67,8 @@ def __init__(
6267
class ActionException(HCloudException):
6368
"""A generic action exception"""
6469

65-
def __init__(self, action):
70+
def __init__(self, action: Action | BoundAction):
71+
assert self.__doc__ is not None
6672
message = self.__doc__
6773
if action.error is not None and "message" in action.error:
6874
message += f": {action.error['message']}"

0 commit comments

Comments
 (0)