Skip to content

Commit 5424670

Browse files
committed
feat: add type hints to ubireader.ubi
1 parent fe33586 commit 5424670

8 files changed

Lines changed: 196 additions & 83 deletions

File tree

ubireader/ubi/__init__.py

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,19 @@
1717
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
#############################################################
1919

20+
from __future__ import annotations
21+
from typing import TYPE_CHECKING
2022
from ubireader.debug import error
2123
from ubireader.ubi.block import sort, extract_blocks
2224
from ubireader.ubi import display
2325
from ubireader.ubi.image import description as image
2426
from ubireader.ubi.block import layout, rm_old_blocks
2527

28+
if TYPE_CHECKING:
29+
from ubireader.ubi_io import ubi_file as UbiFile
30+
from ubireader.ubi.block import description as Block
31+
from ubireader.ubi.image import description as Image
32+
2633
class ubi_base(object):
2734
"""UBI Base object
2835
@@ -39,7 +46,7 @@ class ubi_base(object):
3946
Dict:blocks -- Dict keyed by PEB number of all blocks.
4047
"""
4148

42-
def __init__(self, ubi_file):
49+
def __init__(self, ubi_file: UbiFile) -> None:
4350
self.__name__ = 'UBI'
4451
self._file = ubi_file
4552
self._first_peb_num = 0
@@ -54,7 +61,7 @@ def __init__(self, ubi_file):
5461
self._leb_size = self.file.block_size - arbitrary_block.ec_hdr.data_offset
5562

5663

57-
def _get_file(self):
64+
def _get_file(self) -> UbiFile:
5865
"""UBI File object
5966
6067
Returns:
@@ -64,7 +71,7 @@ def _get_file(self):
6471
file = property(_get_file)
6572

6673

67-
def _get_block_count(self):
74+
def _get_block_count(self) -> int:
6875
"""Total amount of UBI blocks in file.
6976
7077
Returns:
@@ -74,9 +81,9 @@ def _get_block_count(self):
7481
block_count = property(_get_block_count)
7582

7683

77-
def _set_first_peb_num(self, i):
84+
def _set_first_peb_num(self, i: int) -> None:
7885
self._first_peb_num = i
79-
def _get_first_peb_num(self):
86+
def _get_first_peb_num(self) -> int:
8087
"""First Physical Erase Block with UBI data
8188
8289
Returns:
@@ -86,7 +93,7 @@ def _get_first_peb_num(self):
8693
first_peb_num = property(_get_first_peb_num, _set_first_peb_num)
8794

8895

89-
def _get_leb_size(self):
96+
def _get_leb_size(self) -> int:
9097
"""LEB size of UBI blocks in file.
9198
9299
Returns:
@@ -96,7 +103,7 @@ def _get_leb_size(self):
96103
leb_size = property(_get_leb_size)
97104

98105

99-
def _get_peb_size(self):
106+
def _get_peb_size(self) -> int:
100107
"""PEB size of UBI blocks in file.
101108
102109
Returns:
@@ -106,7 +113,7 @@ def _get_peb_size(self):
106113
peb_size = property(_get_peb_size)
107114

108115

109-
def _get_min_io_size(self):
116+
def _get_min_io_size(self) -> int:
110117
"""Min I/O Size
111118
112119
Returns:
@@ -116,7 +123,7 @@ def _get_min_io_size(self):
116123
min_io_size = property(_get_min_io_size)
117124

118125

119-
def _get_blocks(self):
126+
def _get_blocks(self) -> dict[int, Block]:
120127
"""Main Dict of UBI Blocks
121128
122129
Passed around for lists of indexes to be made or to be returned
@@ -142,7 +149,7 @@ class ubi(ubi_base):
142149
List:unknown_blocks_list -- List of blocks with unknown types. *
143150
"""
144151

145-
def __init__(self, ubi_file):
152+
def __init__(self, ubi_file: UbiFile) -> None:
146153
super(ubi, self).__init__(ubi_file)
147154

