support for ancient Python versions (2.7.x)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7179616..2e80bd0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,8 +17,8 @@
 endif()
 
 set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6)
-find_package(PythonLibs 3 REQUIRED)
-find_package(PythonInterp 3 REQUIRED)
+find_package(PythonLibs REQUIRED)
+find_package(PythonInterp REQUIRED)
 
 string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE)
 if (UNIX)
diff --git a/README.md b/README.md
index 36e8158..ead5b37 100644
--- a/README.md
+++ b/README.md
@@ -19,10 +19,10 @@
 
 Think of this library as a tiny self-contained version of Boost.Python with
 everything stripped away that isn't relevant for binding generation. The whole
-codebase requires just over 2000 lines of code and only depends on Python and
-the C++ standard library. This compact implementation was possible thanks to
-some of the new C++11 language features (tuples, lambda functions and variadic
-templates), and by only targeting Python 3.x and higher.
+codebase requires less than 3000 lines of code and only depends on Python (2.7
+or 3.x) and the C++ standard library. This compact implementation was possible
+thanks to some of the new C++11 language features (tuples, lambda functions and
+variadic templates).
 
 ## Core features
 The following core C++ features can be mapped to Python
diff --git a/example/example1.py b/example/example1.py
index 30cda8d..f89b662 100755
--- a/example/example1.py
+++ b/example/example1.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
 import sys
 sys.path.append('.')
 
diff --git a/example/example10.py b/example/example10.py
index 401c5cc..96cf9b0 100755
--- a/example/example10.py
+++ b/example/example10.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
 import sys
 sys.path.append('.')
 
diff --git a/example/example11.py b/example/example11.py
index 733f6de..7fc1b48 100755
--- a/example/example11.py
+++ b/example/example11.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
 import sys, pydoc
 sys.path.append('.')
 
diff --git a/example/example2.py b/example/example2.py
index b0f4707..2782da5 100755
--- a/example/example2.py
+++ b/example/example2.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
 import sys, pydoc
 sys.path.append('.')
 
diff --git a/example/example3.py b/example/example3.py
index a889320..41cf314 100755
--- a/example/example3.py
+++ b/example/example3.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
 import sys
 sys.path.append('.')
 
diff --git a/example/example4.py b/example/example4.py
index aa2a448..a926c14 100755
--- a/example/example4.py
+++ b/example/example4.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
 import sys
 sys.path.append('.')
 
diff --git a/example/example5.py b/example/example5.py
index 7e0dfd0..4e75e17 100755
--- a/example/example5.py
+++ b/example/example5.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
 import sys
 sys.path.append('.')
 
diff --git a/example/example6.py b/example/example6.py
index 7dbadc4..5a014dd 100755
--- a/example/example6.py
+++ b/example/example6.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
 import sys
 sys.path.append('.')
 
diff --git a/example/example7.py b/example/example7.py
index 565ceac..3bfddb0 100755
--- a/example/example7.py
+++ b/example/example7.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
 import sys
 sys.path.append('.')
 
diff --git a/example/example8.py b/example/example8.py
index 9c295d2..e918a77 100755
--- a/example/example8.py
+++ b/example/example8.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
 import sys
 sys.path.append('.')
 
diff --git a/example/example9.py b/example/example9.py
index d8c654e..9a29353 100755
--- a/example/example9.py
+++ b/example/example9.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
+from __future__ import print_function
 import sys
 sys.path.append('.')
 
