Notes on making the transition to python 3.x
============================================

PyTypeObject
------------

The PyTypeObject of py3k is binary compatible with the py2k version and the
old initializers should work. However, there are several considerations to
keep in mind.

1) Because the first three slots are now part of a struct some compilers issue
warnings if they are initialized in the old way.

2) The compare slot has been made reserved in order to preserve binary
compatibily while the tp_compare function went away. The tp_richcompare
function has replaced it and we need to use that slot instead. This will
likely require modifications in the searchsorted functions and generic sorts
that currently use the compare function.

3) The previous numpy practice of initializing the COUNT_ALLOCS slots was
bogus. They are not supposed to be explicitly initialized and were out of
place in any case because an extra base slot was added in python 2.6.

Because of these facts it was thought better to use #ifdefs to bring the old
initializers up to py3k snuff rather than just fill the tp_richcompare slot.
They also serve to mark the places where changes have been made. The new form
is shown below. Note that explicit initialization can stop once none of the
remaining entries are non-zero, because zero is the default value that
variables with non-local linkage receive.


NPY_NO_EXPORT PyTypeObject Foo_Type = {
#if defined(NPY_PY3K)
    PyVarObject_HEAD_INIT(0,0)
#else
    PyObject_HEAD_INIT(0)
    0,                                          /* ob_size */
#endif
    "numpy.foo"                                 /* tp_name */
    0,                                          /* tp_basicsize */
    0,                                          /* tp_itemsize */
    /* methods */
    0,                                          /* tp_dealloc */
    0,                                          /* tp_print */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
#if defined(NPY_PY3K)
    (void *)0,                                  /* tp_reserved */
#else
    0,                                          /* tp_compare */
#endif
    0,                                          /* tp_repr */
    0,                                          /* tp_as_number */
    0,                                          /* tp_as_sequence */
    0,                                          /* tp_as_mapping */
    0,                                          /* tp_hash */
    0,                                          /* tp_call */
    0,                                          /* tp_str */
    0,                                          /* tp_getattro */
    0,                                          /* tp_setattro */
    0,                                          /* tp_as_buffer */
    0,                                          /* tp_flags */
    0,                                          /* tp_doc */
    0,                                          /* tp_traverse */
    0,                                          /* tp_clear */
    0,                                          /* tp_richcompare */
    0,                                          /* tp_weaklistoffset */
    0,                                          /* tp_iter */
    0,                                          /* tp_iternext */
    0,                                          /* tp_methods */
    0,                                          /* tp_members */
    0,                                          /* tp_getset */
    0,                                          /* tp_base */
    0,                                          /* tp_dict */
    0,                                          /* tp_descr_get */
    0,                                          /* tp_descr_set */
    0,                                          /* tp_dictoffset */
    0,                                          /* tp_init */
    0,                                          /* tp_alloc */
    0,                                          /* tp_new */
    0,                                          /* tp_free */
    0,                                          /* tp_is_gc */
    0,                                          /* tp_bases */
    0,                                          /* tp_mro */
    0,                                          /* tp_cache */
    0,                                          /* tp_subclasses */
    0,                                          /* tp_weaklist */
    0,                                          /* tp_del */
    0                                           /* tp_version_tag (2.6) */
};

checklist of types having tp_compare but no tp_richcompare

1) multiarray/flagsobject.c

PyNumberMethods
---------------

Types with tp_as_number defined

1) multiarray/arrayobject.c

The PyNumberMethods struct has changed enough that it looks easiest to just
have an alternate version. Note that np_divide, np_long, np_oct, np_hex, and
np_inplace_divide have gone away. The slot np_int is what np_long used to be,
tp_divide is now tp_floor_divide, and np_inplace_divide is now
np_inplace_floor_divide. We will also have to make sure the *_true_divide
variants are defined. This should also be done for python < 3.x, but that
introduces a requirement for the Py_TPFLAGS_HAVE_CLASS in the type flag.

