diff --git a/configure b/configure
index 1687443..85498d3 100755
--- a/configure
+++ b/configure
@@ -3674,7 +3674,7 @@ if test "x$with_python" = "xno"; then
 $as_echo "skipped" >&6; }
   PYTHONVERS=
 else
-  PYTHONVERS=$(ls /usr/include/python2.*/Python.h 2> /dev/null | sed 's|/usr/include/\([^/]*\)/Python.h|\1|g' | tr '\n' ' ')
+  PYTHONVERS=$(ls -d /usr/lib/python* 2> /dev/null | sed 's|/usr/lib/||g' | tr '\n' ' ')
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHONVERS" >&5
 $as_echo "$PYTHONVERS" >&6; }
 fi
diff --git a/configure.ac b/configure.ac
index 02f9d6d..3aef2f4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -60,7 +60,7 @@ if test "x$with_python" = "xno"; then
   AC_MSG_RESULT([skipped])
   PYTHONVERS=
 else
-  PYTHONVERS=$(ls /usr/include/python2.*/Python.h 2> /dev/null | sed 's|/usr/include/\([[^/]]*\)/Python.h|\1|g' | tr '\n' ' ')
+  PYTHONVERS=$(ls -d /usr/lib/python* 2> /dev/null | sed 's|/usr/lib/||g' | tr '\n' ' ')
   AC_MSG_RESULT([$PYTHONVERS])
 fi
 AC_SUBST([PYTHONVERS])
diff --git a/peanuts.py b/peanuts.py
index 608a5fb..535571d 100755
--- a/peanuts.py
+++ b/peanuts.py
@@ -2,6 +2,7 @@
 
 # Demo program to show use of python-newt module
 
+from __future__ import absolute_import, print_function, unicode_literals
 from snack import *
 
 screen = SnackScreen()
@@ -38,8 +39,8 @@ result = g.runOnce()
 
 screen.finish()
 
-print result
-print "listbox:", li.current()
-print "rb:", rb.getSelection()
-print "bb:", bb.buttonPressed(result)
-print "checkboxtree:", ct.getSelection()
+print(result)
+print("listbox:", li.current())
+print("rb:", rb.getSelection())
+print("bb:", bb.buttonPressed(result))
+print("checkboxtree:", ct.getSelection())
diff --git a/popcorn.py b/popcorn.py
index 9798218..5d5a345 100755
--- a/popcorn.py
+++ b/popcorn.py
@@ -1,5 +1,6 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
 from snack import *
 import sys
 
@@ -45,7 +46,7 @@ r1 = SingleRadioButton("Radio 1", None, 1)
 r2 = SingleRadioButton("Radio 2", r1)
 
 def something():
-    print hello
+    print(hello)
 
 screen = SnackScreen()
 
@@ -99,14 +100,14 @@ g.runOnce()
 
 screen.finish()
 
-print "val", e.value()
-print "check", cb.value()
-print "r1", r1.selected()
-print "listbox", li.current()
+print("val", e.value())
+print("check", cb.value())
+print("r1", r1.selected())
+print("listbox", li.current())
 # returns a tuple of the wrapped text, the actual width, and the actual height
-print res
+print(res)
 
