Skip to content

Commit 4aeb00e

Browse files
authored
Merge pull request #32 from maxmind/greg/object-input
No longer allow ipaddress objects in pure Python implementation
2 parents 0b651e2 + e9e1cc2 commit 4aeb00e

File tree

12 files changed

+133
-72
lines changed

12 files changed

+133
-72
lines changed

.travis-yapf.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
3+
diff=$(yapf -rd maxminddb tests)
4+
5+
if [[ $? != 0 ]]; then
6+
echo "yapf failed to run."
7+
echo "$diff"
8+
exit $?
9+
elif [[ $diff ]]; then
10+
echo "$diff"
11+
exit 1
12+
else
13+
exit 0
14+
fi

.travis.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ python:
55
- 2.7
66
- 3.3
77
- 3.4
8+
- 3.5
9+
- 3.6
810
- pypy
911

1012
before_install:
@@ -17,13 +19,15 @@ before_install:
1719
- sudo make install
1820
- sudo ldconfig
1921
- cd ..
20-
- pip install pylint coveralls
22+
- pip install coverage coveralls
23+
- if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then pip install pylint yapf; fi
2124
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install unittest2; fi
2225

2326
script:
2427
- if [[ $TRAVIS_PYTHON_VERSION != 'pypy' ]]; then export MM_FORCE_EXT_TESTS=1; fi
25-
- CFLAGS="-Werror -Wall -Wextra" python setup.py test
26-
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pylint --rcfile .pylintrc maxminddb/*.py; fi
28+
- CFLAGS="-Werror -Wall -Wextra" coverage run --source maxminddb setup.py test
29+
- if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then pylint --rcfile .pylintrc maxminddb/*.py; fi
30+
- if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then ./.travis-yapf.sh; fi
2731

2832
after_success:
2933
- coveralls

HISTORY.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,20 @@
33
History
44
-------
55

6+
1.4.0
7+
++++++++++++++++++
8+
9+
* IMPORTANT: Previously, the pure Python reader would allow
10+
`ipaddress.IPv4Address` and `ipaddress.IPv6Address` objects when calling
11+
`.get()`. This would fail with the C extension. The fact that these objects
12+
worked at all was an implementation detail and has varied with different
13+
releases. This release makes the pure Python implementation consistent
14+
with the extension. A `TypeError` will now be thrown if you attempt to
15+
use these types with either the pure Python implementation or the
16+
extension. The IP address passed to `.get()` should be a string type.
17+
* Fix issue where incorrect size was used when unpacking some types with the
18+
pure Python reader. Reported by Lee Symes. GitHub #30.
19+
620
1.3.0 (2017-03-13)
721
++++++++++++++++++
822

docs/conf.py

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
sys.path.insert(0, os.path.abspath('..'))
1919
import maxminddb
2020

21-
2221
__version__ = maxminddb.__version__
2322

2423
# If extensions (or modules to document with autodoc) are in another directory,
@@ -33,8 +32,10 @@
3332

3433
# Add any Sphinx extension module names here, as strings. They can be extensions
3534
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
36-
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest',
37-
'sphinx.ext.intersphinx', 'sphinx.ext.coverage']
35+
extensions = [
36+
'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx',
37+
'sphinx.ext.coverage'
38+
]
3839

3940
# Add any paths that contain templates here, relative to this directory.
4041
templates_path = ['_templates']
@@ -95,7 +96,6 @@
9596
# A list of ignored prefixes for module index sorting.
9697
#modindex_common_prefix = []
9798

98-
9999
# -- Options for HTML output ---------------------------------------------
100100

101101
# The theme to use for HTML and HTML Help pages. See the documentation for
@@ -175,7 +175,6 @@
175175
# Output file base name for HTML help builder.
176176
htmlhelp_basename = 'maxminddbdoc'
177177

178-
179178
# -- Options for LaTeX output --------------------------------------------
180179

181180
latex_elements = {
@@ -192,8 +191,8 @@
192191
# Grouping the document tree into LaTeX files. List of tuples
193192
# (source start file, target name, title, author, documentclass [howto/manual]).
194193
latex_documents = [
195-
('index', 'maxminddb.tex', 'maxminddb Documentation',
196-
'Gregory Oschwald', 'manual'),
194+
('index', 'maxminddb.tex', 'maxminddb Documentation', 'Gregory Oschwald',
195+
'manual'),
197196
]
198197

199198
# The name of an image file (relative to this directory) to place at the top of
@@ -216,29 +215,24 @@
216215
# If false, no module index is generated.
217216
#latex_domain_indices = True
218217

219-
220218
# -- Options for manual page output --------------------------------------
221219

222220
# One entry per manual page. List of tuples
223221
# (source start file, name, description, authors, manual section).
224-
man_pages = [
225-
('index', 'maxminddb', 'maxminddb Documentation',
226-
['Gregory Oschwald'], 1)
227-
]
222+
man_pages = [('index', 'maxminddb', 'maxminddb Documentation',
223+
['Gregory Oschwald'], 1)]
228224

229225
# If true, show URL addresses after external links.
230226
#man_show_urls = False
231227

232-
233228
# -- Options for Texinfo output ------------------------------------------
234229

235230
# Grouping the document tree into Texinfo files. List of tuples
236231
# (source start file, target name, title, author,
237232
# dir menu entry, description, category)
238233
texinfo_documents = [
239-
('index', 'maxminddb', 'maxminddb Documentation',
240-
'Gregory Oschwald', 'maxminddb', 'MaxMind DB Reader',
241-
'Miscellaneous'),
234+
('index', 'maxminddb', 'maxminddb Documentation', 'Gregory Oschwald',
235+
'maxminddb', 'MaxMind DB Reader', 'Miscellaneous'),
242236
]
243237

244238
# Documents to append as an appendix to all manuals.
@@ -250,6 +244,5 @@
250244
# How to display URL addresses: 'footnote', 'no', or 'inline'.
251245
#texinfo_show_urls = 'footnote'
252246

253-
254247
# Example configuration for intersphinx: refer to the Python standard library.
255248
intersphinx_mapping = {'http://docs.python.org/': None}

examples/benchmark.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@
1111
import timeit
1212

1313
parser = argparse.ArgumentParser(description='Benchmark maxminddb.')
14-
parser.add_argument('--count', default=250000, type=int,
15-
help='number of lookups')
16-
parser.add_argument('--mode', default=0, type=int,
17-
help='reader mode to use')
18-
parser.add_argument('--file', default='GeoIP2-City.mmdb',
19-
help='path to mmdb file')
14+
parser.add_argument(
15+
'--count', default=250000, type=int, help='number of lookups')
16+
parser.add_argument('--mode', default=0, type=int, help='reader mode to use')
17+
parser.add_argument(
18+
'--file', default='GeoIP2-City.mmdb', help='path to mmdb file')
2019

2120
args = parser.parse_args()
2221

@@ -28,8 +27,9 @@ def lookup_ip_address():
2827
record = reader.get(str(ip))
2928

3029

31-
elapsed = timeit.timeit('lookup_ip_address()',
32-
setup='from __main__ import lookup_ip_address',
33-
number=args.count)
30+
elapsed = timeit.timeit(
31+
'lookup_ip_address()',
32+
setup='from __main__ import lookup_ip_address',
33+
number=args.count)
3434

3535
print(args.count / elapsed, 'lookups per second')

maxminddb/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ def open_database(database, mode=MODE_AUTO):
2727
* MODE_AUTO - tries MODE_MMAP_EXT, MODE_MMAP, MODE_FILE in that
2828
order. Default mode.
2929
"""
30-
has_extension = maxminddb.extension and hasattr(maxminddb.extension, 'Reader')
30+
has_extension = maxminddb.extension and hasattr(maxminddb.extension,
31+
'Reader')
3132
if (mode == MODE_AUTO and has_extension) or mode == MODE_MMAP_EXT:
3233
if not has_extension:
3334
raise ValueError(
34-
"MODE_MMAP_EXT requires the maxminddb.extension module to be available")
35+
"MODE_MMAP_EXT requires the maxminddb.extension module to be available"
36+
)
3537
return maxminddb.extension.Reader(database)
3638
elif mode in (MODE_AUTO, MODE_MMAP, MODE_FILE, MODE_MEMORY):
3739
return maxminddb.reader.Reader(database, mode)

maxminddb/compat.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ def int_from_bytes(b):
2121
return 0
2222

2323
byte_from_int = chr
24+
25+
string_type = basestring
26+
27+
string_type_name = 'string'
2428
else:
2529

2630
def compat_ip_address(address):
@@ -33,3 +37,7 @@ def compat_ip_address(address):
3337
int_from_bytes = lambda x: int.from_bytes(x, 'big')
3438

3539
byte_from_int = lambda x: bytes([x])
40+
41+
string_type = str
42+
43+
string_type_name = string_type.__name__

maxminddb/decoder.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def _decode_packed_type(type_code, type_size, pad=False):
5050
def unpack_type(self, size, offset):
5151
if not pad:
5252
self._verify_size(size, type_size)
53-
new_offset = offset + type_size
53+
new_offset = offset + size
5454
packed_bytes = self._buffer[offset:new_offset]
5555
if pad:
5656
packed_bytes = packed_bytes.rjust(type_size, b'\x00')
@@ -105,8 +105,7 @@ def _decode_utf8_string(self, size, offset):
105105
5: _decode_uint, # uint16
106106
6: _decode_uint, # uint32
107107
7: _decode_map,
108-
8: _decode_packed_type(
109-
b'!i', 4, pad=True), # int32
108+
8: _decode_packed_type(b'!i', 4, pad=True), # int32
110109
9: _decode_uint, # uint64
111110
10: _decode_uint, # uint128
112111
11: _decode_array,

maxminddb/reader.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515

1616
import struct
1717

18-
from maxminddb.compat import byte_from_int, compat_ip_address
18+
from maxminddb.compat import (byte_from_int, compat_ip_address, string_type,
19+
string_type_name)
1920
from maxminddb.const import MODE_AUTO, MODE_MMAP, MODE_FILE, MODE_MEMORY
2021
from maxminddb.decoder import Decoder
2122
from maxminddb.errors import InvalidDatabaseError
@@ -93,6 +94,9 @@ def get(self, ip_address):
9394
Arguments:
9495
ip_address -- an IP address in the standard string notation
9596
"""
97+
if not isinstance(ip_address, string_type):
98+
raise TypeError('argument 1 must be %s, not %s' %
99+
(string_type_name, type(ip_address).__name__))
96100

97101
address = compat_ip_address(ip_address)
98102

@@ -155,14 +159,13 @@ def _read_node(self, node_number, index):
155159
else:
156160
middle = (0xF0 & middle) >> 4
157161
offset = base_offset + index * 4
158-
node_bytes = byte_from_int(middle) + self._buffer[offset:offset +
159-
3]
162+
node_bytes = byte_from_int(middle) + self._buffer[offset:offset + 3]
160163
elif record_size == 32:
161164
offset = base_offset + index * 4
162165
node_bytes = self._buffer[offset:offset + 4]
163166
else:
164-
raise InvalidDatabaseError('Unknown record size: {0}'.format(
165-
record_size))
167+
raise InvalidDatabaseError(
168+
'Unknown record size: {0}'.format(record_size))
166169
return struct.unpack(b'!I', node_bytes)[0]
167170

168171
def _resolve_data_pointer(self, pointer):

setup.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
JYTHON = sys.platform.startswith('java')
1717
requirements = []
1818

19-
if sys.version_info[0] == 2 or (sys.version_info[0] == 3 and
20-
sys.version_info[1] < 3):
19+
if sys.version_info[0] == 2 or (sys.version_info[0] == 3
20+
and sys.version_info[1] < 3):
2121
requirements.append('ipaddress')
2222

2323
compile_args = ['-Wall', '-Wextra']
@@ -30,7 +30,8 @@
3030
'maxminddb.extension',
3131
libraries=['maxminddb'],
3232
sources=['maxminddb/extension/maxminddb.c'],
33-
extra_compile_args=compile_args, )
33+
extra_compile_args=compile_args,
34+
)
3435
]
3536

3637
# Cargo cult code for installing extension with pure Python fallback.
@@ -95,8 +96,8 @@ def status_msgs(*msgs):
9596
def find_packages(location):
9697
packages = []
9798
for pkg in ['maxminddb']:
98-
for _dir, subdirectories, files in (
99-
os.walk(os.path.join(location, pkg))):
99+
for _dir, subdirectories, files in (os.walk(
100+
os.path.join(location, pkg))):
100101
if '__init__.py' in files:
101102
tokens = _dir.split(os.sep)[len(location.split(os.sep)):]
102103
packages.append(".".join(tokens))
@@ -108,7 +109,8 @@ def run_setup(with_cext):
108109
if with_cext:
109110
if Feature:
110111
kwargs['features'] = {
111-
'extension': Feature(
112+
'extension':
113+
Feature(
112114
"optional C implementation",
113115
standard=True,
114116
ext_modules=ext_module)

0 commit comments

Comments
 (0)