/*
 * Number implementations must check *both* arguments for proper type and
 * implement the necessary conversions in the slot functions themselves.
*/
PyNumberMethods foo_number_methods = {
    (binaryfunc)0,                              /* nb_add */
    (binaryfunc)0,                              /* nb_subtract */
    (binaryfunc)0,                              /* nb_multiply */
    (binaryfunc)0,                              /* nb_remainder */
    (binaryfunc)0,                              /* nb_divmod */
    (ternaryfunc)0,                             /* nb_power */
    (unaryfunc)0,                               /* nb_negative */
    (unaryfunc)0,                               /* nb_positive */
    (unaryfunc)0,                               /* nb_absolute */
    (inquiry)0,                                 /* nb_bool, nee nb_nonzero */
    (unaryfunc)0,                               /* nb_invert */
    (binaryfunc)0,                              /* nb_lshift */
    (binaryfunc)0,                              /* nb_rshift */
    (binaryfunc)0,                              /* nb_and */
    (binaryfunc)0,                              /* nb_xor */
    (binaryfunc)0,                              /* nb_or */
    (unaryfunc)0,                               /* nb_int */
    (void *)0,                                  /* nb_reserved, nee nb_long */
    (unaryfunc)0,                               /* nb_float */
    (binaryfunc)0,                              /* nb_inplace_add */
    (binaryfunc)0,                              /* nb_inplace_subtract */
    (binaryfunc)0,                              /* nb_inplace_multiply */
    (binaryfunc)0,                              /* nb_inplace_remainder */
    (ternaryfunc)0,                             /* nb_inplace_power */
    (binaryfunc)0,                              /* nb_inplace_lshift */
    (binaryfunc)0,                              /* nb_inplace_rshift */
    (binaryfunc)0,                              /* nb_inplace_and */
    (binaryfunc)0,                              /* nb_inplace_xor */
    (binaryfunc)0,                              /* nb_inplace_or */
    (binaryfunc)0,                              /* nb_floor_divide */
    (binaryfunc)0,                              /* nb_true_divide */
    (binaryfunc)0,                              /* nb_inplace_floor_divide */
    (binaryfunc)0,                              /* nb_inplace_true_divide */
    (unaryfunc)0                                /* nb_index */
};

PySequenceMethods
-----------------

Types with tp_as_sequence defined

1) multiarray/descriptor.c
2) multiarray/scalartypes.c.src
3) multiarray/arrayobject.c

PySequenceMethods in py3k are binary compatible with py2k, but some of the
slots have gone away. I suspect this means some functions need redefining so
the semantics of the slots needs to be checked.

PySequenceMethods foo_sequence_methods = {
    (lenfunc)0,                                 /* sq_length */
    (binaryfunc)0,                              /* sq_concat */
    (ssizeargfunc)0,                            /* sq_repeat */
    (ssizeargfunc)0,                            /* sq_item */
    (void *)0,                                  /* nee sq_slice */
    (ssizeobjargproc)0,                         /* sq_ass_item */
    (void *)0,                                  /* nee sq_ass_slice */
    (objobjproc)0,                              /* sq_contains */
    (binaryfunc)0,                              /* sq_inplace_concat */
    (ssizeargfunc)0                             /* sq_inplace_repeat */
};

PyMappingMethods
----------------

Types with tp_as_mapping defined

1) multiarray/descriptor.c
2) multiarray/iterators.c
3) multiarray/scalartypes.c.src
4) multiarray/flagsobject.c
5) multiarray/arrayobject.c

PyMappingMethods in py3k look to be the same as in py2k. The semantics
of the slots needs to be checked.

PyMappingMethods foo_mapping_methods = {
	(lenfunc)0,                             /* mp_length */
	(binaryfunc)0,                          /* mp_subscript */
	(objobjargproc)0                        /* mp_ass_subscript */
};

