Skip to content

Commit bb7f43b

Browse files
committed
Enable mypy type checking
1 parent ffee8e7 commit bb7f43b

File tree

14 files changed

+63
-36
lines changed

14 files changed

+63
-36
lines changed

.pre-commit-config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ repos:
2323
hooks:
2424
- id: isort
2525
name: isort (python)
26+
- repo: https://github.com/pre-commit/mirrors-mypy
27+
rev: v1.11.2
28+
hooks:
29+
- id: mypy
30+
additional_dependencies:
31+
[types-pyyaml==6.0.12.20240808, types-aiofiles==24.1.0.20240626]
2632
- repo: local
2733
hooks:
2834
- id: pytest

goosebit/api/v1/devices/device/routes.py

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

3-
from fastapi import APIRouter, Depends, Security
3+
from fastapi import APIRouter, Depends, HTTPException, Security
44
from fastapi.requests import Request
55

66
from goosebit.api.v1.devices.device.responses import DeviceLogResponse, DeviceResponse
@@ -15,7 +15,10 @@
1515
dependencies=[Security(validate_user_permissions, scopes=["home.read"])],
1616
)
1717
async def device_get(_: Request, updater: UpdateManager = Depends(get_update_manager)) -> DeviceResponse:
18-
return await DeviceResponse.convert(await updater.get_device())
18+
device = await updater.get_device()
19+
if device is None:
20+
raise HTTPException(404)
21+
return await DeviceResponse.convert(device)
1922

2023

2124
@router.get(
@@ -24,4 +27,6 @@ async def device_get(_: Request, updater: UpdateManager = Depends(get_update_man
2427
)
2528
async def device_logs(_: Request, updater: UpdateManager = Depends(get_update_manager)) -> DeviceLogResponse:
2629
device = await updater.get_device()
30+
if device is None:
31+
raise HTTPException(404)
2732
return DeviceLogResponse(log=device.last_log)

goosebit/api/v1/software/routes.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,14 @@ async def post_update(_: Request, file: UploadFile | None = File(None), url: str
6666
raise HTTPException(409, "Software with same URL already exists and is referenced by rollout")
6767

6868
software = await create_software_update(url, None)
69-
else:
69+
elif file is not None:
7070
# local file
7171
file_path = config.artifacts_dir.joinpath(file.filename)
7272

7373
async with aiofiles.tempfile.NamedTemporaryFile("w+b") as f:
7474
await f.write(await file.read())
75-
software = await create_software_update(file_path.absolute().as_uri(), Path(f.name))
75+
software = await create_software_update(file_path.absolute().as_uri(), Path(str(f.name)))
76+
else:
77+
raise HTTPException(422)
7678

7779
return {"id": software.id}

goosebit/auth/__init__.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ def create_token(username: str) -> str:
2727
return jwt.encode(header={"alg": "HS256"}, claims={"username": username}, key=config.secret_key)
2828

2929

30-
def get_user_from_token(token: str) -> User | None:
30+
def get_user_from_token(token: str | None) -> User | None:
3131
if token is None:
32-
return
32+
return None
3333
try:
3434
token_data = jwt.decode(token, config.secret_key)
3535
username = token_data.claims["username"]
3636
return USERS.get(username)
3737
except (BadSignatureError, LookupError, ValueError):
38-
pass
38+
return None
3939

4040

4141
def login_user(username: str, password: str) -> str:
@@ -58,17 +58,17 @@ def login_user(username: str, password: str) -> str:
5858

5959

6060
def get_current_user(
61-
session_token: Annotated[str, Depends(session_auth)] = None,
62-
oauth2_token: Annotated[str, Depends(oauth2_auth)] = None,
63-
) -> User:
61+
session_token: Annotated[str | None, Depends(session_auth)] = None,
62+
oauth2_token: Annotated[str | None, Depends(oauth2_auth)] = None,
63+
) -> User | None:
6464
session_user = get_user_from_token(session_token)
6565
oauth2_user = get_user_from_token(oauth2_token)
6666
user = session_user or oauth2_user
6767
return user
6868

6969

7070
# using | Request because oauth2_auth.__call__ expects is
71-
async def get_user_from_request(connection: HTTPConnection | Request) -> User:
71+
async def get_user_from_request(connection: HTTPConnection | Request) -> User | None:
7272
token = await session_auth(connection) or await oauth2_auth(connection)
7373
return get_user_from_token(token)
7474

goosebit/schema/devices.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ class DeviceSchema(BaseModel):
3535
hw_revision: str
3636
feed: str
3737
progress: int | None
38-
last_state: Annotated[UpdateStateSchema, BeforeValidator(UpdateStateSchema.convert)]
39-
update_mode: Annotated[UpdateModeSchema, BeforeValidator(UpdateModeSchema.convert)]
38+
last_state: Annotated[UpdateStateSchema, BeforeValidator(UpdateStateSchema.convert)] # type: ignore[valid-type]
39+
update_mode: Annotated[UpdateModeSchema, BeforeValidator(UpdateModeSchema.convert)] # type: ignore[valid-type]
4040
force_update: bool
4141
last_ip: str | None
4242
last_seen: int | None

goosebit/ui/nav.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ class Navigation:
22
def __init__(self):
33
self.items = []
44

5-
def route(self, text: str, permissions: str = None):
5+
def route(self, text: str, permissions: str | None = None):
66
def decorator(func):
77
self.items.append({"function": func.__name__, "text": text, "permissions": permissions})
88
return func

goosebit/ui/routes.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ async def ui_root(request: Request):
2424
"/home",
2525
dependencies=[Security(validate_user_permissions, scopes=["home.read"])],
2626
)
27-
@nav.route("Home", permissions=["home.read"])
27+
@nav.route("Home", permissions="home.read")
2828
async def home_ui(request: Request):
2929
return templates.TemplateResponse(request, "index.html.jinja", context={"title": "Home"})
3030

@@ -33,7 +33,7 @@ async def home_ui(request: Request):
3333
"/devices",
3434
dependencies=[Security(validate_user_permissions, scopes=["device.read"])],
3535
)
36-
@nav.route("Devices", permissions=["device.read"])
36+
@nav.route("Devices", permissions="device.read")
3737
async def devices_ui(request: Request):
3838
return templates.TemplateResponse(request, "devices.html.jinja", context={"title": "Devices"})
3939

