From ba7f44f407297ae9b547a893272b1764f6304524 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Mon, 7 Apr 2014 13:48:06 -0700 Subject: [PATCH 1/6] Initialize class properly --- .travis.yml | 2 +- maxminddb/__init__.py | 6 ++++-- maxminddb/extension/maxminddb.c | 33 ++++++++++++++++++++------------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index aa8693f..49c1f87 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ before_install: - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install unittest2; fi script: - - CFLAGS="-Werror -Wall -Wextra" python setup.py test + - MAXMINDDB_PURE_PYTHON=0 CFLAGS="-Werror -Wall -Wextra" python setup.py test - MAXMINDDB_PURE_PYTHON=1 coverage run --source=maxminddb setup.py test - if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pylint --rcfile .pylintrc maxminddb/*.py; fi diff --git a/maxminddb/__init__.py b/maxminddb/__init__.py index 37a4468..304ae05 100644 --- a/maxminddb/__init__.py +++ b/maxminddb/__init__.py @@ -2,10 +2,12 @@ import os try: - if os.environ.get('MAXMINDDB_PURE_PYTHON'): + if os.environ.get('MAXMINDDB_PURE_PYTHON') == '1': raise ImportError() from maxminddb.extension import Reader, InvalidDatabaseError -except ImportError: +except ImportError as e: + if os.environ.get('MAXMINDDB_PURE_PYTHON') == '0': + raise e from maxminddb.decoder import InvalidDatabaseError from maxminddb.reader import Reader diff --git a/maxminddb/extension/maxminddb.c b/maxminddb/extension/maxminddb.c index 22f780a..b63f3d8 100644 --- a/maxminddb/extension/maxminddb.c +++ b/maxminddb/extension/maxminddb.c @@ -49,47 +49,47 @@ static PyObject *from_uint128(const MMDB_entry_data_list_s *entry_data_list); # define UNUSED(x) UNUSED_ ## x #endif -static PyObject *Reader_constructor(PyObject *UNUSED(self), PyObject *args) +static int Reader_constructor(PyObject *self, PyObject *args, PyObject *UNUSED(kwds)) { char *filename; if (!PyArg_ParseTuple(args, "s", &filename)) { - return NULL; + return -1; } if (0 != access(filename, R_OK)) { PyErr_Format(FILE_NOT_FOUND_ERROR, "No such file or directory: '%s'", filename); - return NULL; + return -1; } MMDB_s *mmdb = (MMDB_s *)malloc(sizeof(MMDB_s)); if (NULL == mmdb) { PyErr_NoMemory(); - return NULL; + return -1; } - Reader_obj *obj = PyObject_New(Reader_obj, &Reader_Type); - if (!obj) { + Reader_obj *mmdb_obj = (Reader_obj *)self; + if (!mmdb_obj) { PyErr_NoMemory(); - return NULL; + return -1; } uint16_t status = MMDB_open(filename, MMDB_MODE_MMAP, mmdb); if (MMDB_SUCCESS != status) { free(mmdb); - PyObject_Del(obj); - return PyErr_Format( + PyErr_Format( MaxMindDB_error, "Error opening database file (%s). Is this a valid MaxMind DB file?", filename ); + return -1; } - obj->mmdb = mmdb; - return (PyObject *)obj; + mmdb_obj->mmdb = mmdb; + return 0; } static PyObject *Reader_get(PyObject *self, PyObject *args) @@ -418,6 +418,7 @@ static PyTypeObject Reader_Type = { .tp_flags = Py_TPFLAGS_DEFAULT, .tp_methods = Reader_methods, .tp_name = "Reader", + .tp_init = Reader_constructor, }; static PyMethodDef Metadata_methods[] = { @@ -460,11 +461,10 @@ static PyTypeObject Metadata_Type = { }; static PyMethodDef MaxMindDB_methods[] = { - { "Reader", Reader_constructor, METH_VARARGS, - "Creates a new maxminddb.extension.Reader object" }, { NULL, NULL, 0, NULL} }; + #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef MaxMindDB_module = { PyModuleDef_HEAD_INIT, @@ -506,6 +506,13 @@ MOD_INIT(extension){ RETURN_MOD_INIT(NULL); } + Reader_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&Reader_Type)) { + RETURN_MOD_INIT(NULL); + } + Py_INCREF(&Reader_Type); + PyModule_AddObject(m, "Reader", (PyObject *)&Reader_Type); + Py_INCREF(MaxMindDB_error); PyModule_AddObject(m, "InvalidDatabaseError", MaxMindDB_error); From 168b6996fa53729a0a39e8985b67956b4c3a365a Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Mon, 7 Apr 2014 13:51:51 -0700 Subject: [PATCH 2/6] Initialize in struct --- maxminddb/extension/maxminddb.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/maxminddb/extension/maxminddb.c b/maxminddb/extension/maxminddb.c index b63f3d8..b828d1c 100644 --- a/maxminddb/extension/maxminddb.c +++ b/maxminddb/extension/maxminddb.c @@ -419,6 +419,7 @@ static PyTypeObject Reader_Type = { .tp_methods = Reader_methods, .tp_name = "Reader", .tp_init = Reader_constructor, + .tp_new = PyType_GenericNew, }; static PyMethodDef Metadata_methods[] = { @@ -506,10 +507,6 @@ MOD_INIT(extension){ RETURN_MOD_INIT(NULL); } - Reader_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&Reader_Type)) { - RETURN_MOD_INIT(NULL); - } Py_INCREF(&Reader_Type); PyModule_AddObject(m, "Reader", (PyObject *)&Reader_Type); From ff4168c1cd12f36616acf404eff9f90a3b77b9ea Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Mon, 7 Apr 2014 14:08:49 -0700 Subject: [PATCH 3/6] Make pylint happy --- maxminddb/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/maxminddb/__init__.py b/maxminddb/__init__.py index 304ae05..d7aef0f 100644 --- a/maxminddb/__init__.py +++ b/maxminddb/__init__.py @@ -5,9 +5,9 @@ if os.environ.get('MAXMINDDB_PURE_PYTHON') == '1': raise ImportError() from maxminddb.extension import Reader, InvalidDatabaseError -except ImportError as e: +except ImportError as import_error: if os.environ.get('MAXMINDDB_PURE_PYTHON') == '0': - raise e + raise import_error from maxminddb.decoder import InvalidDatabaseError from maxminddb.reader import Reader From ed7ec3b233868f9e81d7ba6237b58a47bc3ed7fd Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Mon, 7 Apr 2014 14:22:38 -0700 Subject: [PATCH 4/6] Revert "Initialize in struct" This reverts commit 168b6996fa53729a0a39e8985b67956b4c3a365a. Apparently some compilers can't handle initialization to a function defined in another module. --- maxminddb/extension/maxminddb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/maxminddb/extension/maxminddb.c b/maxminddb/extension/maxminddb.c index b828d1c..b63f3d8 100644 --- a/maxminddb/extension/maxminddb.c +++ b/maxminddb/extension/maxminddb.c @@ -419,7 +419,6 @@ static PyTypeObject Reader_Type = { .tp_methods = Reader_methods, .tp_name = "Reader", .tp_init = Reader_constructor, - .tp_new = PyType_GenericNew, }; static PyMethodDef Metadata_methods[] = { @@ -507,6 +506,10 @@ MOD_INIT(extension){ RETURN_MOD_INIT(NULL); } + Reader_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&Reader_Type)) { + RETURN_MOD_INIT(NULL); + } Py_INCREF(&Reader_Type); PyModule_AddObject(m, "Reader", (PyObject *)&Reader_Type); From 70928f42c9e278fd30ae5a30638ad2aab3764fca Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Mon, 7 Apr 2014 15:55:32 -0700 Subject: [PATCH 5/6] Clean up metadata object creation --- maxminddb/extension/maxminddb.c | 162 ++++++++++++++++++-------------- 1 file changed, 93 insertions(+), 69 deletions(-) diff --git a/maxminddb/extension/maxminddb.c b/maxminddb/extension/maxminddb.c index b63f3d8..e23f67c 100644 --- a/maxminddb/extension/maxminddb.c +++ b/maxminddb/extension/maxminddb.c @@ -49,7 +49,7 @@ static PyObject *from_uint128(const MMDB_entry_data_list_s *entry_data_list); # define UNUSED(x) UNUSED_ ## x #endif -static int Reader_constructor(PyObject *self, PyObject *args, PyObject *UNUSED(kwds)) +static int Reader_init(PyObject *self, PyObject *args, PyObject *UNUSED(kwds)) { char *filename; @@ -81,10 +81,10 @@ static int Reader_constructor(PyObject *self, PyObject *args, PyObject *UNUSED(k if (MMDB_SUCCESS != status) { free(mmdb); PyErr_Format( - MaxMindDB_error, - "Error opening database file (%s). Is this a valid MaxMind DB file?", - filename - ); + MaxMindDB_error, + "Error opening database file (%s). Is this a valid MaxMind DB file?", + filename + ); return -1; } @@ -170,11 +170,6 @@ static PyObject *Reader_metadata(PyObject *self, PyObject *UNUSED(args)) return NULL; } - Metadata_obj *obj = PyObject_New(Metadata_obj, &Metadata_Type); - if (!obj) { - return NULL; - } - MMDB_entry_data_list_s *entry_data_list; MMDB_get_metadata_as_entry_data_list(mmdb_obj->mmdb, &entry_data_list); MMDB_entry_data_list_s *original_entry_data_list = entry_data_list; @@ -184,50 +179,20 @@ static PyObject *Reader_metadata(PyObject *self, PyObject *UNUSED(args)) if (NULL == metadata_dict || !PyDict_Check(metadata_dict)) { PyErr_SetString(MaxMindDB_error, "Error decoding metadata."); - PyObject_Del(obj); return NULL; } - obj->binary_format_major_version = PyDict_GetItemString( - metadata_dict, "binary_format_major_version"); - obj->binary_format_minor_version = PyDict_GetItemString( - metadata_dict, "binary_format_minor_version"); - obj->build_epoch = PyDict_GetItemString(metadata_dict, "build_epoch"); - obj->database_type = PyDict_GetItemString(metadata_dict, "database_type"); - obj->description = PyDict_GetItemString(metadata_dict, "description"); - obj->ip_version = PyDict_GetItemString(metadata_dict, "ip_version"); - obj->languages = PyDict_GetItemString(metadata_dict, "languages"); - obj->node_count = PyDict_GetItemString(metadata_dict, "node_count"); - obj->record_size = PyDict_GetItemString(metadata_dict, "record_size"); - - if (NULL == obj->binary_format_major_version || - NULL == obj->binary_format_minor_version || - NULL == obj->build_epoch || - NULL == obj->database_type || - NULL == obj->description || - NULL == obj->ip_version || - NULL == obj->languages || - NULL == obj->node_count || - NULL == obj->record_size) { - PyErr_SetString(MaxMindDB_error, - "Error decoding metadata."); - PyObject_Del(obj); + PyObject *args = PyTuple_New(0); + if (NULL == args) { + Py_DECREF(metadata_dict); return NULL; } - Py_INCREF(obj->binary_format_major_version); - Py_INCREF(obj->binary_format_minor_version); - Py_INCREF(obj->build_epoch); - Py_INCREF(obj->database_type); - Py_INCREF(obj->description); - Py_INCREF(obj->ip_version); - Py_INCREF(obj->languages); - Py_INCREF(obj->node_count); - Py_INCREF(obj->record_size); + PyObject *metadata = PyObject_Call((PyObject *)&Metadata_Type, args, + metadata_dict); Py_DECREF(metadata_dict); - - return (PyObject *)obj; + return metadata; } static PyObject *Reader_close(PyObject *self, PyObject *UNUSED(args)) @@ -253,6 +218,71 @@ static void Reader_dealloc(PyObject *self) PyObject_Del(self); } +static int Metadata_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + + PyObject + *binary_format_major_version, + *binary_format_minor_version, + *build_epoch, + *database_type, + *description, + *ip_version, + *languages, + *node_count, + *record_size; + + static char *kwlist[] = { + "binary_format_major_version", + "binary_format_minor_version", + "build_epoch", + "database_type", + "description", + "ip_version", + "languages", + "node_count", + "record_size", + NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOOOOOOO", kwlist, + &binary_format_major_version, + &binary_format_minor_version, + &build_epoch, + &database_type, + &description, + &ip_version, + &languages, + &node_count, + &record_size)) { + return -1; + } + + Metadata_obj *obj = (Metadata_obj *)self; + + obj->binary_format_major_version = binary_format_major_version; + obj->binary_format_minor_version = binary_format_minor_version; + obj->build_epoch = build_epoch; + obj->database_type = database_type; + obj->description = description; + obj->ip_version = ip_version; + obj->languages = languages; + obj->node_count = node_count; + obj->record_size = record_size; + + Py_INCREF(obj->binary_format_major_version); + Py_INCREF(obj->binary_format_minor_version); + Py_INCREF(obj->build_epoch); + Py_INCREF(obj->database_type); + Py_INCREF(obj->description); + Py_INCREF(obj->ip_version); + Py_INCREF(obj->languages); + Py_INCREF(obj->node_count); + Py_INCREF(obj->record_size); + + return 0; +} + static void Metadata_dealloc(PyObject *self) { Metadata_obj *obj = (Metadata_obj *)self; @@ -406,8 +436,8 @@ static PyMethodDef Reader_methods[] = { "Get record for IP address" }, { "metadata", Reader_metadata, METH_NOARGS, "Returns metadata object for database" }, - { "close", Reader_close, METH_NOARGS, "Closes database"}, - { NULL, NULL, 0, NULL } + { "close", Reader_close, METH_NOARGS, "Closes database" }, + { NULL, NULL, 0, NULL } }; static PyTypeObject Reader_Type = { @@ -418,7 +448,7 @@ static PyTypeObject Reader_Type = { .tp_flags = Py_TPFLAGS_DEFAULT, .tp_methods = Reader_methods, .tp_name = "Reader", - .tp_init = Reader_constructor, + .tp_init = Reader_init, }; static PyMethodDef Metadata_methods[] = { @@ -458,10 +488,11 @@ static PyTypeObject Metadata_Type = { .tp_members = Metadata_members, .tp_methods = Metadata_methods, .tp_name = "Metadata", + .tp_init = Metadata_init }; static PyMethodDef MaxMindDB_methods[] = { - { NULL, NULL, 0, NULL} + { NULL, NULL, 0, NULL } }; @@ -474,16 +505,6 @@ static struct PyModuleDef MaxMindDB_module = { }; #endif -static void init_type(PyObject *m, PyTypeObject *type) -{ - Metadata_Type.tp_new = PyType_GenericNew; - - if (PyType_Ready(type) == 0) { - Py_INCREF(type); - PyModule_AddObject(m, "extension", (PyObject *)type); - } -} - MOD_INIT(extension){ PyObject *m; @@ -497,15 +518,6 @@ MOD_INIT(extension){ RETURN_MOD_INIT(NULL); } - init_type(m, &Reader_Type); - init_type(m, &Metadata_Type); - - MaxMindDB_error = PyErr_NewException("extension.InvalidDatabaseError", NULL, - NULL); - if (MaxMindDB_error == NULL) { - RETURN_MOD_INIT(NULL); - } - Reader_Type.tp_new = PyType_GenericNew; if (PyType_Ready(&Reader_Type)) { RETURN_MOD_INIT(NULL); @@ -513,6 +525,18 @@ MOD_INIT(extension){ Py_INCREF(&Reader_Type); PyModule_AddObject(m, "Reader", (PyObject *)&Reader_Type); + Metadata_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&Metadata_Type)) { + RETURN_MOD_INIT(NULL); + } + PyModule_AddObject(m, "extension", (PyObject *)&Metadata_Type); + + MaxMindDB_error = PyErr_NewException("extension.InvalidDatabaseError", NULL, + NULL); + if (MaxMindDB_error == NULL) { + RETURN_MOD_INIT(NULL); + } + Py_INCREF(MaxMindDB_error); PyModule_AddObject(m, "InvalidDatabaseError", MaxMindDB_error); From 50860833cd9896f60ffcd1d4fc72ed3bb7b8d0d4 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Mon, 7 Apr 2014 15:56:53 -0700 Subject: [PATCH 6/6] Don't test extension on PyPy --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 49c1f87..b5e70ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ before_install: - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install unittest2; fi script: - - MAXMINDDB_PURE_PYTHON=0 CFLAGS="-Werror -Wall -Wextra" python setup.py test + - if [[ $TRAVIS_PYTHON_VERSION != 'pypy' ]]; then MAXMINDDB_PURE_PYTHON=0 CFLAGS="-Werror -Wall -Wextra" python setup.py test; fi - MAXMINDDB_PURE_PYTHON=1 coverage run --source=maxminddb setup.py test - if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pylint --rcfile .pylintrc maxminddb/*.py; fi