Skip to content

Commit 9c7d477

Browse files
committed
feat: add type hints to top-level ubireader module
1 parent 6ed18b0 commit 9c7d477

4 files changed

Lines changed: 55 additions & 33 deletions

File tree

ubireader/debug.py

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

20+
from __future__ import annotations
2021
import sys
2122
import traceback
23+
from typing import Literal, NoReturn, Protocol, overload
2224
from ubireader import settings
2325

24-
def log(obj, message):
26+
class _Obj(Protocol):
27+
__name__: str
28+
29+
def log(obj: _Obj, message: str) -> None:
2530
if settings.logging_on or settings.logging_on_verbose:
2631
print('{} {}'.format(obj.__name__, message))
2732

28-
def verbose_log(obj, message):
33+
def verbose_log(obj: _Obj, message: str) -> None:
2934
if settings.logging_on_verbose:
3035
log(obj, message)
3136

32-
def verbose_display(displayable_obj):
37+
class _Displayable(Protocol):
38+
def display(self, tab: str) -> str: ...
39+
40+
def verbose_display(displayable_obj: _Displayable) -> None:
3341
if settings.logging_on_verbose:
3442
print(displayable_obj.display('\t'))
3543

36-
def error(obj, level, message):
44+
@overload
45+
def error(obj: _Obj, level: Literal['fatal', 'Fatal'], message: str) -> NoReturn: ...
46+
@overload
47+
def error(obj: _Obj, level: str, message: str) -> None: ...
48+
49+
def error(obj: _Obj, level: str, message: str) -> None:
3750
if settings.error_action == 'exit':
3851
print('{} {}: {}'.format(obj.__name__, level, message))
3952
if settings.fatal_traceback:

ubireader/py.typed

Whitespace-only changes.

ubireader/ubi_io.py

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,18 @@
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, log, verbose_log
2123
from ubireader.ubi.block import sort
2224
from ubireader.ubi.defines import UBI_VID_STATIC
2325

26+
if TYPE_CHECKING:
27+
from typing import Self # In TYPE_CHECKING block because it's only available after python 3.11
28+
from collections.abc import Iterator, Mapping
29+
from ubireader.ubi import ubi as Ubi
30+
from ubireader.ubi.block import description as Block
31+
2432
class ubi_file(object):
2533
"""UBI image file object
2634
@@ -50,7 +58,7 @@ class ubi_file(object):
5058
extract blocks, etc.
5159
"""
5260

53-
def __init__(self, path, block_size, start_offset=0, end_offset=None):
61+
def __init__(self, path: str, block_size: int, start_offset: int = 0, end_offset: int | None = None) -> None:
5462
self.__name__ = 'UBI_File'
5563
self.is_valid = False
5664
try:
@@ -89,54 +97,54 @@ def __init__(self, path, block_size, start_offset=0, end_offset=None):
8997
self._last_read_addr = self._fhandle.tell()
9098
self.is_valid = True
9199

92-
def __enter__(self):
100+
def __enter__(self) -> Self:
93101
return self
94102

95-
def __exit__(self, exc_type, exc_value, traceback):
103+
def __exit__(self, exc_type, exc_value, traceback) -> None:
96104
self.close()
97105

98-
def _set_start(self, i):
106+
def _set_start(self, i: int) -> None:
99107
self._start_offset = i
100-
def _get_start(self):
108+
def _get_start(self) -> int:
101109
return self._start_offset
102110
start_offset = property(_get_start, _set_start)
103111

104112

105-
def _get_end(self):
113+
def _get_end(self) -> int:
106114
return self._end_offset
107115
end_offset = property(_get_end)
108116

109117

110-
def _get_block_size(self):
118+
def _get_block_size(self) -> int:
111119
return self._block_size
112120
block_size = property(_get_block_size)
113121

114-
def close(self):
122+
def close(self) -> None:
115123
self._fhandle.close()
116124

117-
def seek(self, offset):
125+
def seek(self, offset: int) -> None:
118126
self._fhandle.seek(offset)
119127

120128

121-
def read(self, size):
129+
def read(self, size: int) -> bytes:
122130
self._last_read_addr = self.tell()
123131
verbose_log(self, 'read loc: %s, size: %s' % (self._last_read_addr, size))
124132
return self._fhandle.read(size)
125133

126134

127-
def tell(self):
135+
def tell(self) -> int:
128136
return self._fhandle.tell()
129137

130138

131-
def last_read_addr(self):
139+
def last_read_addr(self) -> int:
132140
return self._last_read_addr
133141

134142

135-
def reset(self):
143+
def reset(self) -> None:
136144
self._fhandle.seek(self.start_offset)
137145

138146