diff --git a/include/pybind/cast.h b/include/pybind/cast.h
index a46f9fb..2feaf84 100644
--- a/include/pybind/cast.h
+++ b/include/pybind/cast.h
@@ -25,7 +25,7 @@
 #endif
 
 /** Linked list descriptor type for function signatures (produces smaller binaries
- * compared to a previous solution using std::string and operator +=) */
+    compared to a previous solution using std::string and operator +=) */
 class descr {
 public:
     struct entry {
@@ -241,18 +241,42 @@
         PYBIND_TYPE_CASTER(type, #type); \
     };
 
+#if PY_MAJOR_VERSION >= 3
+#define PyLong_AsUnsignedLongLong_Fixed PyLong_AsUnsignedLongLong
+#define PyLong_AsLongLong_Fixed PyLong_AsLongLong
+#else
+inline PY_LONG_LONG PyLong_AsLongLong_Fixed(PyObject *o) {
+    if (PyInt_Check(o))
+        return (PY_LONG_LONG) PyLong_AsLong(o);
+    else
+        return ::PyLong_AsLongLong(o);
+}
+
+inline unsigned PY_LONG_LONG PyLong_AsUnsignedLongLong_Fixed(PyObject *o) {
+    if (PyInt_Check(o))
+        return (unsigned PY_LONG_LONG) PyLong_AsUnsignedLong(o);
+    else
+        return ::PyLong_AsUnsignedLongLong(o);
+}
+#endif
+
 PYBIND_TYPE_CASTER_NUMBER(int8_t, long, PyLong_AsLong, PyLong_FromLong)
 PYBIND_TYPE_CASTER_NUMBER(uint8_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong)
 PYBIND_TYPE_CASTER_NUMBER(int16_t, long, PyLong_AsLong, PyLong_FromLong)
 PYBIND_TYPE_CASTER_NUMBER(uint16_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong)
 PYBIND_TYPE_CASTER_NUMBER(int32_t, long, PyLong_AsLong, PyLong_FromLong)
 PYBIND_TYPE_CASTER_NUMBER(uint32_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong)
-PYBIND_TYPE_CASTER_NUMBER(int64_t, PY_LONG_LONG, PyLong_AsLongLong, PyLong_FromLongLong)
-PYBIND_TYPE_CASTER_NUMBER(uint64_t, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong, PyLong_FromUnsignedLongLong)
+PYBIND_TYPE_CASTER_NUMBER(int64_t, PY_LONG_LONG, PyLong_AsLongLong_Fixed, PyLong_FromLongLong)
+PYBIND_TYPE_CASTER_NUMBER(uint64_t, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong_Fixed, PyLong_FromUnsignedLongLong)
 
 #if defined(__APPLE__) // size_t/ssize_t are separate types on Mac OS X
+#if PY_MAJOR_VERSION >= 3
 PYBIND_TYPE_CASTER_NUMBER(ssize_t, Py_ssize_t, PyLong_AsSsize_t, PyLong_FromSsize_t)
 PYBIND_TYPE_CASTER_NUMBER(size_t, size_t, PyLong_AsSize_t, PyLong_FromSize_t)
+#else
+PYBIND_TYPE_CASTER_NUMBER(ssize_t, PY_LONG_LONG, PyLong_AsLongLong_Fixed, PyLong_FromLongLong)
+PYBIND_TYPE_CASTER_NUMBER(size_t, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong_Fixed, PyLong_FromUnsignedLongLong)
+#endif
 #endif
 
 PYBIND_TYPE_CASTER_NUMBER(float, double, PyFloat_AsDouble, PyFloat_FromDouble)
@@ -286,7 +310,19 @@
 template <> class type_caster<std::string> {
 public:
     bool load(PyObject *src, bool) {
+#if PY_MAJOR_VERSION >= 3
         const char *ptr = PyUnicode_AsUTF8(src);
+#else
+        const char *ptr = nullptr;
+        object temp;
+        if (PyString_Check(src)) {
+            ptr = PyString_AsString(src);
+        } else {
+            temp = object(PyUnicode_AsUTF8String(src), false);
+            if (temp.ptr() != nullptr)
+                ptr = PyString_AsString(temp.ptr());
+        }
+#endif
         if (!ptr) { PyErr_Clear(); return false; }
         value = std::string(ptr);
         return true;
@@ -301,13 +337,25 @@
 template <> class type_caster<std::wstring> {
 public:
     bool load(PyObject *src, bool) {
+#if PY_MAJOR_VERSION >= 3
         const wchar_t *ptr = PyUnicode_AsWideCharString(src, nullptr);
+#else
+        object temp(PyUnicode_AsUTF16String(src), false);
+        if (temp.ptr() == nullptr)
+            return false;
+        const wchar_t *ptr = (wchar_t*) PyString_AsString(temp.ptr());
+#endif
+
         if (!ptr) { PyErr_Clear(); return false; }
         value = std::wstring(ptr);
         return true;
     }
     static PyObject *cast(const std::wstring &src, return_value_policy /* policy */, PyObject * /* parent */) {
+#if PY_MAJOR_VERSION >= 3
         return PyUnicode_FromWideChar(src.c_str(), src.length());
+#else
+        return PyUnicode_DecodeUTF16((const char *) src.c_str(), src.length() * 2, "strict", nullptr);
+#endif
     }
     PYBIND_TYPE_CASTER(std::wstring, "wstr");
 };
@@ -316,7 +364,14 @@
 template <> class type_caster<char> {
 public:
     bool load(PyObject *src, bool) {
+#if PY_MAJOR_VERSION >= 3
         char *ptr = PyUnicode_AsUTF8(src);
+#else
+        temp = object(PyUnicode_AsLatin1String(src), false);
+        if (temp.ptr() == nullptr)
+            return false;
+        char *ptr = PyString_AsString(temp.ptr());
+#endif
         if (!ptr) { PyErr_Clear(); return false; }
         value = ptr;
         return true;
@@ -337,6 +392,9 @@
     operator char() { return *value; }
 protected:
     char *value;
+#if PY_MAJOR_VERSION < 3
+    object temp;
+#endif
 };
 
 template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
diff --git a/include/pybind/common.h b/include/pybind/common.h
index 8a9850d..d327ab6 100644
--- a/include/pybind/common.h
+++ b/include/pybind/common.h
@@ -24,9 +24,6 @@
 #endif
 #endif
 
-#define PYTHON_PLUGIN(name) \
-    extern "C" PYTHON_EXPORT PyObject *PyInit_##name()
-
 #include <vector>
 #include <string>
 #include <stdexcept>
@@ -37,7 +34,7 @@
 #if defined(_MSC_VER)
 #define HAVE_ROUND
 #pragma warning(push)
-#pragma warning(disable: 4510 4610 4512)
+#pragma warning(disable: 4510 4610 4512 4005)
 #if _DEBUG
 #define _DEBUG_MARKER
 #undef _DEBUG
@@ -61,6 +58,14 @@
 #pragma warning(pop)
 #endif
 
+#if PY_MAJOR_VERSION >= 3
+#define PYTHON_PLUGIN(name) \
+    extern "C" PYTHON_EXPORT PyObject *PyInit_##name()
+#else
+#define PYTHON_PLUGIN(name) \
+    extern "C" PYTHON_EXPORT PyObject *init##name()
+#endif
+
 NAMESPACE_BEGIN(pybind)
 
 typedef Py_ssize_t ssize_t;
diff --git a/include/pybind/numpy.h b/include/pybind/numpy.h
index d101013..3042800 100644
--- a/include/pybind/numpy.h
+++ b/include/pybind/numpy.h
@@ -47,7 +47,11 @@
         static API lookup() {
             PyObject *numpy = PyImport_ImportModule("numpy.core.multiarray");
             PyObject *capsule = numpy ? PyObject_GetAttrString(numpy, "_ARRAY_API") : nullptr;
+#if PY_MAJOR_VERSION >= 3
             void **api_ptr = (void **) (capsule ? PyCapsule_GetPointer(capsule, NULL) : nullptr);
+#else
+            void **api_ptr = (void **) (capsule ? PyCObject_AsVoidPtr(capsule) : nullptr);
+#endif
             Py_XDECREF(capsule);
             Py_XDECREF(numpy);
             if (api_ptr == nullptr)
diff --git a/include/pybind/operators.h b/include/pybind/operators.h
index e0f858f..84fc4c2 100644
--- a/include/pybind/operators.h
+++ b/include/pybind/operators.h
@@ -103,7 +103,11 @@
 PYBIND_BINARY_OPERATOR(sub,       rsub,         operator-,    l - r)
 PYBIND_BINARY_OPERATOR(add,       radd,         operator+,    l + r)
 PYBIND_BINARY_OPERATOR(mul,       rmul,         operator*,    l * r)
+#if PY_MAJOR_VERSION >= 3
 PYBIND_BINARY_OPERATOR(truediv,   rtruediv,     operator/,    l / r)
+#else
+PYBIND_BINARY_OPERATOR(div,       rdiv,         operator/,    l / r)
+#endif
 PYBIND_BINARY_OPERATOR(mod,       rmod,         operator%,    l % r)
 PYBIND_BINARY_OPERATOR(lshift,    rlshift,      operator<<,   l << r)
 PYBIND_BINARY_OPERATOR(rshift,    rrshift,      operator>>,   l >> r)
diff --git a/include/pybind/pybind.h b/include/pybind/pybind.h
index fa2cffd..45ce9e4 100644
--- a/include/pybind/pybind.h
+++ b/include/pybind/pybind.h
@@ -45,7 +45,14 @@
 template <typename T> inline arg_t<T> arg::operator=(const T &value) { return arg_t<T>(name, value); }
 
 /// Annotation for methods
-struct is_method { };
+struct is_method {
+#if PY_MAJOR_VERSION < 3
+    PyObject *class_;
+    is_method(object *o) : class_(o->ptr()) { }
+#else
+    is_method(object *) { }
+#endif
+};
 
 /// Annotation for documentation
 struct doc { const char *value; doc(const char *value) : value(value) { } };
@@ -69,11 +76,16 @@
         short keywords = 0;
         return_value_policy policy = return_value_policy::automatic;
         std::string signature;
+#if PY_MAJOR_VERSION < 3
+        PyObject *class_ = nullptr;
+#endif
         PyObject *sibling = nullptr;
         const char *doc = nullptr;
         function_entry *next = nullptr;
     };
 
+    function_entry *m_entry;
+
     /// Picks a suitable return value converter from cast.h
     template <typename T> using return_value_caster =
         detail::type_caster<typename std::conditional<
@@ -122,7 +134,14 @@
         def[entry->keywords++] = strdup(std::to_string(a.value).c_str());
     }
 
-    static void process_extra(const pybind::is_method &, function_entry *entry, const char **, const char **) { entry->is_method = true; }
+    static void process_extra(const pybind::is_method &m, function_entry *entry, const char **, const char **) {
+        entry->is_method = true;
+#if PY_MAJOR_VERSION < 3
+        entry->class_ = m.class_;
+#else
+        (void) m;
+#endif
+    }
     static void process_extra(const pybind::return_value_policy p, function_entry *entry, const char **, const char **) { entry->policy = p; }
     static void process_extra(pybind::sibling s, function_entry *entry, const char **, const char **) { entry->sibling = s.value; }
 
@@ -170,13 +189,13 @@
             std::tuple<Extra...> extras;
         };
 
-        function_entry *entry = new function_entry();
-        entry->data = new capture { f, std::tuple<Extra...>(std::forward<Extra>(extra)...) };
+        m_entry = new function_entry();
+        m_entry->data = new capture { f, std::tuple<Extra...>(std::forward<Extra>(extra)...) };
 
         typedef arg_value_caster<Arg...> cast_in;
         typedef return_value_caster<Return> cast_out;
 
-        entry->impl = [](function_entry *entry, PyObject *pyArgs, PyObject *kwargs, PyObject *parent) -> PyObject * {
+        m_entry->impl = [](function_entry *entry, PyObject *pyArgs, PyObject *kwargs, PyObject *parent) -> PyObject * {
             capture *data = (capture *) entry->data;
             process_extras(data->extras, pyArgs, kwargs, entry->is_method);
             cast_in args;
@@ -187,14 +206,14 @@
 
         const int N = sizeof...(Extra) > sizeof...(Arg) ? sizeof...(Extra) : sizeof...(Arg);
         std::array<const char *, N> kw{}, def{};
-        process_extras(((capture *) entry->data)->extras, entry, kw.data(), def.data());
+        process_extras(((capture *) m_entry->data)->extras, m_entry, kw.data(), def.data());
 
 
         detail::descr d = cast_in::name(kw.data(), def.data());
         d += " -> ";
         d += std::move(cast_out::name());
 
-        initialize(entry, d, sizeof...(Arg));
+        initialize(d, sizeof...(Arg));
     }
 
     /// Delegating helper constructor to deal with lambda functions
@@ -219,6 +238,9 @@
                    (Return (*)(const Class *, Arg ...)) nullptr, std::forward<Extra>(extra)...);
     }
 
+    /// Return the function name
+    const char *name() const { return m_entry->name; }
+
 private:
     /// Functors, lambda functions, etc.
     template <typename Func, typename Return, typename... Arg, typename... Extra>
@@ -228,13 +250,13 @@
             std::tuple<Extra...> extras;
         };
 
-        function_entry *entry = new function_entry();
-        entry->data = new capture { std::forward<Func>(f), std::tuple<Extra...>(std::forward<Extra>(extra)...) };
+        m_entry = new function_entry();
+        m_entry->data = new capture { std::forward<Func>(f), std::tuple<Extra...>(std::forward<Extra>(extra)...) };
 
         typedef arg_value_caster<Arg...> cast_in;
         typedef return_value_caster<Return> cast_out;
 
-        entry->impl = [](function_entry *entry, PyObject *pyArgs, PyObject *kwargs, PyObject *parent) -> PyObject *{
+        m_entry->impl = [](function_entry *entry, PyObject *pyArgs, PyObject *kwargs, PyObject *parent) -> PyObject *{
             capture *data = (capture *)entry->data;
             process_extras(data->extras, pyArgs, kwargs, entry->is_method);
             cast_in args;
@@ -245,13 +267,13 @@
 
         const int N = sizeof...(Extra) > sizeof...(Arg) ? sizeof...(Extra) : sizeof...(Arg);
         std::array<const char *, N> kw{}, def{};
-        process_extras(((capture *) entry->data)->extras, entry, kw.data(), def.data());
+        process_extras(((capture *) m_entry->data)->extras, m_entry, kw.data(), def.data());
 
         detail::descr d = cast_in::name(kw.data(), def.data());
         d += " -> ";
         d += std::move(cast_out::name());
 
-        initialize(entry, d, sizeof...(Arg));
+        initialize(d, sizeof...(Arg));
     }
 
     static PyObject *dispatcher(PyObject *self, PyObject *args, PyObject *kwargs ) {
@@ -322,19 +344,31 @@
         }
     }
 
-    void initialize(function_entry *entry, const detail::descr &descr, int args) {
-        if (entry->name == nullptr)
-            entry->name = "";
+    void initialize(const detail::descr &descr, int args) {
+        if (m_entry->name == nullptr)
+            m_entry->name = "";
 
-        if (entry->keywords != 0 && entry->keywords != args)
+#if PY_MAJOR_VERSION < 3
+        if (strcmp(m_entry->name, "__next__") == 0)
+            m_entry->name = "next";
+#endif
+
+        if (m_entry->keywords != 0 && m_entry->keywords != args)
             throw std::runtime_error(
-                "cpp_function(): function \"" + std::string(entry->name) + "\" takes " +
-                std::to_string(args) + " arguments, but " + std::to_string(entry->keywords) +
+                "cpp_function(): function \"" + std::string(m_entry->name) + "\" takes " +
+                std::to_string(args) + " arguments, but " + std::to_string(m_entry->keywords) +
                 " pybind::arg entries were specified!");
 
-        entry->is_constructor = !strcmp(entry->name, "__init__");
-        entry->signature = descr.str();
+        m_entry->is_constructor = !strcmp(m_entry->name, "__init__");
+        m_entry->signature = descr.str();
 
+#if PY_MAJOR_VERSION < 3
+        if (m_entry->sibling && PyMethod_Check(m_entry->sibling))
+            m_entry->sibling = PyMethod_GET_FUNCTION(m_entry->sibling);
+#endif
+
+        function_entry *entry = m_entry;
+        bool overloaded = false;
         if (!entry->sibling || !PyCFunction_Check(entry->sibling)) {
             entry->def = new PyMethodDef();
             memset(entry->def, 0, sizeof(PyMethodDef));
@@ -354,13 +388,14 @@
                 parent = parent->next;
             parent->next = entry;
             entry = backup;
+            overloaded = true;
         }
 
         std::string signatures;
         int index = 0;
         function_entry *it = entry;
         while (it) { /* Create pydoc it */
-            if (it->sibling)
+            if (overloaded)
                 signatures += std::to_string(++index) + ". ";
             signatures += "Signature : " + std::string(it->signature) + "\n";
             if (it->doc && strlen(it->doc) > 0)
@@ -374,7 +409,11 @@
             std::free((char *) func->m_ml->ml_doc);
         func->m_ml->ml_doc = strdup(signatures.c_str());
         if (entry->is_method) {
+#if PY_MAJOR_VERSION >= 3
             m_ptr = PyInstanceMethod_New(m_ptr);
+#else
+            m_ptr = PyMethod_New(m_ptr, nullptr, entry->class_);
+#endif
             if (!m_ptr)
                 throw std::runtime_error("cpp_function::cpp_function(): Could not allocate instance method object");
             Py_DECREF(func);
@@ -387,6 +426,7 @@
     PYBIND_OBJECT_DEFAULT(module, object, PyModule_Check)
 
     module(const char *name, const char *doc = nullptr) {
+#if PY_MAJOR_VERSION >= 3
         PyModuleDef *def = new PyModuleDef();
         memset(def, 0, sizeof(PyModuleDef));
         def->m_name = name;
@@ -394,6 +434,9 @@
         def->m_size = -1;
         Py_INCREF(def);
         m_ptr = PyModule_Create(def);
+#else
+        m_ptr = Py_InitModule3(name, nullptr, doc);
+#endif
         if (m_ptr == nullptr)
             throw std::runtime_error("Internal error in module::module()");
         inc_ref();
@@ -430,7 +473,11 @@
                 void (*init_holder)(PyObject *), const destructor &dealloc,
                 PyObject *parent, const char *doc) {
         PyHeapTypeObject *type = (PyHeapTypeObject*) PyType_Type.tp_alloc(&PyType_Type, 0);
+#if PY_MAJOR_VERSION >= 3
         PyObject *name = PyUnicode_FromString(name_);
+#else
+        PyObject *name = PyString_FromString(name_);
+#endif
         if (type == nullptr || name == nullptr)
             throw std::runtime_error("Internal error in custom_type::custom_type()");
         Py_INCREF(name);
@@ -444,7 +491,10 @@
         if (module_name.check())
             full_name =  std::string(module_name) + "." + full_name;
 
-        type->ht_name = type->ht_qualname = name;
+        type->ht_name = name;
+#if PY_MAJOR_VERSION >= 3
+        type->ht_qualname = name;
+#endif
         type->ht_type.tp_name = strdup(full_name.c_str());
         type->ht_type.tp_basicsize = instance_size;
         type->ht_type.tp_init = (initproc) init;
@@ -453,6 +503,9 @@
         type->ht_type.tp_flags |=
             Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
         type->ht_type.tp_flags &= ~Py_TPFLAGS_HAVE_GC;
+#if PY_MAJOR_VERSION < 3
+        type->ht_type.tp_flags |= Py_TPFLAGS_CHECKTYPES;
+#endif
         type->ht_type.tp_as_number = &type->as_number;
         type->ht_type.tp_as_sequence = &type->as_sequence;
         type->ht_type.tp_as_mapping = &type->as_mapping;
@@ -482,7 +535,12 @@
     /* Allocate a metaclass on demand (for static properties) */
     handle metaclass() {
         auto &ht_type = ((PyHeapTypeObject *) m_ptr)->ht_type;
+#if PY_MAJOR_VERSION >= 3
         auto &ob_type = ht_type.ob_base.ob_base.ob_type;
+#else
+        auto &ob_type = ht_type.ob_type;
+#endif
+
         if (ob_type == &PyType_Type) {
             std::string name_ = std::string(ht_type.tp_name) + "_meta";
             PyHeapTypeObject *type = (PyHeapTypeObject*) PyType_Type.tp_alloc(&PyType_Type, 0);
@@ -490,7 +548,10 @@
             if (type == nullptr || name == nullptr)
                 throw std::runtime_error("Internal error in custom_type::metaclass()");
             Py_INCREF(name);
-            type->ht_name = type->ht_qualname = name;
+            type->ht_name = name;
+#if PY_MAJOR_VERSION >= 3
+            type->ht_qualname = name;
+#endif
             type->ht_type.tp_name = strdup(name_.c_str());
             type->ht_type.tp_base = &PyType_Type;
             type->ht_type.tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE;
@@ -541,6 +602,9 @@
             void *get_buffer_data) {
         PyHeapTypeObject *type = (PyHeapTypeObject*) m_ptr;
         type->ht_type.tp_as_buffer = &type->as_buffer;
+#if PY_MAJOR_VERSION < 3
+        type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
+#endif
         type->as_buffer.bf_getbuffer = getbuffer;
         type->as_buffer.bf_releasebuffer = releasebuffer;
         auto info = ((detail::type_info *) capsule(attr("__pybind__")));
@@ -606,17 +670,19 @@
 
     template <typename Func, typename... Extra>
     class_ &def(const char *name_, Func&& f, Extra&&... extra) {
-        attr(name_) = cpp_function(std::forward<Func>(f), name(name_),
-                                   sibling(attr(name_)), is_method(),
-                                   std::forward<Extra>(extra)...);
+        cpp_function cf(std::forward<Func>(f), name(name_),
+                        sibling(attr(name_)), is_method(this),
+                        std::forward<Extra>(extra)...);
+        attr(cf.name()) = cf;
         return *this;
     }
 
     template <typename Func, typename... Extra> class_ &
     def_static(const char *name_, Func f, Extra&&... extra) {
-        attr(name_) = cpp_function(std::forward<Func>(f), name(name_),
-                                   sibling(attr(name_)),
-                                   std::forward<Extra>(extra)...);
+        cpp_function cf(std::forward<Func>(f), name(name_),
+                        sibling(attr(name_)),
+                        std::forward<Extra>(extra)...);
+        attr(cf.name()) = cf;
         return *this;
     }
 
@@ -654,9 +720,9 @@
     class_ &def_readwrite(const char *name, D C::*pm, Extra&&... extra) {
         cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; },
                           return_value_policy::reference_internal,
-                          is_method(), extra...),
+                          is_method(this), extra...),
                      fset([pm](C &c, const D &value) { c.*pm = value; },
-                          is_method(), extra...);
+                          is_method(this), extra...);
         def_property(name, fget, fset);
         return *this;
     }
@@ -665,7 +731,7 @@
     class_ &def_readonly(const char *name, const D C::*pm, Extra&& ...extra) {
         cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; },
                           return_value_policy::reference_internal,
-                          is_method(), std::forward<Extra>(extra)...);
+                          is_method(this), std::forward<Extra>(extra)...);
         def_property_readonly(name, fget);
         return *this;
     }
diff --git a/include/pybind/pytypes.h b/include/pybind/pytypes.h
index 5aff796..e9a60e9 100644
--- a/include/pybind/pytypes.h
+++ b/include/pybind/pytypes.h
@@ -213,10 +213,30 @@
 public:
     PYBIND_OBJECT_DEFAULT(str, object, PyUnicode_Check)
     str(const char *s) : object(PyUnicode_FromString(s), false) { }
-    operator const char *() const { return PyUnicode_AsUTF8(m_ptr); }
+    operator const char *() const {
+#if PY_MAJOR_VERSION >= 3
+        return PyUnicode_AsUTF8(m_ptr);
+#else
+        m_temp = object(PyUnicode_AsUTF8String(m_ptr), false);
+        if (m_temp.ptr() == nullptr)
+            return nullptr;
+        return PyString_AsString(m_temp.ptr());
+#endif
+    }
+private:
+#if PY_MAJOR_VERSION < 3
+    mutable object m_temp;
+#endif
 };
 