148155
layout_list, data_list, int_vol_list, unknown_list = sort.by_type(self.blocks)
@@ -161,12 +168,12 @@ def __init__(self, ubi_file):
161168

162169
layout_infos = layout.associate_blocks(self.blocks, layout_pairs)
163170

164-
self._images = []
171+
self._images: list[Image] = []
165172
for i in range(0, len(layout_infos)):
166173
self._images.append(image(self.blocks, layout_infos[i]))
167174

168175

169-
def _get_images(self):
176+
def _get_images(self) -> list[Image]:
170177
"""Get UBI images.
171178
172179
Returns:
@@ -176,7 +183,7 @@ def _get_images(self):
176183
images = property(_get_images)
177184

178185

179-
def _get_data_blocks_list(self):
186+
def _get_data_blocks_list(self) -> list[int]:
180187
"""Get all UBI blocks found in file that are data blocks.
181188
182189
Returns:
@@ -186,7 +193,7 @@ def _get_data_blocks_list(self):
186193
data_blocks_list = property(_get_data_blocks_list)
187194

188195

189-
def _get_layout_blocks_list(self):
196+
def _get_layout_blocks_list(self) -> list[int]:
190197
"""Get all UBI blocks found in file that are layout volume blocks.
191198
192199
Returns:
@@ -196,7 +203,7 @@ def _get_layout_blocks_list(self):
196203
layout_blocks_list = property(_get_layout_blocks_list)
197204

198205

199-
def _get_int_vol_blocks_list(self):
206+
def _get_int_vol_blocks_list(self) -> list[int]:
200207
"""Get all UBI blocks found in file that are internal volume blocks.
201208
202209
Returns:
@@ -208,7 +215,7 @@ def _get_int_vol_blocks_list(self):
208215
int_vol_blocks_list = property(_get_int_vol_blocks_list)
209216

210217

211-
def _get_unknown_blocks_list(self):
218+
def _get_unknown_blocks_list(self) -> list[int]:
212219
"""Get all UBI blocks found in file of unknown type..
213220
214221
Returns:
@@ -217,7 +224,7 @@ def _get_unknown_blocks_list(self):
217224
return self._unknown_blocks_list
218225
unknown_blocks_list = property(_get_unknown_blocks_list)
219226

220-
def display(self, tab=''):
227+
def display(self, tab: str = '') -> str:
221228
"""Print information about this object.
222229
223230
Argument:

ubireader/ubi/block/__init__.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,19 @@
1717
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
#############################################################
1919

20+
from __future__ import annotations
21+
from typing import TYPE_CHECKING
2022
from zlib import crc32
2123
from ubireader import settings
2224
from ubireader.debug import error, log, verbose_display, verbose_log
2325
from ubireader.ubi import display
2426
from ubireader.ubi.defines import UBI_EC_HDR_SZ, UBI_VID_HDR_SZ, UBI_INTERNAL_VOL_START, UBI_EC_HDR_MAGIC, UBI_CRC32_INIT
2527
from ubireader.ubi.headers import ec_hdr, vid_hdr, vtbl_recs
2628

29+
if TYPE_CHECKING:
30+
from collections.abc import Iterable, Mapping
31+
from ubireader.ubi import ubi_base as UbiBase
32+
from ubireader.ubi.headers import _vtbl_rec as VtblRec
2733

2834
class description(object):
2935
"""UBI Block description Object
@@ -48,16 +54,18 @@ class description(object):
4854
Will print out all information when invoked as a string.
4955
"""
5056

51-
def __init__(self, block_buf):
57+
data_crc: int
58+
59+
def __init__(self, block_buf: bytes) -> None:
5260

5361
self.file_offset = -1
5462
self.peb_num = -1
5563
self.leb_num = -1
5664
self.size = -1
5765

58-
self.vid_hdr = None
66+
self.vid_hdr: vid_hdr | None = None
5967
self.is_internal_vol = False
60-
self.vtbl_recs = []
68+
self.vtbl_recs: list[VtblRec] = []
6169

