Skip to content

Commit 7f7fc8e

Browse files
committed
Add types to internal modules
1 parent b41ff85 commit 7f7fc8e

File tree

3 files changed

+48
-43
lines changed

3 files changed

+48
-43
lines changed

maxminddb/decoder.py

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,23 @@
77
"""
88
import struct
99

10+
from mmap import mmap
11+
from typing import cast, Dict, List, Tuple, Union
12+
1013
from maxminddb.errors import InvalidDatabaseError
14+
from maxminddb.file import FileBuffer
15+
from maxminddb.types import Record
1116

1217

1318
class Decoder: # pylint: disable=too-few-public-methods
1419
"""Decoder for the data section of the MaxMind DB"""
1520

16-
def __init__(self, database_buffer, pointer_base=0, pointer_test=False):
21+
def __init__(
22+
self,
23+
database_buffer: Union[FileBuffer, mmap, bytes],
24+
pointer_base: int = 0,
25+
pointer_test: bool = False,
26+
) -> None:
1727
"""Created a Decoder for a MaxMind DB
1828
1929
Arguments:
@@ -25,35 +35,37 @@ def __init__(self, database_buffer, pointer_base=0, pointer_test=False):
2535
self._buffer = database_buffer
2636
self._pointer_base = pointer_base
2737

28-
def _decode_array(self, size, offset):
38+
def _decode_array(self, size: int, offset: int) -> Tuple[List[Record], int]:
2939
array = []
3040
for _ in range(size):
3141
(value, offset) = self.decode(offset)
3242
array.append(value)
3343
return array, offset
3444

35-
def _decode_boolean(self, size, offset): # pylint: disable=no-self-use
45+
def _decode_boolean( # pylint: disable=no-self-use
46+
self, size: int, offset: int
47+
) -> Tuple[bool, int]:
3648
return size != 0, offset
3749

38-
def _decode_bytes(self, size, offset):
50+
def _decode_bytes(self, size: int, offset: int) -> Tuple[bytes, int]:
3951
new_offset = offset + size
4052
return self._buffer[offset:new_offset], new_offset
4153

42-
def _decode_double(self, size, offset):
54+
def _decode_double(self, size: int, offset: int) -> Tuple[float, int]:
4355
self._verify_size(size, 8)
4456
new_offset = offset + size
4557
packed_bytes = self._buffer[offset:new_offset]
4658
(value,) = struct.unpack(b"!d", packed_bytes)
4759
return value, new_offset
4860

49-
def _decode_float(self, size, offset):
61+
def _decode_float(self, size: int, offset: int) -> Tuple[float, int]:
5062
self._verify_size(size, 4)
5163
new_offset = offset + size
5264
packed_bytes = self._buffer[offset:new_offset]
5365
(value,) = struct.unpack(b"!f", packed_bytes)
5466
return value, new_offset
5567

56-
def _decode_int32(self, size, offset):
68+
def _decode_int32(self, size: int, offset: int) -> Tuple[int, int]:
5769
if size == 0:
5870
return 0, offset
5971
new_offset = offset + size
@@ -64,15 +76,15 @@ def _decode_int32(self, size, offset):
6476
(value,) = struct.unpack(b"!i", packed_bytes)
6577
return value, new_offset
6678

67-
def _decode_map(self, size, offset):
68-
container = {}
79+
def _decode_map(self, size: int, offset: int) -> Tuple[Dict[str, Record], int]:
80+
container: Dict[str, Record] = {}
6981
for _ in range(size):
7082
(key, offset) = self.decode(offset)
7183
(value, offset) = self.decode(offset)
72-
container[key] = value
84+
container[cast(str, key)] = value
7385
return container, offset
7486

75-
def _decode_pointer(self, size, offset):
87+
def _decode_pointer(self, size: int, offset: int) -> Tuple[Record, int]:
7688
pointer_size = (size >> 3) + 1
7789

7890
buf = self._buffer[offset : offset + pointer_size]
@@ -95,12 +107,12 @@ def _decode_pointer(self, size, offset):
95107
(value, _) = self.decode(pointer)
96108
return value, new_offset
97109

98-
def _decode_uint(self, size, offset):
110+
def _decode_uint(self, size: int, offset: int) -> Tuple[int, int]:
99111
new_offset = offset + size
100112
uint_bytes = self._buffer[offset:new_offset]
101113
return int.from_bytes(uint_bytes, "big"), new_offset
102114

103-
def _decode_utf8_string(self, size, offset):
115+
def _decode_utf8_string(self, size: int, offset: int) -> Tuple[str, int]:
104116
new_offset = offset + size
105117
return self._buffer[offset:new_offset].decode("utf-8"), new_offset
106118

@@ -120,7 +132,7 @@ def _decode_utf8_string(self, size, offset):
120132
15: _decode_float,
121133
}
122134