139-
def reader(self):
147+
def reader(self) -> Iterator[bytes]:
140148
self.reset()
141149
while True:
142150
cur_loc = self._fhandle.tell()
@@ -154,7 +162,7 @@ def reader(self):
154162
yield buf
155163

156164

157-
def read_block(self, block):
165+
def read_block(self, block: Block) -> bytes:
158166
"""Read complete PEB data from file.
159167
160168
Argument:
@@ -164,7 +172,7 @@ def read_block(self, block):
164172
return self._fhandle.read(block.size)
165173

166174

167-
def read_block_data(self, block):
175+
def read_block_data(self, block: Block) -> bytes:
168176
"""Read LEB data from file
169177
170178
Argument:
@@ -180,7 +188,7 @@ def read_block_data(self, block):
180188

181189

182190
class leb_virtual_file():
183-
def __init__(self, ubi, block_list):
191+
def __init__(self, ubi: Ubi, block_list: Mapping[int, Block]) -> None:
184192
self.__name__ = 'leb_virtual_file'
185193
self.is_valid = False
186194
self._ubi = ubi
@@ -196,7 +204,7 @@ def __init__(self, ubi, block_list):
196204
self.is_valid = True
197205

198206

199-
def read(self, size):
207+
def read(self, size: int) -> bytes:
200208
buf = ''
201209
leb = int(self.tell() / self._ubi.leb_size)
202210
offset = self.tell() % self._ubi.leb_size
@@ -227,24 +235,24 @@ def read(self, size):
227235
error(self, 'Fatal', 'read loc: %s, size: %s, LEB: %s, offset: %s, error: %s' % (self._last_read_addr, size, leb, offset, e))
228236

229237

230-
def reset(self):
238+
def reset(self) -> None:
231239
self.seek(0)
232240

233241

234-
def seek(self, offset):
242+
def seek(self, offset: int) -> None:
235243
self._seek = offset
236244

237245

238-
def tell(self):
246+
def tell(self) -> int:
239247
return self._seek
240248

241249

242-
def last_read_addr(self):
250+
def last_read_addr(self) -> int:
243251
"""Start address of last physical file read"""
244252
return self._last_read_addr
245253

246254

247-
def reader(self):
255+
def reader(self) -> Iterator[bytes]:
248256
last_leb = 0
249257
for block in self._blocks:
250258
while 0 != (self._ubi.blocks[block].leb_num - last_leb):

ubireader/utils.py

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

20+
from __future__ import annotations
2021
import re
2122
from ubireader.debug import error, log
2223
from ubireader.ubi.defines import UBI_EC_HDR_MAGIC, FILE_CHUNK_SZ
2324
from ubireader.ubifs.defines import UBIFS_NODE_MAGIC, UBIFS_SB_NODE_SZ, UBIFS_SB_NODE, UBIFS_COMMON_HDR_SZ
2425
from ubireader.ubifs import nodes
2526

26-
def guess_start_offset(path, guess_offset=0):
27+
def guess_start_offset(path: str, guess_offset: int =0) -> int | None:
2728
file_offset = guess_offset
2829

2930
f = open(path, 'rb')
@@ -60,7 +61,7 @@ def guess_start_offset(path, guess_offset=0):
6061
f.close()
6162

6263

63-
def guess_filetype(path, start_offset=0):
64+
def guess_filetype(path: str, start_offset: int = 0) -> bytes | None:
6465
log(guess_filetype, 'Looking for file type at %s' % start_offset)
6566

6667
with open(path, 'rb') as f:
@@ -81,7 +82,7 @@ def guess_filetype(path, start_offset=0):
8182
return ftype
8283

8384

84-
def guess_leb_size(path):
85+
def guess_leb_size(path: str) -> int | None:
8586
"""Get LEB size from superblock
8687
8788
Arguments:
@@ -125,7 +126,7 @@ def guess_leb_size(path):
125126
return block_size
126127

127128

128-
def guess_peb_size(path):
129+
def guess_peb_size(path: str) -> int | None:
129130
"""Determine the most likely block size
130131
131132
Arguments:
@@ -138,7 +139,7 @@ def guess_peb_size(path):
138139
common length between them.
139140
"""
140141
file_offset = 0
141-
offsets = []
142+
offsets: list[int] = []
142143
f = open(path, 'rb')
143144
f.seek(0,2)
144145
file_size = f.tell()+1
@@ -160,7 +161,7 @@ def guess_peb_size(path):
160161
file_offset += FILE_CHUNK_SZ
161162
f.close()
162163

163-
occurrences = {}
164+
occurrences: dict[int, int] = {}
164165
for i in range(0, len(offsets)):
165166
try:
166167
diff = offsets[i] - offsets[i-1]

0 commit comments

Comments
 (0)