6270
# TODO better understanding of block types/errors
6371
self.ec_hdr = ec_hdr(block_buf[0:UBI_EC_HDR_SZ])
@@ -77,16 +85,16 @@ def __init__(self, block_buf):
7785
self.is_valid = not self.ec_hdr.errors and not self.vid_hdr.errors or settings.ignore_block_header_errors
7886

7987

80-
def __repr__(self):
88+
def __repr__(self) -> str:
8189
return 'Block: PEB# %s: LEB# %s' % (self.peb_num, self.leb_num)
8290

8391

84-
def display(self, tab=''):
92+
def display(self, tab: str ='') -> str:
8593
return display.block(self, tab)
8694

8795

8896

89-
def get_blocks_in_list(blocks, idx_list):
97+
def get_blocks_in_list(blocks: Mapping[int, description], idx_list: Iterable[int]) -> dict[int, description]:
9098
"""Retrieve block objects in list of indexes
9199
92100
Arguments:
@@ -103,7 +111,7 @@ def get_blocks_in_list(blocks, idx_list):
103111

104112

105113

106-
def extract_blocks(ubi):
114+
def extract_blocks(ubi: UbiBase) -> dict[int, description]:
107115
"""Get a list of UBI block objects from file
108116
109117
Arguments:.
@@ -113,11 +121,11 @@ def extract_blocks(ubi):
113121
Dict -- Of block objects keyed by PEB number.
114122
"""
115123

116-
blocks = {}
124+
blocks: dict[int, description] = {}
117125
ubi.file.seek(ubi.file.start_offset)
118126
peb_count = 0
119127
cur_offset = 0
120-
bad_blocks = []
128+
bad_blocks: list[int] = []
121129

122130
# range instead of xrange, as xrange breaks > 4GB end_offset.
123131
for i in range(ubi.file.start_offset, ubi.file.end_offset, ubi.file.block_size):
@@ -157,8 +165,8 @@ def extract_blocks(ubi):
157165
return blocks
158166

159167

160-
def rm_old_blocks(blocks, block_list):
161-
del_blocks = []
168+
def rm_old_blocks(blocks: Mapping[int, description], block_list: Iterable[int]) -> list[int]:
169+
del_blocks: list[int] = []
162170

163171
for i in block_list:
164172
if i in del_blocks:

ubireader/ubi/block/layout.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,20 @@
1717
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
#############################################################
1919

20+
from __future__ import annotations
21+
from typing import TYPE_CHECKING, Literal, Protocol, cast, overload
2022
from ubireader.debug import log
2123
from ubireader.ubi.block import sort
2224

23-
def group_pairs(blocks, layout_blocks_list):
25+
if TYPE_CHECKING:
26+
from collections.abc import Iterable, Mapping
27+
from ubireader.ubi.block import description as Block
28+
29+
class _LayoutPair(Protocol):
30+
def __getitem__(self, idx: Literal[0, 1]) -> int: ...
31+
def __contains__(self, item: int) -> bool: ...
32+
33+
def group_pairs(blocks: Mapping[int, Block], layout_blocks_list: Iterable[int]) -> list[_LayoutPair]:
2434
"""Sort a list of layout blocks into pairs
2535
2636
Arguments:
@@ -31,7 +41,7 @@ def group_pairs(blocks, layout_blocks_list):
3141
List -- Layout block pair indexes grouped in a list
3242
"""
3343

34-
image_dict={}
44+
image_dict: dict[int, _LayoutPair] = {}
3545
for block_id in layout_blocks_list:
3646
image_seq=blocks[block_id].ec_hdr.image_seq
3747
if image_seq not in image_dict:
@@ -43,8 +53,13 @@ def group_pairs(blocks, layout_blocks_list):
4353

4454
return list(image_dict.values())
4555

56+
class _LayoutInfo(_LayoutPair):
57+
@overload
58+
def __getitem__(self, idx: Literal[0, 1]) -> int: ...
59+
@overload
60+
def __getitem__(self, idx: Literal[2]) -> list[int]: ...
4661

47-
def associate_blocks(blocks, layout_pairs):
62+
def associate_blocks(blocks: Mapping[int, Block], layout_pairs: list[_LayoutPair]) -> list[_LayoutInfo]:
4863
"""Group block indexes with appropriate layout pairs
4964
5065
Arguments:
@@ -55,9 +70,9 @@ def associate_blocks(blocks, layout_pairs):
5570
List -- Layout block pairs grouped with associated block ranges.
5671
"""
5772

58-
seq_blocks = []
73+
seq_blocks: list[int] = []
5974
for layout_pair in layout_pairs:
60-
seq_blocks = sort.by_image_seq(blocks, blocks[layout_pair[0]].ec_hdr.image_seq)
75+
seq_blocks = sort.by_image_seq(blocks, blocks[cast(int, layout_pair[0])].ec_hdr.image_seq)
6176
seq_blocks = [b for b in seq_blocks if b not in layout_pair]
6277
layout_pair.append(seq_blocks)
6378

ubireader/ubi/block/sort.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,15 @@
1717
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
#############################################################
1919

20+
from __future__ import annotations
21+
from typing import TYPE_CHECKING, Literal
2022
from ubireader import settings
2123

22-
def by_image_seq(blocks, image_seq):
24+
if TYPE_CHECKING:
25+
from collections.abc import Mapping
26+
from ubireader.ubi.block import description as Block
27+
28+
def by_image_seq(blocks: Mapping[int, Block], image_seq: int) -> list[int]:
2329
"""Filter blocks to return only those associated with the provided image_seq number.
2430
If uboot_fix is set, associate blocks with an image_seq of 0 also.
2531
@@ -36,7 +42,7 @@ def by_image_seq(blocks, image_seq):
3642
else:
3743
return list(filter(lambda block: blocks[block].ec_hdr.image_seq == image_seq, blocks))
3844