@@ -42,7 +42,7 @@ async def devices_ui(request: Request):
4242
"/software",
4343
dependencies=[Security(validate_user_permissions, scopes=["software.read"])],
4444
)
45-
@nav.route("Software", permissions=["software.read"])
45+
@nav.route("Software", permissions="software.read")
4646
async def software_ui(request: Request):
4747
return templates.TemplateResponse(request, "software.html.jinja", context={"title": "Software"})
4848

@@ -51,7 +51,7 @@ async def software_ui(request: Request):
5151
"/rollouts",
5252
dependencies=[Security(validate_user_permissions, scopes=["rollout.read"])],
5353
)
54-
@nav.route("Rollouts", permissions=["rollout.read"])
54+
@nav.route("Rollouts", permissions="rollout.read")
5555
async def rollouts_ui(request: Request):
5656
return templates.TemplateResponse(request, "rollouts.html.jinja", context={"title": "Rollouts"})
5757

goosebit/updater/controller/v1/routes.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@
2323

2424
@router.get("/{dev_id}")
2525
async def polling(request: Request, dev_id: str, updater: UpdateManager = Depends(get_update_manager)):
26-
links = {}
26+
links: dict[str, dict[str, str]] = {}
2727

2828
sleep = updater.poll_time
2929
device = await updater.get_device()
3030

