Skip to content

Commit a0f62d0

Browse files
authored
Merge pull request #234 from seemanne/ese-add-buffer-support
Add arbitrary io buffer support to reader
2 parents 971c79c + 12dbdb6 commit a0f62d0

File tree

2 files changed

+51
-29
lines changed

2 files changed

+51
-29
lines changed

maxminddb/reader.py

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -64,35 +64,7 @@ def __init__(
6464
a path. This mode implies MODE_MEMORY.
6565
6666
"""
67-
filename: Any
68-
if (mode == MODE_AUTO and mmap) or mode == MODE_MMAP:
69-
with open(database, "rb") as db_file: # type: ignore[arg-type]
70-
self._buffer = mmap.mmap(db_file.fileno(), 0, access=mmap.ACCESS_READ)
71-
self._buffer_size = self._buffer.size()
72-
filename = database
73-
elif mode in (MODE_AUTO, MODE_FILE):
74-
self._buffer = FileBuffer(database) # type: ignore[arg-type]
75-
self._buffer_size = self._buffer.size()
76-
filename = database
77-
elif mode == MODE_MEMORY:
78-
with open(database, "rb") as db_file: # type: ignore[arg-type]
79-
buf = db_file.read()
80-
self._buffer = buf
81-
self._buffer_size = len(buf)
82-
filename = database
83-
elif mode == MODE_FD:
84-
self._buffer = database.read() # type: ignore[union-attr]
85-
self._buffer_size = len(self._buffer) # type: ignore[arg-type]
86-
filename = database.name # type: ignore[union-attr]
87-
else:
88-
msg = (
89-
f"Unsupported open mode ({mode}). Only MODE_AUTO, MODE_FILE, "
90-
"MODE_MEMORY and MODE_FD are supported by the pure Python "
91-
"Reader"
92-
)
93-
raise ValueError(
94-
msg,
95-
)
67+
filename = self._load_buffer(database, mode)
9668

9769
metadata_start = self._buffer.rfind(
9870
self._METADATA_START_MARKER,
@@ -276,6 +248,45 @@ def _resolve_data_pointer(self, pointer: int) -> Record:
276248
(data, _) = self._decoder.decode(resolved)
277249
return data
278250

251+
def _load_buffer(
252+
self, database: AnyStr | int | PathLike | IO, mode: int = MODE_AUTO
253+
) -> str:
254+
filename: Any
255+
if (mode == MODE_AUTO and mmap) or mode == MODE_MMAP:
256+
with open(database, "rb") as db_file: # type: ignore[arg-type]
257+
self._buffer = mmap.mmap(db_file.fileno(), 0, access=mmap.ACCESS_READ)
258+
self._buffer_size = self._buffer.size()
259+
filename = database
260+
elif mode in (MODE_AUTO, MODE_FILE):
261+
self._buffer = FileBuffer(database) # type: ignore[arg-type]
262+
self._buffer_size = self._buffer.size()
263+
filename = database
264+
elif mode == MODE_MEMORY:
265+
with open(database, "rb") as db_file: # type: ignore[arg-type]
266+
buf = db_file.read()
267+
self._buffer = buf
268+
self._buffer_size = len(buf)
269+
filename = database
270+
elif mode == MODE_FD:
271+
self._buffer = database.read() # type: ignore[union-attr]
272+
self._buffer_size = len(self._buffer) # type: ignore[arg-type]
273+
# io buffers are not guaranteed to have a name attribute
274+
if hasattr(database, "name"):
275+
filename = database.name # type: ignore[union-attr]
276+
else:
277+
filename = f"<{type(database)}>"
278+
else:
279+
msg = (
280+
f"Unsupported open mode ({mode}). Only MODE_AUTO, MODE_FILE, "
281+
"MODE_MEMORY and MODE_FD are supported by the pure Python "
282+
"Reader"
283+
)
284+
raise ValueError(
285+
msg,
286+
)
287+
288+
return filename
289+
279290
def close(self) -> None:
280291
"""Close the MaxMind DB file and returns the resources to the system."""
281292
with contextlib.suppress(AttributeError):

tests/reader_test.py

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

3+
import io
34
import ipaddress
45
import multiprocessing
56
import os
@@ -524,6 +525,16 @@ def test_closed_metadata(self) -> None:
524525
else:
525526
self.assertIsNotNone(metadata, "pure Python implementation returns value")
526527

528+
def test_reading_from_buffer(self) -> None:
529+
filename = "tests/data/test-data/MaxMind-DB-test-ipv4-24.mmdb"
530+
with open(filename, "rb") as f:
531+
buf = io.BytesIO(f.read())
532+
# we have to use unpatched open_database here because the patched version
533+
# calls open() on our buffer
534+
reader = maxminddb.open_database(buf, MODE_FD)
535+
self._check_ip_v4(reader, filename)
536+
reader.close()
537+
527538
if os.name != "nt":
528539

529540
def test_multiprocessing(self):

0 commit comments

Comments
 (0)