From 03eca9df5082e97f3b157ce7d1d86ef76016e52b Mon Sep 17 00:00:00 2001
From: Jonathan Scruggs <j.scruggs@gmail.com>
Date: Thu, 28 Sep 2017 16:00:16 +0100
Subject: [PATCH 3/3] oiio/RB-1.6: Repair breaks after boost python 1.65
 changes (#1753)

Alas, the new Boost 1.65 moves some boost python material from one
namespace to another in a way that breaks compatibility related to
support for numpy arrays. This breaks the build, including all of
our MacOS-based TravisCI tests, which of course pick up the latest
Boost via Homebrew.

Backported from:
https://github.com/OpenImageIO/oiio/commit/57f294df7430a860c60612c28235730fd429ea0d
---
 src/python/py_imagebuf.cpp    | 22 +++++++++++++++-------
 src/python/py_imageoutput.cpp | 10 +++++-----
 src/python/py_oiio.cpp        | 22 +++++++++++++++++++---
 src/python/py_oiio.h          | 23 +++++++----------------
 4 files changed, 46 insertions(+), 31 deletions(-)

diff --git a/src/python/py_imagebuf.cpp b/src/python/py_imagebuf.cpp
index 28a8c537..fa271fe2 100644
--- a/src/python/py_imagebuf.cpp
+++ b/src/python/py_imagebuf.cpp
@@ -329,7 +329,7 @@ BOOST_PYTHON_FUNCTION_OVERLOADS(ImageBuf_get_pixels_bt_overloads,
 
 
 bool
-ImageBuf_set_pixels_tuple (ImageBuf &buf, ROI roi, tuple data)
+ImageBuf_set_pixels_tuple (ImageBuf &buf, ROI roi, const tuple& data)
 {
     if (! roi.defined())
         roi = buf.roi();
@@ -347,8 +347,13 @@ ImageBuf_set_pixels_tuple (ImageBuf &buf, ROI roi, tuple data)
 
 
 bool
-ImageBuf_set_pixels_array (ImageBuf &buf, ROI roi, numeric::array data)
+ImageBuf_set_pixels_array (ImageBuf &buf, ROI roi, const object& data)
 {
+    // If it's a tuple, we handle that with the other function
+    extract<tuple> tup (data);
+    if (tup.check())
+        return ImageBuf_set_pixels_tuple (buf, roi, tup());
+
     if (! roi.defined())
         roi = buf.roi();
     roi.chend = std::min (roi.chend, buf.nchannels()+1);
@@ -356,13 +361,16 @@ ImageBuf_set_pixels_array (ImageBuf &buf, ROI roi, numeric::array data)
     if (size == 0)
         return true;   // done
 
-    TypeDesc type;
-    size_t pylen = 0;
-    const void *addr = python_array_address (data, type, pylen);
-    if (!addr || size > pylen)
+    TypeDesc elementtype;
+    size_t numelements;
+    const void* addr = python_array_address (data, elementtype, numelements);
+    if (!addr || size > numelements)
         return false;   // Not enough data to fill our ROI
 
-    buf.set_pixels (roi, type, addr);
+    std::vector<float> vals (numelements);
+    convert_types (elementtype, addr, TypeDesc::TypeFloat, vals.data(),
+                   int(numelements));
+    buf.set_pixels (roi, TypeDesc::TypeFloat, &vals[0]);
     return true;
 }
 
diff --git a/src/python/py_imageoutput.cpp b/src/python/py_imageoutput.cpp
index 1c2e5f3c..2203aac4 100644
--- a/src/python/py_imageoutput.cpp
+++ b/src/python/py_imageoutput.cpp
@@ -112,7 +112,7 @@ ImageOutputWrap::make_read_buffer (object &buffer, imagesize_t size)
 
 
 bool
-ImageOutputWrap::write_scanline_array (int y, int z, numeric::array &buffer)
+ImageOutputWrap::write_scanline_array (int y, int z, object &buffer)
 {
     TypeDesc format;
     size_t numelements = 0;
@@ -154,7 +154,7 @@ ImageOutputWrap::write_scanline_bt (int y, int z, TypeDesc::BASETYPE format,
 
 bool
 ImageOutputWrap::write_scanlines_array (int ybegin, int yend, int z,
-                                        numeric::array &buffer)
+                                        object &buffer)
 {
     TypeDesc format;
     size_t numelements = 0;
@@ -199,7 +199,7 @@ ImageOutputWrap::write_scanlines_bt (int ybegin, int yend, int z,
 
 bool
 ImageOutputWrap::write_tile_array (int x, int y, int z,
-                                   numeric::array &buffer)
+                                   object &buffer)
 {
     TypeDesc format;
     size_t numelements = 0;
@@ -243,7 +243,7 @@ ImageOutputWrap::write_tile_bt (int x, int y, int z, TypeDesc::BASETYPE format,
 bool
 ImageOutputWrap::write_tiles_array (int xbegin, int xend, int ybegin, int yend,
                                     int zbegin, int zend,
-                                    numeric::array &buffer)
+                                    object &buffer)
 {
     TypeDesc format;
     size_t numelements = 0;
@@ -290,7 +290,7 @@ ImageOutputWrap::write_tiles_bt (int xbegin, int xend, int ybegin, int yend,
 
 
 bool
-ImageOutputWrap::write_image_array (numeric::array &buffer)
+ImageOutputWrap::write_image_array (object &buffer)
 {
     TypeDesc format;
     size_t numelements = 0;
diff --git a/src/python/py_oiio.cpp b/src/python/py_oiio.cpp
index bc10803c..5e965089 100644
--- a/src/python/py_oiio.cpp
+++ b/src/python/py_oiio.cpp
@@ -78,6 +78,13 @@ typedesc_from_python_array_code (char code)
 }
 
 
+std::string
+object_classname (const object& obj)
+{
+    return extract<std::string>(obj.attr("__class__").attr("__name__"));
+}
+
+
 
 object
 C_array_to_Python_array (const char *data, TypeDesc type, size_t size)
@@ -313,11 +320,18 @@ oiio_get_string_attribute_d (const char *name, const char *defaultval)
 
 
 const void *
-python_array_address (numeric::array &data, TypeDesc &elementtype,
+python_array_address (const object &data, TypeDesc &elementtype,
                       size_t &numelements)
 {
     // Figure out the type of the array
-    object tcobj = data.attr("typecode");
+    object tcobj;
+    try {
+        tcobj = data.attr("typecode");
+    } catch(...) {
+        return NULL;
+    }
+    if (! tcobj)
+        return NULL;
     extract<char> tce (tcobj);
     char typecode = tce.check() ? (char)tce : 0;
     elementtype = typedesc_from_python_array_code (typecode);
@@ -395,7 +409,9 @@ OIIO_DECLARE_PYMODULE(OIIO_PYMODULE_NAME) {
     scope().attr("VERSION_PATCH") = OIIO_VERSION_PATCH;
     scope().attr("INTRO_STRING") = OIIO_INTRO_STRING;
 
-    boost::python::numeric::array::set_module_and_type("array", "array");
+    #if BOOST_VERSION < 106500
+        boost::python::numeric::array::set_module_and_type("array", "array");
+    #endif
 }
 
 } // namespace PyOpenImageIO
diff --git a/src/python/py_oiio.h b/src/python/py_oiio.h
index febe2f9e..9fc04d06 100644
--- a/src/python/py_oiio.h
+++ b/src/python/py_oiio.h
@@ -68,12 +68,13 @@ bool PyProgressCallback(void*, float);
 object C_array_to_Python_array (const char *data, TypeDesc type, size_t size);
 const char * python_array_code (TypeDesc format);
 TypeDesc typedesc_from_python_array_code (char code);
+std::string object_classname (const object& obj);
 
 
 // Given python array 'data', figure out its element type and number of
 // elements, and return the memory address of its contents.  Return NULL as
 // the address for an error.
-const void * python_array_address (numeric::array &data, TypeDesc &elementtype,
+const void * python_array_address (const object &data, TypeDesc &elementtype,
                                    size_t &numelements);
 
 
@@ -105,16 +106,6 @@ void py_to_stdvector (std::vector<T> &vals, const tuple &tup)
 
 
 
-// Suck up a tuple of presumed T values into a vector<T>
-template<typename T>
-void py_to_stdvector (std::vector<T> &vals, const numeric::array &arr)
-{
-    for (int i = 0, e = len(arr); i < e; ++i)
-        vals.push_back (extract<T>(arr[i]));
-}
-
-
-
 // Convert an array of T values into either tuple. FUNC is a conversion
 // function such as PyInt_FromLong, PyFloat_FromDouble, or
 // PyString_FromString.
@@ -312,12 +303,12 @@ public:
                          stride_t xstride=AutoStride);
     bool write_scanline_bt (int, int, TypeDesc::BASETYPE,
                             boost::python::object&, stride_t xstride=AutoStride);
-    bool write_scanline_array (int, int, numeric::array&);
+    bool write_scanline_array (int, int, object&);
     bool write_scanlines (int, int, int, TypeDesc, boost::python::object&,
                          stride_t xstride=AutoStride);
     bool write_scanlines_bt (int, int, int, TypeDesc::BASETYPE,
                             boost::python::object&, stride_t xstride=AutoStride);
-    bool write_scanlines_array (int, int, int, numeric::array&);
+    bool write_scanlines_array (int, int, int, object&);
     bool write_tile (int, int, int, TypeDesc, boost::python::object&,
                      stride_t xstride=AutoStride, stride_t ystride=AutoStride,
                      stride_t zstride=AutoStride);
@@ -325,7 +316,7 @@ public:
                         boost::python::object&, stride_t xstride=AutoStride,
                         stride_t ystride=AutoStride,
                         stride_t zstride=AutoStride);
-    bool write_tile_array (int, int, int, numeric::array&);
+    bool write_tile_array (int, int, int, object&);
     bool write_tiles (int, int, int, int, int, int,
                       TypeDesc, boost::python::object&,
                       stride_t xstride=AutoStride, stride_t ystride=AutoStride,
@@ -335,7 +326,7 @@ public:
                          stride_t xstride=AutoStride,
                          stride_t ystride=AutoStride,
                          stride_t zstride=AutoStride);
-    bool write_tiles_array (int, int, int, int, int, int, numeric::array&);
+    bool write_tiles_array (int, int, int, int, int, int, object&);
     bool write_image (TypeDesc format, object &buffer,
                       stride_t xstride=AutoStride,
                       stride_t ystride=AutoStride,
@@ -344,7 +335,7 @@ public:
                          stride_t xstride=AutoStride,
                          stride_t ystride=AutoStride,
                          stride_t zstride=AutoStride);
-    bool write_image_array (numeric::array &buffer);
+    bool write_image_array (object &buffer);
     bool write_deep_scanlines (int ybegin, int yend, int z,
                                const DeepData &deepdata);
     bool write_deep_tiles (int xbegin, int xend, int ybegin, int yend,
-- 
2.14.2