123-
def decode(self, offset):
135+
def decode(self, offset: int) -> Tuple[Record, int]:
124136
"""Decode a section of the data section starting at offset
125137
126138
Arguments:
@@ -143,7 +155,7 @@ def decode(self, offset):
143155
(size, new_offset) = self._size_from_ctrl_byte(ctrl_byte, new_offset, type_num)
144156
return decoder(self, size, new_offset)
145157

146-
def _read_extended(self, offset):
158+
def _read_extended(self, offset: int) -> Tuple[int, int]:
147159
next_byte = self._buffer[offset]
148160
type_num = next_byte + 7
149161
if type_num < 7:
@@ -155,14 +167,16 @@ def _read_extended(self, offset):
155167
return type_num, offset + 1
156168

157169
@staticmethod
158-
def _verify_size(expected, actual):
170+
def _verify_size(expected: int, actual: int) -> None:
159171
if expected != actual:
160172
raise InvalidDatabaseError(
161173
"The MaxMind DB file's data section contains bad data "
162174
"(unknown data type or corrupt data)"
163175
)
164176

165-
def _size_from_ctrl_byte(self, ctrl_byte, offset, type_num):
177+
def _size_from_ctrl_byte(
178+
self, ctrl_byte: int, offset: int, type_num: int
179+
) -> Tuple[int, int]:
166180
size = ctrl_byte & 0x1F
167181
if type_num == 1 or size < 29:
168182
return size, offset

maxminddb/file.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""For internal use only. It provides a slice-like file reader."""
22

33
import os
4+
from typing import Union
45

56
try:
67
# pylint: disable=no-name-in-module
@@ -12,44 +13,44 @@
1213
class FileBuffer:
1314
"""A slice-able file reader"""
1415

15-
def __init__(self, database):
16+
def __init__(self, database: str) -> None:
1617
self._handle = open(database, "rb")
1718
self._size = os.fstat(self._handle.fileno()).st_size
1819
if not hasattr(os, "pread"):
1920
self._lock = Lock()
2021

21-
def __getitem__(self, key):
22+
def __getitem__(self, key: Union[slice, int]):
2223
if isinstance(key, slice):
2324
return self._read(key.stop - key.start, key.start)
2425
if isinstance(key, int):
2526
return self._read(1, key)[0]
2627
raise TypeError("Invalid argument type.")
2728

28-
def rfind(self, needle, start):
29+
def rfind(self, needle: bytes, start: int) -> int:
2930
"""Reverse find needle from start"""
3031
pos = self._read(self._size - start - 1, start).rfind(needle)
3132
if pos == -1:
3233
return pos
3334
return start + pos
3435

35-
def size(self):
36+
def size(self) -> int:
3637
"""Size of file"""
3738
return self._size
3839

39-
def close(self):
40+
def close(self) -> None:
4041
"""Close file"""
4142
self._handle.close()
4243

4344
if hasattr(os, "pread"):
4445

45-
def _read(self, buffersize, offset):
46+
def _read(self, buffersize: int, offset: int) -> bytes:
4647
"""read that uses pread"""
4748
# pylint: disable=no-member
4849
return os.pread(self._handle.fileno(), buffersize, offset)
4950

5051
else:
5152

52-
def _read(self, buffersize, offset):
53+
def _read(self, buffersize: int, offset: int) -> bytes:
5354
"""read with a lock
5455
5556
This lock is necessary as after a fork, the different processes

maxminddb/reader.py

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import struct
1818
from ipaddress import IPv4Address, IPv6Address
1919
from os import PathLike
20-
from typing import Any, AnyStr, Dict, List, IO, Optional, Tuple, Union
20+
from typing import Any, AnyStr, IO, Optional, Tuple, Union
2121

2222
from maxminddb.const import MODE_AUTO, MODE_MMAP, MODE_FILE, MODE_MEMORY, MODE_FD
2323
from maxminddb.decoder import Decoder
@@ -61,7 +61,7 @@ def __init__(
6161
self._buffer_size = self._buffer.size()
6262
filename = database
6363
elif mode in (MODE_AUTO, MODE_FILE):
64-
self._buffer = FileBuffer(database)
64+
self._buffer = FileBuffer(database) # type: ignore
6565
self._buffer_size = self._buffer.size()
6666
filename = database
6767
elif mode == MODE_MEMORY:
@@ -95,6 +95,12 @@ def __init__(
9595
metadata_start += len(self._METADATA_START_MARKER)
9696
metadata_decoder = Decoder(self._buffer, metadata_start)
9797
(metadata, _) = metadata_decoder.decode(metadata_start)
98+
99+
if not isinstance(metadata, dict):
100+
raise InvalidDatabaseError(
101+
"Error reading metadata in database file ({0}).".format(filename)
102+
)
103+
98104
self._metadata = Metadata(**metadata) # pylint: disable=bad-option-value
99105

100106
self._decoder = Decoder(
@@ -208,23 +214,7 @@ def _read_node(self, node_number: int, index: int) -> int:
208214
raise InvalidDatabaseError("Unknown record size: {0}".format(record_size))
209215
return struct.unpack(b"!I", node_bytes)[0]
210216

211-
def _resolve_data_pointer(
212-
self, pointer: int
213-
) -> Union[
214-
str,
215-
Dict[str, str],
216-
Dict[
217-
str,
218-
Union[
219-
List[int],
220-
bytes,
221-
float,
222-
int,
223-
Dict[str, Dict[str, Union[List[int], str]]],
224-
str,
225-
],
226-
],
227-
]:
217+
def _resolve_data_pointer(self, pointer: int) -> Record:
228218
resolved = pointer - self._metadata.node_count + self._metadata.search_tree_size
229219

230220
if resolved >= self._buffer_size:

0 commit comments

Comments
 (0)