Skip to content

Commit a01a1ba

Browse files
committed
Use file mode if mmap is not available
1 parent 406b8bf commit a01a1ba

File tree

3 files changed

+49
-5
lines changed

3 files changed

+49
-5
lines changed

maxminddb/file.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""This is intended for internal use only"""
2+
3+
import os
4+
5+
6+
class FileBuffer(object):
7+
8+
"""A slice-able file reader"""
9+
10+
def __init__(self, database):
11+
self._handle = open(database, 'rb')
12+
self._size = os.fstat(self._handle.fileno()).st_size
13+
14+
def __getitem__(self, key):
15+
if isinstance(key, slice):
16+
self._handle.seek(key.start)
17+
return self._handle.read(key.stop - key.start)
18+
elif isinstance(key, int):
19+
self._handle.seek(key)
20+
return self._handle.read(1)
21+
else:
22+
raise TypeError("Invalid argument type.")
23+
24+
def rfind(self, needle, beg):
25+
start = max(0, beg)
26+
self._handle.seek(start)
27+
pos = self._handle.read(self._size - start - 1).rfind(needle)
28+
if pos == -1:
29+
return pos
30+
return start + pos
31+
32+
def size(self):
33+
return self._size
34+
35+
def close(self):
36+
self._handle.close()

maxminddb/reader.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,17 @@
77
"""
88
from __future__ import unicode_literals
99

10-
import mmap
10+
try:
11+
import mmap
12+
except:
13+
mmap = None
14+
1115
import struct
1216

1317
from maxminddb.compat import byte_from_int, int_from_byte, ipaddress
1418
from maxminddb.decoder import Decoder
1519
from maxminddb.errors import InvalidDatabaseError
20+
from maxminddb.file import FileBuffer
1621

1722

1823
class Reader(object):
@@ -34,9 +39,12 @@ def __init__(self, database):
3439
database -- A path to a valid MaxMind DB file such as a GeoIP2
3540
database file.
3641
"""
37-
with open(database, 'rb') as db_file:
38-
self._buffer = mmap.mmap(
39-
db_file.fileno(), 0, access=mmap.ACCESS_READ)
42+
if mmap:
43+
with open(database, 'rb') as db_file:
44+
self._buffer = mmap.mmap(
45+
db_file.fileno(), 0, access=mmap.ACCESS_READ)
46+
else:
47+
self._buffer = FileBuffer(database)
4048

4149
metadata_start = self._buffer.rfind(self._METADATA_START_MARKER,
4250
self._buffer.size() - 128 * 1024)

tests/reader_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def test_closed_get(self):
163163
reader.close()
164164
self.assertRaisesRegex(ValueError,
165165
'Attempt to read from a closed MaxMind DB.'
166-
'|closed or invalid',
166+
'|closed',
167167
reader.get, ('1.1.1.1'))
168168

169169
# XXX - Figure out whether we want to have the same behavior on both the

0 commit comments

Comments
 (0)