1616import struct
1717
1818from maxminddb .compat import byte_from_int , int_from_byte , ipaddress
19+ from maxminddb .const import MODE_AUTO , MODE_MMAP , MODE_FILE , MODE_MEMORY
1920from maxminddb .decoder import Decoder
2021from maxminddb .errors import InvalidDatabaseError
2122from maxminddb .file import FileBuffer
@@ -33,24 +34,41 @@ class Reader(object):
3334
3435 _ipv4_start = None
3536
36- def __init__ (self , database ):
37+ def __init__ (self , database , mode = MODE_AUTO ):
3738 """Reader for the MaxMind DB file format
3839
3940 Arguments:
4041 database -- A path to a valid MaxMind DB file such as a GeoIP2
4142 database file.
43+ mode -- mode to open the database with. Valid mode are:
44+ * MODE_MMAP - read from memory map.
45+ * MODE_FILE - read database as standard file.
46+ * MODE_MEMORY - load database into memory.
47+ * MODE_AUTO - tries MODE_MMAP and then MODE_FILE. Default.
4248 """
43- if mmap :
49+ if ( mode == MODE_AUTO and mmap ) or mode == MODE_MMAP :
4450 with open (database , 'rb' ) as db_file :
4551 self ._buffer = mmap .mmap (
4652 db_file .fileno (), 0 , access = mmap .ACCESS_READ )
47- else :
53+ self ._buffer_size = self ._buffer .size ()
54+ elif mode in (MODE_AUTO , MODE_FILE ):
4855 self ._buffer = FileBuffer (database )
56+ self ._buffer_size = self ._buffer .size ()
57+ elif mode == MODE_MEMORY :
58+ with open (database , 'rb' ) as db_file :
59+ self ._buffer = db_file .read ()
60+ self ._buffer_size = len (self ._buffer )
61+ else :
62+ raise ValueError ('Unsupported open mode ({0}). Only MODE_AUTO, '
63+ ' MODE_FILE, and MODE_MEMORY are support by the pure Python '
64+ 'Reader' .format (mode ))
4965
5066 metadata_start = self ._buffer .rfind (self ._METADATA_START_MARKER ,
51- self ._buffer .size () - 128 * 1024 )
67+ max (0 , self ._buffer_size
68+ - 128 * 1024 ))
5269
5370 if metadata_start == - 1 :
71+ self .close ()
5472 raise InvalidDatabaseError ('Error opening database file ({0}). '
5573 'Is this a valid MaxMind DB file?'
5674 '' .format (database ))
@@ -149,7 +167,7 @@ def _resolve_data_pointer(self, pointer):
149167 resolved = pointer - self ._metadata .node_count + \
150168 self ._metadata .search_tree_size
151169
152- if resolved > self ._buffer . size () :
170+ if resolved > self ._buffer_size :
153171 raise InvalidDatabaseError (
154172 "The MaxMind DB file's search tree is corrupt" )
155173
@@ -158,7 +176,8 @@ def _resolve_data_pointer(self, pointer):
158176
159177 def close (self ):
160178 """Closes the MaxMind DB file and returns the resources to the system"""
161- self ._buffer .close ()
179+ if type (self ._buffer ) not in (str , bytes ):
180+ self ._buffer .close ()
162181
163182
164183class Metadata (object ):
0 commit comments