-print foo
-print 'lbcw', lbcw
-print "ct selected", ct.getSelection()
-print "ct current", ct.getCurrent()
+print(foo)
+print('lbcw', lbcw)
+print("ct selected", ct.getSelection())
+print("ct current", ct.getCurrent())
diff --git a/snack.py b/snack.py
index 09506a4..0e42112 100644
--- a/snack.py
+++ b/snack.py
@@ -39,9 +39,11 @@ Functions:
  - EntryWindow
 """
 
+
+from __future__ import absolute_import, print_function, unicode_literals
 import _snack
-import types
 import string
+import sys
 
 from _snack import FLAG_DISABLED, FLAGS_SET, FLAGS_RESET, FLAGS_TOGGLE, FD_READ, FD_WRITE, FD_EXCEPT
 
@@ -304,7 +306,7 @@ hotkeys = { "F1" : _snack.KEY_F1, "F2" : _snack.KEY_F2, "F3" : _snack.KEY_F3,
             "INSERT": _snack.KEY_INSERT,
              " " : ord(" ") }
 
-for n in hotkeys.keys():
+for n in list(hotkeys.keys()):
     hotkeys[hotkeys[n]] = n
 for o,c in [ (ord(c),c) for c in string.ascii_letters+string.digits ]:
     hotkeys[c] = o
@@ -328,14 +330,14 @@ class Form:
         self.w.addhotkey(hotkeys[keyname])
 
     def add(self, widget):
-        if widget.__dict__.has_key('hotkeys'):
+        if 'hotkeys' in widget.__dict__:
             for key in widget.hotkeys.keys():
                 self.addHotKey(key)
 
-        if widget.__dict__.has_key('gridmembers'):
+        if 'gridmembers' in widget.__dict__:
             for w in widget.gridmembers:
                 self.add(w)
-        elif widget.__dict__.has_key('w'):
+        elif 'w' in widget.__dict__:
             self.trans[widget.w.key] = widget
             return self.w.add(widget.w)
         return None
@@ -408,14 +410,14 @@ class Grid:
         if (growy):
             gridFlags = gridFlags | _snack.GRID_GROWY
 
-        if (what.__dict__.has_key('g')):
+        if 'g' in what.__dict__:
             return self.g.setfield(col, row, what.g, padding, anchorFlags,
                        gridFlags)
         else:
             return self.g.setfield(col, row, what.w, padding, anchorFlags)
     
     def __init__(self, *args):
-        self.g = apply(_snack.grid, args)
+        self.g = _snack.grid(*args)
         self.gridmembers = []
 
 colorsets = { "ROOT" : _snack.COLORSET_ROOT,
@@ -604,9 +606,9 @@ class ButtonBar(Grid):
         self.item = 0
         Grid.__init__(self, len(buttonlist), 1)
         for blist in buttonlist:
-            if (type(blist) == types.StringType):
+            if isinstance(blist, str if sys.version >= '3' else basestring):
                 title = blist
-                value = string.lower(blist)
+                value = blist.lower()
             elif len(blist) == 2:
                 (title, value) = blist
             else:
@@ -622,7 +624,7 @@ class ButtonBar(Grid):
             self.item = self.item + 1
 
     def buttonPressed(self, result):    
-        if self.hotkeys.has_key(result):
+        if result in self.hotkeys:
             return self.hotkeys[result]
 
         for (button, value) in self.list:
@@ -657,7 +659,7 @@ class GridFormHelp(Grid):
         self.form_created = 0
         args = list(args)
         args[:0] = [self]
-        apply(Grid.__init__, tuple(args))
+        Grid.__init__(*tuple(args))
 
     def add(self, widget, col, row, padding = (0, 0, 0, 0),
             anchorLeft = 0, anchorTop = 0, anchorRight = 0,
@@ -713,7 +715,7 @@ class GridForm(GridFormHelp):
     """
     def __init__(self, screen, title, *args):
         myargs = (self, screen, title, None) + args