31+
if device is None:
32+
raise HTTPException(404)
33+
3134
if device.last_state == UpdateStateEnum.UNKNOWN:
3235
# device registration
3336
sleep = config.poll_time_registration
@@ -49,7 +52,7 @@ async def polling(request: Request, dev_id: str, updater: UpdateManager = Depend
4952
# provide update if available. Note: this is also required while in state "running", otherwise swupdate
5053
# won't confirm a successful testing (might be a bug/problem in swupdate)
5154
handling_type, software = await updater.get_update()
52-
if handling_type != HandlingType.SKIP:
55+
if handling_type != HandlingType.SKIP and software is not None:
5356
links["deploymentBase"] = {
5457
"href": str(
5558
request.url_for(
@@ -152,7 +155,8 @@ async def deployment_feedback(
152155

153156
try:
154157
log = data.status.details
155-
await updater.update_log("\n".join(log))
158+
if log is not None:
159+
await updater.update_log("\n".join(log))
156160
except AttributeError:
157161
logging.warning(f"No details to update device update log, device={updater.dev_id}")
158162

goosebit/updater/controller/v1/schema.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,16 @@ class FeedbackStatusResultFinished(StrEnum):
4141

4242
class FeedbackStatusResultSchema(BaseModel):
4343
finished: FeedbackStatusResultFinished
44-
progress: FeedbackStatusProgressSchema = None
44+
progress: FeedbackStatusProgressSchema | None = None
4545

4646

4747
class FeedbackStatusSchema(BaseModel):
4848
execution: FeedbackStatusExecutionState
4949
result: FeedbackStatusResultSchema
50-
code: int = None
51-
details: list[str] = None
50+
code: int | None = None
51+
details: list[str] | None = None
5252

5353

5454
class FeedbackSchema(BaseModel):
55-
time: str = None
55+
time: str | None = None
5656
status: FeedbackStatusSchema

goosebit/updater/manager.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def __init__(self, dev_id: str):
4545
self.dev_id = dev_id
4646

4747
async def get_device(self) -> Device | None:
48-
return
48+
return None
4949

5050
async def update_force_update(self, force_update: bool) -> None:
5151
return
@@ -86,7 +86,8 @@ async def subscribe_log(self, callback: Callable):
8686
subscribers = self.log_subscribers
8787
subscribers.append(callback)
8888
self.log_subscribers = subscribers
89-
await callback(device.last_log)
89+
if device is not None:
90+
await callback(device.last_log)
9091
try:
9192
yield
9293
except asyncio.CancelledError:
@@ -126,7 +127,7 @@ async def publish_log(self, log_data: str | None):
126127
await cb(log_data)
127128

128129
@abstractmethod
129-
async def get_update(self) -> tuple[HandlingType, Software]: ...
130+
async def get_update(self) -> tuple[HandlingType, Software | None]: ...
130131

131132
@abstractmethod
132133
async def update_log(self, log_data: str) -> None: ...
@@ -137,11 +138,16 @@ def __init__(self, dev_id: str):
137138
super().__init__(dev_id)
138139
self.poll_time = config.poll_time_updating
139140

140-
async def _get_software(self) -> Software:
141-
return await Software.latest(await self.get_device())
141+
async def _get_software(self) -> Software | None:
142+
device = await self.get_device()
143+
if device is None:
144+
return None
145+
return await Software.latest(device)
142146

143-
async def get_update(self) -> tuple[HandlingType, Software]:
147+
async def get_update(self) -> tuple[HandlingType, Software | None]:
144148
software = await self._get_software()
149+
if software is None:
150+
return HandlingType.SKIP, None
145151
return HandlingType.FORCED, software
146152

147153
async def update_log(self, log_data: str) -> None:
@@ -276,7 +282,7 @@ async def _get_software(self) -> Software | None:
276282
assert device.update_mode == UpdateModeEnum.PINNED
277283
return None
278284

279-
async def get_update(self) -> tuple[HandlingType, Software]:
285+
async def get_update(self) -> tuple[HandlingType, Software | None]:
280286
device = await self.get_device()
281287
software = await self._get_software()
282288

0 commit comments

Comments
 (0)