Skip to content

Commit 9e2b49f

Browse files
committed
Typed dicts
1 parent da1f682 commit 9e2b49f

File tree

2 files changed

+32
-13
lines changed

2 files changed

+32
-13
lines changed

reolinkfw/__init__.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import re
88
import zlib
99
from ast import literal_eval
10-
from collections.abc import Iterator, Mapping
10+
from collections.abc import Iterator
1111
from contextlib import redirect_stdout
1212
from ctypes import sizeof
1313
from functools import partial
@@ -34,7 +34,7 @@
3434

3535
from reolinkfw.fdt import RE_FDT_HEADER, FDTHeader
3636
from reolinkfw.tmpfile import TempFile
37-
from reolinkfw.typedefs import Buffer, Files, StrPath, StrPathURL
37+
from reolinkfw.typedefs import Buffer, DVRInfo, InfoFiles, StrPath, StrPathURL
3838
from reolinkfw.ubifs import UBIFS
3939
from reolinkfw.uboot import Compression, LegacyImageHeader, get_arch_name
4040
from reolinkfw.util import (
@@ -440,18 +440,18 @@ def firmwares_from_zip(zip: Union[StrPath, IO[bytes]]) -> list[tuple[str, Reolin
440440
return fws
441441

442442

443-
def get_info_from_files(files: Mapping[Files, Optional[bytes]]) -> dict[str, Optional[str]]:
443+
def get_info_from_files(files: InfoFiles) -> DVRInfo:
444444
xml: dict[str, str] = dict(fromstring(files["dvr.xml"]).items())
445445
info = {k: xml.get(k) for k in INFO_KEYS}
446446
info["version_file"] = files["version_file"].decode().strip()
447447
if not info.get("firmware_version_prefix"):
448448
thefile = files["dvr"] if files["dvr"] is not None else files["router"]
449449
match = re.search(b"echo (v[23]\.0\.0)", thefile) if thefile is not None else None
450450
info["firmware_version_prefix"] = match.group(1).decode() if match else None
451-
return info
451+
return info # type: ignore
452452

453453

454-
def get_files_from_squashfs(fd: BinaryIO, offset: int = 0, closefd: bool = True) -> dict[Files, Optional[bytes]]:
454+
def get_files_from_squashfs(fd: BinaryIO, offset: int = 0, closefd: bool = True) -> InfoFiles:
455455
# Firmwares using squashfs have either one or two file system
456456
# sections. When there is only one, the app directory is located at
457457
# /mnt/app. Otherwise it's the same as with cramfs and ubifs.
@@ -461,10 +461,10 @@ def get_files_from_squashfs(fd: BinaryIO, offset: int = 0, closefd: bool = True)
461461
path2 = posixpath.join("/mnt/app", name)
462462
if (file := (image.select(name) or image.select(path2))) is not None:
463463
files[name] = file.read_bytes()
464-
return files
464+
return files # type: ignore
465465

466466

467-
def get_files_from_ubifs(binbytes: Buffer) -> dict[Files, Optional[bytes]]:
467+
def get_files_from_ubifs(binbytes: Buffer) -> InfoFiles:
468468
# For now all firmwares using ubifs have two file system sections.
469469
# The interesting files are in the root directory of the "app" one.
470470
# Using select() with a relative path is enough.
@@ -474,10 +474,10 @@ def get_files_from_ubifs(binbytes: Buffer) -> dict[Files, Optional[bytes]]:
474474
for name in files:
475475
if (file := image.select(name)) is not None:
476476
files[name] = file.read_bytes()
477-
return files
477+
return files # type: ignore
478478

479479

480-
def get_files_from_ubi(fd: BinaryIO, size: int, offset: int = 0) -> dict[Files, Optional[bytes]]:
480+
def get_files_from_ubi(fd: BinaryIO, size: int, offset: int = 0) -> InfoFiles:
481481
fsbytes = get_fs_from_ubi(fd, size, offset)
482482
fs = FileType.from_magic(fsbytes[:4])
483483
if fs == FileType.UBIFS:
@@ -487,7 +487,7 @@ def get_files_from_ubi(fd: BinaryIO, size: int, offset: int = 0) -> dict[Files,
487487
raise Exception("Unknown file system in UBI")
488488

489489

490-
def get_files_from_cramfs(fd: BinaryIO, offset: int = 0, closefd: bool = True) -> dict[Files, Optional[bytes]]:
490+
def get_files_from_cramfs(fd: BinaryIO, offset: int = 0, closefd: bool = True) -> InfoFiles:
491491
# For now all firmwares using cramfs have two file system sections.
492492
# The interesting files are in the root directory of the "app" one.
493493
# Using select() with a relative path is enough.
@@ -496,7 +496,7 @@ def get_files_from_cramfs(fd: BinaryIO, offset: int = 0, closefd: bool = True) -
496496
for name in files:
497497
if (file := cramfs.select(name)) is not None:
498498
files[name] = file.read_bytes()
499-
return files
499+
return files # type: ignore
500500

501501

502502
def is_url(string: StrOrURL) -> bool:

reolinkfw/typedefs.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import collections.abc
22
from os import PathLike
3-
from typing import AnyStr, Literal, Union
3+
from typing import AnyStr, Optional, TypedDict, Union
44

55
from aiohttp.typedefs import StrOrURL
66

@@ -9,9 +9,28 @@
99
else:
1010
Buffer = Union[bytes, bytearray, memoryview]
1111

12-
Files = Literal["version_file", "version.json", "dvr.xml", "dvr", "router"]
1312
GenericPath = Union[AnyStr, PathLike[AnyStr]]
1413
StrPath = Union[str, PathLike[str]]
1514
StrPathURL = Union[StrPath, StrOrURL]
1615
StrOrBytesPath = Union[StrPath, bytes, PathLike[bytes]]
1716
FileDescriptorOrPath = Union[int, StrOrBytesPath]
17+
18+
InfoFiles = TypedDict("InfoFiles", {
19+
"version_file": bytes,
20+
"dvr.xml": bytes,
21+
"version.json": Optional[bytes],
22+
"dvr": Optional[bytes],
23+
"router": Optional[bytes],
24+
})
25+
26+
27+
class DVRInfo(TypedDict):
28+
"""Info from the dvr.xml and version_file files."""
29+
board_name: str
30+
board_type: str
31+
build_date: str
32+
detail_machine_type: str
33+
display_type_info: str
34+
firmware_version_prefix: str
35+
type: str
36+
version_file: str

0 commit comments

Comments
 (0)