-        apply(GridFormHelp.__init__, myargs)
+        GridFormHelp.__init__(*myargs)
 
 class CheckboxTree(Widget):
     """ CheckboxTree combo widget,
@@ -788,7 +790,7 @@ def ListboxChoiceWindow(screen, title, text, items,
     l = Listbox(height, scroll = scroll, returnExit = 1)
     count = 0
     for item in items:
-        if (type(item) == types.TupleType):
+        if type(item) == tuple:
             (text, key) = item
         else:
             text = item
@@ -848,9 +850,9 @@ def EntryWindow(screen, title, text, prompts, allowCancel = 1, width = 40,
     count = 0
     entryList = []
     for n in prompts:
-        if (type(n) == types.TupleType):
+        if type(n) == tuple:
             (n, e) = n
-            if (type(e) in types.StringTypes):
+            if isinstance(e, str if sys.version >= '3' else basestring):
                 e = Entry(entryWidth, e)
         else:
             e = Entry(entryWidth)
diff --git a/snackmodule.c b/snackmodule.c
index a566d46..72b23e8 100644
--- a/snackmodule.c
+++ b/snackmodule.c
@@ -12,10 +12,24 @@
 #include <unistd.h>
 
 #include "Python.h"
+#include "structmember.h"
 #include "nls.h"
 #include "newt.h"
 #include "newt_pr.h"
 
+#if PY_MAJOR_VERSION >= 3
+  #define PyInt_FromLong PyLong_FromLong
+  #define PyInt_AsLong PyLong_AsLong
+  #define PyString_FromString PyUnicode_FromString
+  #define MOD_ERROR_VAL NULL
+  #define MOD_SUCCESS_VAL(val) val
+  #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
+#else
+  #define MOD_ERROR_VAL
+  #define MOD_SUCCESS_VAL(val)
+  #define MOD_INIT(name) void init##name(void)
+#endif
+
 typedef struct snackWidget_s snackWidget;
 typedef struct snackGrid_s snackGrid;
 typedef struct snackForm_s snackForm;
@@ -68,6 +82,8 @@ static snackWidget * textWidget(PyObject * s, PyObject * args);
 static PyObject * ternaryWindow(PyObject * s, PyObject * args);
 static snackWidget * checkboxTreeWidget(PyObject * s, PyObject * args, PyObject * kwargs);
 static PyObject * pywstrlen(PyObject * s, PyObject * args);
+static PyObject * widget_get_checkboxValue(PyObject *self, void *closure);
+static PyObject * widget_get_radioValue(PyObject *self, void *closure);
 
 static PyMethodDef snackModuleMethods[] = {
     { "button", (PyCFunction) buttonWidget, METH_VARARGS, NULL },
@@ -107,12 +123,31 @@ static PyMethodDef snackModuleMethods[] = {
     { NULL }
 } ;
 
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef moduledef = {
+    PyModuleDef_HEAD_INIT,
+        "_snack",            /* m_name */
+        NULL,                /* m_doc */
+        -1,                  /* m_size */
+        snackModuleMethods,  /* m_methods */
+        NULL,                /* m_reload */
+        NULL,                /* m_traverse */
+        NULL,                /* m_clear */
+        NULL,                /* m_free */
+    };
+#endif
+
+static struct PyGetSetDef widget_getset[] = {
+        { "checkboxValue", widget_get_checkboxValue, 0, NULL, NULL },
+        { "radioValue", widget_get_radioValue, 0, NULL, NULL },
+        { NULL }
+};
+
 struct snackGrid_s {
     PyObject_HEAD
     newtGrid grid;
 } ;
 
-static PyObject * gridGetAttr(PyObject * s, char * name);
 static PyObject * gridPlace(snackGrid * s, PyObject * args);
 static PyObject * gridSetField(snackGrid * s, PyObject * args);
 
@@ -123,20 +158,34 @@ static PyMethodDef gridMethods[] = {
 };
 
 static PyTypeObject snackGridType = {
-        PyObject_HEAD_INIT(&PyType_Type)
-        0,                              /* ob_size */
+        PyVarObject_HEAD_INIT(&PyType_Type, 0)
         "snackgrid",                    /* tp_name */
         sizeof(snackGrid),              /* tp_size */
         0,                              /* tp_itemsize */
         emptyDestructor,      			/* tp_dealloc */
         0,                              /* tp_print */
-        gridGetAttr,    		/* tp_getattr */
+        0,                   		/* tp_getattr */
         0,                              /* tp_setattr */
         0,                              /* tp_compare */
         0,                              /* tp_repr */
         0,                              /* tp_as_number */
         0,                              /* tp_as_sequence */
         0,                		/* tp_as_mapping */
+	0,                              /* tp_hash */
+	0,                              /* tp_call */
+	0,                              /* tp_str */
+	PyObject_GenericGetAttr,        /* tp_getattro */
+	0,                              /* tp_setattro */
+	0,                              /* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT,             /* tp_flags */
+	0,                              /* tp_doc */
+	0,                              /* tp_traverse */
+	0,                              /* tp_clear */
+	0,                              /* tp_richcompare */
+	0,                              /* tp_weaklistoffset */
+	0,                              /* tp_iter */
+	0,                              /* tp_iternext */
+	gridMethods                     /* tp_methods */
 };
 
 struct snackForm_s {
@@ -144,7 +193,6 @@ struct snackForm_s {
     newtComponent fo;
 } ;
 
-static PyObject * formGetAttr(PyObject * s, char * name);
 static PyObject * formAdd(snackForm * s, PyObject * args);
 static PyObject * formDraw(snackForm * s, PyObject * args);
 static PyObject * formRun(snackForm * s, PyObject * args);
@@ -165,20 +213,34 @@ static PyMethodDef formMethods[] = {
 };
 
 static PyTypeObject snackFormType = {
-        PyObject_HEAD_INIT(&PyType_Type)
-        0,                              /* ob_size */
+        PyVarObject_HEAD_INIT(&PyType_Type, 0)
         "snackform",                    /* tp_name */
         sizeof(snackForm),              /* tp_size */
         0,                              /* tp_itemsize */
         emptyDestructor,      		/* tp_dealloc */
         0,                              /* tp_print */
-        formGetAttr,    		/* tp_getattr */
+        0,                     		/* tp_getattr */
         0,                              /* tp_setattr */
         0,                              /* tp_compare */
         0,                              /* tp_repr */
         0,                              /* tp_as_number */
         0,                              /* tp_as_sequence */
         0,                		/* tp_as_mapping */
+	0,                              /* tp_hash */
+	0,                              /* tp_call */
+	0,                              /* tp_str */
+	PyObject_GenericGetAttr,        /* tp_getattro */
+	0,                              /* tp_setattro */
+	0,                              /* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT,             /* tp_flags */
+	0,                              /* tp_doc */
+	0,                              /* tp_traverse */
+	0,                              /* tp_clear */
+	0,                              /* tp_richcompare */
+	0,                              /* tp_weaklistoffset */
+	0,                              /* tp_iter */
+	0,                              /* tp_iternext */
+	formMethods                     /* tp_methods */
 };
 
 struct snackWidget_s {
@@ -191,7 +253,6 @@ struct snackWidget_s {
 } ;
 
 static PyObject * widgetAddCallback(snackWidget * s, PyObject * args);
-static PyObject * widgetGetAttr(PyObject * s, char * name);
 static void widgetDestructor(PyObject * s);
 static PyObject * widgetEntrySetValue(snackWidget * s, PyObject * args);
 static PyObject * widgetLabelText(snackWidget * s, PyObject * args);
@@ -255,21 +316,43 @@ static PyMethodDef widgetMethods[] = {
     { NULL }
 };
 
+static PyMemberDef widget_members[] = {
+        { "key" , T_INT, offsetof(snackWidget, co), 0, NULL },
+        { "entryValue", T_STRING, offsetof(snackWidget, apointer), 0, NULL },
+	{ NULL }
+};
+
 static PyTypeObject snackWidgetType = {
-        PyObject_HEAD_INIT(&PyType_Type)
-        0,                              /* ob_size */
+        PyVarObject_HEAD_INIT(&PyType_Type, 0)
         "snackwidget",                  /* tp_name */
         sizeof(snackWidget),            /* tp_size */
         0,                              /* tp_itemsize */
         widgetDestructor,      		/* tp_dealloc */
         0,                              /* tp_print */
-        widgetGetAttr,  		/* tp_getattr */
+        0,                   		/* tp_getattr */
         0,                              /* tp_setattr */
         0,                              /* tp_compare */
         0,                              /* tp_repr */
         0,                              /* tp_as_number */
         0,                              /* tp_as_sequence */
         0,                		/* tp_as_mapping */
+	0,                              /* tp_hash */
+	0,                              /* tp_call */
+	0,                              /* tp_str */
+	PyObject_GenericGetAttr,        /* tp_getattro */
+	0,                              /* tp_setattro */
+	0,                              /* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT,             /* tp_flags */
+	0,                              /* tp_doc */
+	0,                              /* tp_traverse */
+	0,                              /* tp_clear */
+	0,                              /* tp_richcompare */
+	0,                              /* tp_weaklistoffset */
+	0,                              /* tp_iter */
+	0,                              /* tp_iternext */
+	widgetMethods,                  /* tp_methods */
+	widget_members,                 /* tp_members */
+	widget_getset                   /* tp_getset */
 };
 
 static snackWidget * snackWidgetNew (void) {
@@ -859,10 +942,6 @@ static snackGrid * gridCreate(PyObject * s, PyObject * args) {
     return grid;
 }
 
-static PyObject * gridGetAttr(PyObject * s, char * name) {
-    return Py_FindMethod(gridMethods, s, name);
-}
-
 static PyObject * gridPlace(snackGrid * grid, PyObject * args) {
     int x, y;
 
@@ -886,7 +965,7 @@ static PyObject * gridSetField(snackGrid * grid, PyObject * args) {
 				&anchorFlags, &growFlags)) 
 	return NULL;
 
-    if (w->ob_type == &snackWidgetType) {
+    if (Py_TYPE(w) == &snackWidgetType) {
 	newtGridSetField(grid->grid, x, y, NEWT_GRID_COMPONENT,
 			 w->co, pLeft, pTop, pRight, pBottom, anchorFlags, 
 			 growFlags);
@@ -901,10 +980,6 @@ static PyObject * gridSetField(snackGrid * grid, PyObject * args) {
     return Py_None;
 }
 
-static PyObject * formGetAttr(PyObject * s, char * name) {
-    return Py_FindMethod(formMethods, s, name);
-}
-
 static PyObject * formDraw(snackForm * s, PyObject * args) {
     newtDrawForm(s->fo);
 
@@ -996,20 +1071,18 @@ static PyObject * formSetCurrent(snackForm * form, PyObject * args) {
     return Py_None;
 }
 
-static PyObject * widgetGetAttr(PyObject * s, char * name) {
-    snackWidget * w = (snackWidget *) s;
+static PyObject * widget_get_checkboxValue(PyObject *self, void *closure)
+{
+	snackWidget *w = (snackWidget *)self;
 
-    if (!strcmp(name, "key")) {
-	return Py_BuildValue("i", w->co);
-    } else if (!strcmp(name, "entryValue")) {
-	return Py_BuildValue("s", w->apointer);
-    } else if (!strcmp(name, "checkboxValue")) {
 	return Py_BuildValue("i", w->achar == ' ' ? 0 : 1);
-    } else if (!strcmp(name, "radioValue")) {
-	return Py_BuildValue("i", newtRadioGetCurrent(w->co));
-    }
+}
+
+static PyObject * widget_get_radioValue(PyObject *self, void *closure)
+{
+	snackWidget *w = (snackWidget *)self;
 
-    return Py_FindMethod(widgetMethods, s, name);
+	return Py_BuildValue("i", newtRadioGetCurrent(w->co));
 }
 
 static void widgetDestructor(PyObject * o) {
@@ -1351,10 +1424,19 @@ static void setitemstring_decref(PyObject * dict,
     Py_DECREF(o);
 }
 
-void init_snack(void) {
+MOD_INIT(_snack)
+{
     PyObject * d, * m;
 
+#if PY_MAJOR_VERSION >= 3
+    m = PyModule_Create(&moduledef);
+#else
     m = Py_InitModule("_snack", snackModuleMethods);
+#endif
+
+    if (! m)
+	    return MOD_ERROR_VAL;
+
     d = PyModule_GetDict(m);
 
     setitemstring_decref(d, "ANCHOR_LEFT", PyInt_FromLong(NEWT_ANCHOR_LEFT));
@@ -1431,4 +1513,6 @@ void init_snack(void) {
     setitemstring_decref(d, "COLORSET_COMPACTBUTTON", PyInt_FromLong(NEWT_COLORSET_COMPACTBUTTON));
     setitemstring_decref(d, "COLORSET_ACTSELLISTBOX", PyInt_FromLong(NEWT_COLORSET_ACTSELLISTBOX));
     setitemstring_decref(d, "COLORSET_SELLISTBOX", PyInt_FromLong(NEWT_COLORSET_SELLISTBOX));
+
+    return MOD_SUCCESS_VAL(m);
 }