-inline pybind::str handle::str() const { return pybind::str(PyObject_Str(m_ptr), false); }
+inline pybind::str handle::str() const {
+    PyObject *str = PyObject_Str(m_ptr);
+#if PY_MAJOR_VERSION < 3
+    PyObject *unicode = PyUnicode_FromEncodedObject(str, "utf-8", nullptr);
+    Py_XDECREF(str); str = unicode;
+#endif
+    return pybind::str(str, false);
+}
 
 class bool_ : public object {
 public:
@@ -252,7 +272,13 @@
         m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr());
     }
     bool compute(ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step, ssize_t *slicelength) const {
-        return PySlice_GetIndicesEx(m_ptr, length, start, stop, step, slicelength) == 0;
+        return PySlice_GetIndicesEx(
+#if PY_MAJOR_VERSION >= 3
+                m_ptr,
+#else
+                (PySliceObject *) m_ptr,
+#endif
+                length, start, stop, step, slicelength) == 0;
     }
 };
 
diff --git a/include/pybind/stl.h b/include/pybind/stl.h
index 4b935cf..bf1d898 100644
--- a/include/pybind/stl.h
+++ b/include/pybind/stl.h
@@ -100,9 +100,10 @@
     PYBIND_TYPE_CASTER(type, detail::descr("dict<") + key_conv::name() + detail::descr(", ") + value_conv::name() + detail::descr(">"));
 };
 
+NAMESPACE_END(detail)
+
 inline std::ostream &operator<<(std::ostream &os, const object &obj) { os << (const char *) obj.str(); return os; }
 
-NAMESPACE_END(detail)
 NAMESPACE_END(pybind)
 
 #if defined(_MSC_VER)