39-
def by_leb(blocks):
45+
def by_leb(blocks: Mapping[int, Block]) -> list[Literal['x'] | int]:
4046
"""Sort blocks by Logical Erase Block number.
4147
4248
Arguments:
@@ -46,7 +52,7 @@ def by_leb(blocks):
4652
List -- Indexes of blocks sorted by LEB.
4753
"""
4854
slist_len = len(blocks)
49-
slist = ['x'] * slist_len
55+
slist: list[Literal['x'] | int] = ['x'] * slist_len
5056

5157
for block in blocks:
5258
if blocks[block].leb_num >= slist_len:
@@ -59,7 +65,7 @@ def by_leb(blocks):
5965
return slist
6066

6167

62-
def by_vol_id(blocks, slist=None):
68+
def by_vol_id(blocks: Mapping[int, Block], slist: list[int] | None = None) -> dict[int, list[int]]:
6369
"""Sort blocks by volume id
6470
6571
Arguments:
@@ -70,7 +76,7 @@ def by_vol_id(blocks, slist=None):
7076
Dict -- blocks grouped in lists with dict key as volume id.
7177
"""
7278

73-
vol_blocks = {}
79+
vol_blocks: dict[int, list[int]] = {}
7480

7581
# sort block by volume
7682
# not reliable with multiple partitions (fifo)
@@ -88,7 +94,7 @@ def by_vol_id(blocks, slist=None):
8894

8995
return vol_blocks
9096

91-
def by_type(blocks, slist=None):
97+
def by_type(blocks: Mapping[int, Block], slist: list[int] | None = None) -> tuple[list[int], list[int], list[int], list[int]]:
9298
"""Sort blocks into layout, internal volume, data or unknown
9399
94100
Arguments:
@@ -106,10 +112,10 @@ def by_type(blocks, slist=None):
106112
of crc in ed_hdr or vid_hdr.
107113
"""
108114

109-
layout = []
110-
data = []
111-
int_vol = []
112-
unknown = []
115+
layout: list[int] = []
116+
data: list[int] = []
117+
int_vol: list[int] = []
118+
unknown: list[int] = []
113119

114120
for i in blocks:
115121
if slist and i not in slist:

0 commit comments

Comments
 (0)