diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..5b0c3e9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,22 @@ +sudo: required +dist: trusty +language: cpp + +before_install: + - export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g") + - sudo apt-get -qq update + - sudo apt-get install -y libboost-python-dev python-numpy python3-numpy libpython3-dev python-sphinx + - sudo ln -s /usr/lib/x86_64-linux-gnu/libboost_python-py34.so /usr/lib/x86_64-linux-gnu/libboost_python3.so + +script: + - mkdir build + - cd build + - cmake -DPYTHON_EXECUTABLE=$PYTHON .. && make && make test ARGS="-V" + - cd ../libs/numpy/doc + - make html + - cd ../../../ + - if [ "$PYTHON" == "/usr/bin/python" ]; then scons; fi + +env: + - PYTHON=/usr/bin/python + - PYTHON=/usr/bin/python3 diff --git a/CMakeLists.txt b/CMakeLists.txt index 98f6a77..8e4c74e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,14 +1,26 @@ -cmake_minimum_required(VERSION 2.8.3) +cmake_minimum_required(VERSION 2.8.12) project( boost.numpy ) -set(BUILD_TEST ON CACHE BOOL "Build Boost.NumPy Tests") +set(BUILD_TESTS ON CACHE BOOL "Build Boost.NumPy Tests") set(BUILD_EXAMPLES ON CACHE BOOL "Build Boost.NumPy Examples") # put our local cmake find scripts at the beginning of the cmake # module search path set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/libs/numpy/cmake ${CMAKE_MODULE_PATH}) +IF (NOT DEFINED LIB_SUFFIX) + EXECUTE_PROCESS( + COMMAND uname -m + COMMAND tr -d '\n' + OUTPUT_VARIABLE ARCH + ) + message(STATUS "Detected architecture '" ${ARCH} "'") + IF (ARCH STREQUAL x86_64) + SET(LIB_SUFFIX 64) + ENDIF (ARCH STREQUAL x86_64) +ENDIF (NOT DEFINED LIB_SUFFIX) + # configure output folders so artifacts are built into a single set of # top-level folders rather than the default cmake build structure that # matches the source tree. @@ -23,7 +35,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin # find required python packages find_package(PythonInterp REQUIRED) -find_package(PythonLibsNew REQUIRED) +find_package(PythonLibs REQUIRED) find_package(NumPy REQUIRED) # find boost @@ -31,6 +43,8 @@ find_package(NumPy REQUIRED) # set(Boost_USE_STATIC_LIBS ON) # set(Boost_USE_MULTITHREADED ON) # set(Boost_USE_STATIC_RUNTIME ON) +set(CMAKE_MACOSX_RPATH 1) + if(${PYTHON_VERSION_STRING} GREATER 3.0) message(STATUS "Using Python3") find_package(Boost COMPONENTS python3 REQUIRED) @@ -43,7 +57,17 @@ message( STATUS "Boost Paths:") message( STATUS "Include : " ${Boost_INCLUDE_DIRS}) message( STATUS "Libraries: " ${Boost_LIBRARIES}) -# add_definitions( -DBOOST_ALL_NO_LIB ) +if(MSVC) + # With Visual Studio remove the automatic linking + # feature + add_definitions( -DBOOST_ALL_NO_LIB ) +endif() + +if(Boost_USE_STATIC_LIBS) + # if the user specified he wants to link to static libraries + # force linking to static boost python + add_definitions( -DBOOST_PYTHON_STATIC_LIB ) +endif() # In some cases, you may need to explicitly specify that a dynamic Boost is used; if so use: # add_definitions( -DBOOST_ALL_DYN_LINK ) diff --git a/README b/README deleted file mode 100644 index ac6bb86..0000000 --- a/README +++ /dev/null @@ -1,90 +0,0 @@ -Boost.NumPy is an extension for Boost.Python that adds NumPy support. - -It is intended as a replacement for the old numeric support in -Boost.Python proper, which is now out-of-date and does not support -C/C++ pointer access to the data. Because it builds against the NumPy -headers and hence has a dependency that Boost.Python does not, it is -intended to be built as a separate library. This is also not intended -to be a high-level C++ array library; it would be more accurate to -consider it a C++ NumPy API, with the intent of making the NumPy C-API -available in a form that is safer and more convenient for C++ users -(and particularly those using Boost.Python, of course). - -THIS IS NOT AN OFFICIAL BOOST LIBRARY - -...we're just calling it Boost.NumPy right now because that clearly -indicates that it's for Boost.Python and NumPy. We do intend to -propose it for inclusion in Boost eventually. - - -INSTALLATION - -We have provided three build systems: Boost.Build, SCons, and CMake -build system. At the moment, we recommend using SCons or CMake on -Linux and CMake on Windows. - -Building with SCons should be as simple as running "scons" and "scons -install", but you may need to use the "--with-boost*" options (see -"scons --help") to specify where to find Boost. The Python that is -used by SCons will be the one built against. Additionally, the -SConsChecks submodule must be initialized by git before building -by running - - git submodule update --init - -Please see libs/numpy/doc/cmakeBuild.rst for more information on -building with CMake. - - -DOCUMENTATION - -More documentation on how to use the library can be found in -libs/numpy/doc, but it may be most useful to start with the -examples in libs/numpy/examples. The headers files are also -well documented and are intended to serve as a reference. - - -ISSUES AND NEW FEATURES - -Please create an issue on the GitHub site at: - -https://github.com/ndarray/Boost.NumPy/issues - - -CONTACT - -Please send email questions to: - -ndarray-dev@googlegroups.com - -...but I would prefer bug reports and feature requests to go to -the GitHub issues list (see above). - - -MULTI-PLATFORM SUPPORT - -The vast majority of development has happened on Linux/g++, and while -we have taken some steps to support MacOS/clang, there hasn't been -much testing. There has been no testing on Windows, though we have -no reason to believe anything we've done won't work on Windows. - -In short, we'd really love to have some testing on additional platforms, -especially from people who know their way around SCons, NumPy, or -Boost.Python. - - -HISTORY/AUTHORS - -Boost.NumPy was originally written by Jim Bosch as part of the -"ndarray" C++ library, then reorganized into a standalone component, -cleaned up, and documented as part of a Boost-sponsored -Google Summer of Code by Ankit Daftery, mentored by Stefan Seefeld. -Philip Miller contributed the CMake build system. - -The project is hosted both on the Boost Sandbox: - -https://svn.boost.org/svn/boost/sandbox/numpy - -and on GitHub: - -https://github.com/ndarray/Boost.NumPy diff --git a/README.md b/README.md new file mode 100644 index 0000000..bdd00f2 --- /dev/null +++ b/README.md @@ -0,0 +1,83 @@ +# Boost.NumPy [![Build Status](https://travis-ci.org/ndarray/Boost.NumPy.svg?branch=master)](https://travis-ci.org/ndarray/Boost.NumPy) + +> # THIS PACKAGE IS NOW DEPRECATED IN FAVOR OF NUMPY SUPPORT INCLUDED DIRECTLY IN BOOST.PYTHON. +> +> NumPy support is scheduled to be included in Boost release 1.63, and is already available on +> the Boost.Python master branch (https://github.com/boostorg/python/tree/master). The interface +> is the same as Boost.Numpy, but in a different namespace. +> +> There are currently no plans for further development on this independent package. + +Boost.NumPy is an extension for Boost.Python < v1.63 that adds NumPy support. + +## INSTALLATION + +We have provided two build systems: SCons and CMake build system. +We reconmmend using CMake for all new users, and for anyone using +Python 3 (SCons itself does not support Python 3, and our SCons +build is restricted to building against the version of Python that +executes SCons. + +Please see `libs/numpy/doc/cmakeBuild.rst` for more information on +building with CMake. + +Building with SCons should be as simple as running `scons` and `scons +install`, but you may need to use the `--with-boost*` options (see +`scons --help`) to specify where to find Boost. The Python that is +used by SCons will be the one built against. Additionally, the +SConsChecks submodule must be initialized by git before building +by running + + git submodule update --init + + +## DOCUMENTATION + +More documentation on how to use the library can be found in +libs/numpy/doc, but it may be most useful to start with the +examples in libs/numpy/examples. The headers files are also +well documented and are intended to serve as a reference. + + +## ISSUES AND NEW FEATURES + +Please create an issue on the GitHub site at: + +https://github.com/ndarray/Boost.NumPy/issues + +Patches and detailed debugging are greatly appreciated; the authors don't have much time to devote to this project on a regular basis, but we do try to fix critical bugs. + + +## CONTACT + +Please post questions, bug reports, and feature requests to +the GitHub issues list (see above). + + +## MULTI-PLATFORM SUPPORT + +The vast majority of development has happened on Linux/g++, and while +we have taken some steps to support MacOS/clang, there hasn't been +much testing. There has been very little testing on Windows, though there +has been some work contributed to get it working there. + +In short, we'd really love to have some testing on additional platforms, +especially from people who know their way around SCons, NumPy, or +Boost.Python. + + +## HISTORY/AUTHORS + +Boost.NumPy was originally written by Jim Bosch as part of the +"ndarray" C++ library, then reorganized into a standalone component, +cleaned up, and documented as part of a Boost-sponsored +Google Summer of Code by Ankit Daftery, mentored by Stefan Seefeld. +Philip Miller contributed the CMake build system. + +An older version of this project is hosted on the Boost Sandbox: + +https://svn.boost.org/svn/boost/sandbox/numpy + +but the latest version is on GitHub: + +https://github.com/ndarray/Boost.NumPy diff --git a/SConsChecks b/SConsChecks index b2af1e0..fbdb46b 160000 --- a/SConsChecks +++ b/SConsChecks @@ -1 +1 @@ -Subproject commit b2af1e08ea4b887810184cef611572f11dbda8f7 +Subproject commit fbdb46be16969a7eba0afa7ac5f4639e9ae433d5 diff --git a/boost/numpy.hpp b/boost/numpy.hpp index e4fb087..df7cf64 100644 --- a/boost/numpy.hpp +++ b/boost/numpy.hpp @@ -26,11 +26,13 @@ namespace numpy { * This must be called before using anything in boost.numpy; * It should probably be the first line inside BOOST_PYTHON_MODULE. * + * This returns false and sets a Python exception on failure. + * * @internal This just calls the Numpy C-API functions "import_array()" * and "import_ufunc()", and then calls * dtype::register_scalar_converters(). */ -void initialize(bool register_scalar_converters=true); +bool initialize(bool register_scalar_converters=true); } // namespace boost::numpy } // namespace boost diff --git a/boost/numpy/ndarray.hpp b/boost/numpy/ndarray.hpp index ee5800c..a702df3 100644 --- a/boost/numpy/ndarray.hpp +++ b/boost/numpy/ndarray.hpp @@ -87,10 +87,10 @@ class ndarray : public python::object ndarray copy() const; /// @brief Return the size of the nth dimension. - int const shape(int n) const { return get_shape()[n]; } + Py_intptr_t shape(int n) const { return get_shape()[n]; } /// @brief Return the stride of the nth dimension. - int const strides(int n) const { return get_strides()[n]; } + Py_intptr_t strides(int n) const { return get_strides()[n]; } /** * @brief Return the array's raw data pointer. @@ -116,10 +116,10 @@ class ndarray : public python::object Py_intptr_t const * get_strides() const { return get_struct()->strides; } /// @brief Return the number of array dimensions. - int const get_nd() const { return get_struct()->nd; } + int get_nd() const { return get_struct()->nd; } /// @brief Return the array flags. - bitflag const get_flags() const; + bitflag get_flags() const; /// @brief Reverse the dimensions of the array. ndarray transpose() const; diff --git a/boost/numpy/ufunc.hpp b/boost/numpy/ufunc.hpp index 98ecbf4..d86fa34 100644 --- a/boost/numpy/ufunc.hpp +++ b/boost/numpy/ufunc.hpp @@ -52,13 +52,13 @@ class multi_iter : public python::object char * get_data(int n) const; /// @brief Return the number of dimensions of the broadcasted array expression. - int const get_nd() const; + int get_nd() const; /// @brief Return the shape of the broadcasted array expression as an array of integers. Py_intptr_t const * get_shape() const; /// @brief Return the shape of the broadcasted array expression in the nth dimension. - Py_intptr_t const shape(int n) const; + Py_intptr_t shape(int n) const; }; diff --git a/libs/numpy/cmake/FindPythonLibsNew.cmake b/libs/numpy/cmake/FindPythonLibsNew.cmake deleted file mode 100644 index b2a5d60..0000000 --- a/libs/numpy/cmake/FindPythonLibsNew.cmake +++ /dev/null @@ -1,211 +0,0 @@ -# - Find python libraries -# This module finds the libraries corresponding to the Python interpeter -# FindPythonInterp provides. -# This code sets the following variables: -# -# PYTHONLIBS_FOUND - have the Python libs been found -# PYTHON_PREFIX - path to the Python installation -# PYTHON_LIBRARIES - path to the python library -# PYTHON_INCLUDE_DIRS - path to where Python.h is found -# PYTHON_SITE_PACKAGES - path to installation site-packages -# PYTHON_IS_DEBUG - whether the Python interpreter is a debug build -# -# PYTHON_INCLUDE_PATH - path to where Python.h is found (deprecated) -# -# A function PYTHON_ADD_MODULE( src1 src2 ... srcN) is defined to build modules for python. - -#============================================================================= -# Copyright 2001-2009 Kitware, Inc. -# Copyright 2012 Continuum Analytics, Inc. -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# * Neither the names of Kitware, Inc., the Insight Software Consortium, -# nor the names of their contributors may be used to endorse or promote -# products derived from this software without specific prior written -# permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -# Use the Python interpreter to find the libs. -if(PythonLibsNew_FIND_REQUIRED) - find_package(PythonInterp REQUIRED) -else() - find_package(PythonInterp) -endif() - -if(NOT PYTHONINTERP_FOUND) - set(PYTHONLIBS_FOUND FALSE) - return() -endif() - -# According to http://stackoverflow.com/questions/646518/python-how-to-detect-debug-interpreter -# testing whether sys has the gettotalrefcount function is a reliable, cross-platform -# way to detect a CPython debug interpreter. -execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" - "from distutils import sysconfig as s;import sys;import struct; -print('.'.join(str(v) for v in sys.version_info)); -print(s.PREFIX); -print(s.get_python_inc(plat_specific=True)); -print(s.get_python_lib(plat_specific=True)); -print(s.get_config_var('SO')); -print(hasattr(sys, 'gettotalrefcount')+0); -print(struct.calcsize('@P')); -" - RESULT_VARIABLE _PYTHON_SUCCESS - OUTPUT_VARIABLE _PYTHON_VALUES - ERROR_VARIABLE _PYTHON_ERROR_VALUE - OUTPUT_STRIP_TRAILING_WHITESPACE) - -if(NOT _PYTHON_SUCCESS MATCHES 0) - if(PythonLibsNew_FIND_REQUIRED) - message(FATAL_ERROR - "Python config failure:\n${_PYTHON_ERROR_VALUE}") - endif() - set(PYTHONLIBS_FOUND FALSE) - return() -endif() - -# Convert the process output into a list -string(REGEX REPLACE ";" "\\\\;" _PYTHON_VALUES ${_PYTHON_VALUES}) -string(REGEX REPLACE "\n" ";" _PYTHON_VALUES ${_PYTHON_VALUES}) -list(GET _PYTHON_VALUES 0 _PYTHON_VERSION_LIST) -list(GET _PYTHON_VALUES 1 PYTHON_PREFIX) -list(GET _PYTHON_VALUES 2 PYTHON_INCLUDE_DIR) -list(GET _PYTHON_VALUES 3 PYTHON_SITE_PACKAGES) -list(GET _PYTHON_VALUES 4 PYTHON_MODULE_EXTENSION) -list(GET _PYTHON_VALUES 5 PYTHON_IS_DEBUG) -list(GET _PYTHON_VALUES 6 PYTHON_SIZEOF_VOID_P) - -# Make sure the Python has the same pointer-size as the chosen compiler -if(NOT ${PYTHON_SIZEOF_VOID_P} MATCHES ${CMAKE_SIZEOF_VOID_P}) - if(PythonLibsNew_FIND_REQUIRED) - math(EXPR _PYTHON_BITS "${PYTHON_SIZEOF_VOID_P} * 8") - math(EXPR _CMAKE_BITS "${CMAKE_SIZEOF_VOID_P} * 8") - message(FATAL_ERROR - "Python config failure: Python is ${_PYTHON_BITS}-bit, " - "chosen compiler is ${_CMAKE_BITS}-bit") - endif() - set(PYTHONLIBS_FOUND FALSE) - return() -endif() - -# The built-in FindPython didn't always give the version numbers -string(REGEX REPLACE "\\." ";" _PYTHON_VERSION_LIST ${_PYTHON_VERSION_LIST}) -list(GET _PYTHON_VERSION_LIST 0 PYTHON_VERSION_MAJOR) -list(GET _PYTHON_VERSION_LIST 1 PYTHON_VERSION_MINOR) -list(GET _PYTHON_VERSION_LIST 2 PYTHON_VERSION_PATCH) - -# Make sure all directory separators are '/' -string(REGEX REPLACE "\\\\" "/" PYTHON_PREFIX ${PYTHON_PREFIX}) -string(REGEX REPLACE "\\\\" "/" PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_DIR}) -string(REGEX REPLACE "\\\\" "/" PYTHON_SITE_PACKAGES ${PYTHON_SITE_PACKAGES}) - -# TODO: All the nuances of CPython debug builds have not been dealt with/tested. -if(PYTHON_IS_DEBUG) - set(PYTHON_MODULE_EXTENSION "_d${PYTHON_MODULE_EXTENSION}") -endif() - -if(CMAKE_HOST_WIN32) - set(PYTHON_LIBRARY - "${PYTHON_PREFIX}/libs/Python${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}.lib") -elseif(APPLE) - set(PYTHON_LIBRARY - "${PYTHON_PREFIX}/lib/libpython${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}.dylib") -else() - if(${PYTHON_SIZEOF_VOID_P} MATCHES 8) - set(_PYTHON_LIBS_SEARCH "${PYTHON_PREFIX}/lib64" "${PYTHON_PREFIX}/lib") - else() - set(_PYTHON_LIBS_SEARCH "${PYTHON_PREFIX}/lib") - endif() - # Probably this needs to be more involved. It would be nice if the config - # information the python interpreter itself gave us were more complete. - find_library(PYTHON_LIBRARY - NAMES "python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" - PATHS ${_PYTHON_LIBS_SEARCH} - NO_SYSTEM_ENVIRONMENT_PATH) -endif() - -# For backward compatibility, set PYTHON_INCLUDE_PATH, but make it internal. -SET(PYTHON_INCLUDE_PATH "${PYTHON_INCLUDE_DIR}" CACHE INTERNAL - "Path to where Python.h is found (deprecated)") - -MARK_AS_ADVANCED( - PYTHON_LIBRARY - PYTHON_INCLUDE_DIR -) - -# We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the -# cache entries because they are meant to specify the location of a single -# library. We now set the variables listed by the documentation for this -# module. -SET(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") -SET(PYTHON_LIBRARIES "${PYTHON_LIBRARY}") -SET(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}") - - -# Don't know how to get to this directory, just doing something simple :P -#INCLUDE(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) -#FIND_PACKAGE_HANDLE_STANDARD_ARGS(PythonLibs DEFAULT_MSG PYTHON_LIBRARIES PYTHON_INCLUDE_DIRS) -find_package_message(PYTHON - "Found PythonLibs: ${PYTHON_LIBRARY}" - "${PYTHON_EXECUTABLE}${PYTHON_VERSION}") - - -# PYTHON_ADD_MODULE( src1 src2 ... srcN) is used to build modules for python. -FUNCTION(PYTHON_ADD_MODULE _NAME ) - GET_PROPERTY(_TARGET_SUPPORTS_SHARED_LIBS - GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) - OPTION(PYTHON_ENABLE_MODULE_${_NAME} "Add module ${_NAME}" TRUE) - OPTION(PYTHON_MODULE_${_NAME}_BUILD_SHARED - "Add module ${_NAME} shared" ${_TARGET_SUPPORTS_SHARED_LIBS}) - - # Mark these options as advanced - MARK_AS_ADVANCED(PYTHON_ENABLE_MODULE_${_NAME} - PYTHON_MODULE_${_NAME}_BUILD_SHARED) - - IF(PYTHON_ENABLE_MODULE_${_NAME}) - IF(PYTHON_MODULE_${_NAME}_BUILD_SHARED) - SET(PY_MODULE_TYPE MODULE) - ELSE(PYTHON_MODULE_${_NAME}_BUILD_SHARED) - SET(PY_MODULE_TYPE STATIC) - SET_PROPERTY(GLOBAL APPEND PROPERTY PY_STATIC_MODULES_LIST ${_NAME}) - ENDIF(PYTHON_MODULE_${_NAME}_BUILD_SHARED) - - SET_PROPERTY(GLOBAL APPEND PROPERTY PY_MODULES_LIST ${_NAME}) - ADD_LIBRARY(${_NAME} ${PY_MODULE_TYPE} ${ARGN}) - TARGET_LINK_LIBRARIES(${_NAME} ${PYTHON_LIBRARIES}) - - IF(PYTHON_MODULE_${_NAME}_BUILD_SHARED) - SET_TARGET_PROPERTIES(${_NAME} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}") - SET_TARGET_PROPERTIES(${_NAME} PROPERTIES SUFFIX "${PYTHON_MODULE_EXTENSION}") - ELSE() - ENDIF() - - ENDIF(PYTHON_ENABLE_MODULE_${_NAME}) -ENDFUNCTION(PYTHON_ADD_MODULE) - diff --git a/libs/numpy/doc/tutorial/dtype.rst b/libs/numpy/doc/tutorial/dtype.rst index 02bb513..c604b31 100644 --- a/libs/numpy/doc/tutorial/dtype.rst +++ b/libs/numpy/doc/tutorial/dtype.rst @@ -5,32 +5,32 @@ Here is a brief tutorial to show how to create ndarrays with built-in python dat Like before, first get the necessary headers, setup the namespaces and initialize the Python runtime and numpy module:: - #include - #include + #include + #include - namespace p = boost::python; - namespace np = boost::numpy; + namespace p = boost::python; + namespace np = boost::numpy; - int main(int argc, char **argv) - { - Py_Initialize(); - np::initialize(); + int main(int argc, char **argv) + { + Py_Initialize(); + np::initialize(); Next, we create the shape and dtype. We use the get_builtin method to get the numpy dtype corresponding to the builtin C++ dtype Here, we will create a 3x3 array passing a tuple with (3,3) for the size, and double as the data type :: - p::tuple shape = p::make_tuple(3, 3); - np::dtype dtype = np::dtype::get_builtin(); - np::ndarray a = np::zeros(shape, dtype); + p::tuple shape = p::make_tuple(3, 3); + np::dtype dtype = np::dtype::get_builtin(); + np::ndarray a = np::zeros(shape, dtype); Finally, we can print the array using the extract method in the python namespace. Here, we first convert the variable into a string, and then extract it as a C++ character array from the python string using the template :: - std::cout << "Original array:\n" << p::extract(p::str(a)) << std::endl; + std::cout << "Original array:\n" << p::extract(p::str(a)) << std::endl; We can also print the dtypes of the data members of the ndarray by using the get_dtype method for the ndarray :: - std::cout << "Datatype is:\n" << p::extract(p::str(a.get_dtype())) << std::endl ; + std::cout << "Datatype is:\n" << p::extract(p::str(a.get_dtype())) << std::endl ; We can also create custom dtypes and build ndarrays with the custom dtypes @@ -52,4 +52,4 @@ We are now ready to create an ndarray with dimensions specified by \*shape\* and np::ndarray new_array = np::zeros(shape,custom_dtype); - } + } diff --git a/libs/numpy/doc/tutorial/fromdata.rst b/libs/numpy/doc/tutorial/fromdata.rst index 2937c78..993d5e4 100644 --- a/libs/numpy/doc/tutorial/fromdata.rst +++ b/libs/numpy/doc/tutorial/fromdata.rst @@ -2,25 +2,25 @@ How to access data using raw pointers ===================================== One of the advantages of the ndarray wrapper is that the same data can be used in both Python and C++ and changes can be made to reflect at both ends. -The from_data method makes this possible. +The from_data method makes this possible. Like before, first get the necessary headers, setup the namespaces and initialize the Python runtime and numpy module:: - #include - #include + #include + #include - namespace p = boost::python; - namespace np = boost::numpy; + namespace p = boost::python; + namespace np = boost::numpy; - int main(int argc, char **argv) - { - Py_Initialize(); - np::initialize(); + int main(int argc, char **argv) + { + Py_Initialize(); + np::initialize(); Create an array in C++ , and pass the pointer to it to the from_data method to create an ndarray:: - int arr[] = {1,2,3,4} ; - np::ndarray py_array = np::from_data(arr, np::dtype::get_builtin() , p::make_tuple(4), p::make_tuple(4), p::object()); + int arr[] = {1,2,3,4,5} ; + np::ndarray py_array = np::from_data(arr, np::dtype::get_builtin() , p::make_tuple(5), p::make_tuple(sizeof(int)), p::object()); Print the source C++ array, as well as the ndarray, to check if they are the same:: @@ -33,9 +33,9 @@ Print the source C++ array, as well as the ndarray, to check if they are the sam Now, change an element in the Python ndarray, and check if the value changed correspondingly in the source C++ array:: - py_array[1] = 5 ; - std::cout << "Is the change reflected in the C++ array used to create the ndarray ? " << std::endl ; - for (int j = 0;j<4 ; j++) + py_array[1] = 5 ; + std::cout << "Is the change reflected in the C++ array used to create the ndarray ? " << std::endl ; + for (int j = 0; j < 5; j++) { std::cout << arr[j] << ' ' ; } diff --git a/libs/numpy/doc/tutorial/ndarray.rst b/libs/numpy/doc/tutorial/ndarray.rst index c007839..a2aea58 100644 --- a/libs/numpy/doc/tutorial/ndarray.rst +++ b/libs/numpy/doc/tutorial/ndarray.rst @@ -8,16 +8,16 @@ This tutorial will introduce you to some of the ways in which you can create nda First, as before, initialise the necessary namepaces and runtimes :: - #include - #include + #include + #include - namespace p = boost::python; - namespace np = boost::numpy; + namespace p = boost::python; + namespace np = boost::numpy; - int main(int argc, char **argv) - { - Py_Initialize(); - np::initialize(); + int main(int argc, char **argv) + { + Py_Initialize(); + np::initialize(); Let's now create an ndarray from a simple tuple. We first create a tuple object, and then pass it to the array method, to generate the necessary tuple :: @@ -39,15 +39,15 @@ We can also create an array by supplying data arrays and a few other parameters. First,create an integer array :: - int data[] = {1,2,3,4} ; + int data[] = {1,2,3,4,5} ; Create a shape, and strides, needed by the function :: - p::tuple shape = p::make_tuple(4) ; - p::tuple stride = p::make_tuple(4) ; + p::tuple shape = p::make_tuple(5) ; + p::tuple stride = p::make_tuple(sizeof(int)) ; -Here, shape is 1x4 , and the stride is also 4. -A stride is the number of bytes that must be travelled to get to the next desired element while constructing the ndarray. Here, the size of the "int" is 32 bits and hence, the stride is 4 to access each element. +Here, shape is (4,) , and the stride is `sizeof(int)``. +A stride is the number of bytes that must be traveled to get to the next desired element while constructing the ndarray. The function also needs an owner, to keep track of the data array passed. Passing none is dangerous :: @@ -59,7 +59,7 @@ The from_data function takes the data array, datatype,shape,stride and owner as Now let's print the ndarray we created :: - std::cout << "Single dimensional array ::" << std::endl << p::extract < char const * > (p::str(data_ex)) << std::endl ; + std::cout << "Single dimensional array ::" << std::endl << p::extract < char const * > (p::str(data_ex)) << std::endl ; Let's make it a little more interesting. Lets make an 3x2 ndarray from a multi-dimensional array using non-unit strides @@ -71,7 +71,7 @@ Now let's create an array of 3x2 elements, picking the first and third elements The strides will be 4x2 i.e. 4 bytes to go to the next desired row, and 2 bytes to go to the next desired column :: shape = p::make_tuple(3,2) ; - stride = p::make_tuple(4,2) ; + stride = p::make_tuple(sizeof(uint8_t)*2,sizeof(uint8_t)) ; Get the numpy dtype for the built-in 8-bit integer data type :: diff --git a/libs/numpy/doc/tutorial/simple.rst b/libs/numpy/doc/tutorial/simple.rst index 3c46296..f56a831 100644 --- a/libs/numpy/doc/tutorial/simple.rst +++ b/libs/numpy/doc/tutorial/simple.rst @@ -5,37 +5,37 @@ Let's start with a simple tutorial to create and modify arrays. Get the necessary headers for numpy components and set up necessary namespaces:: - #include - #include + #include + #include - namespace p = boost::python; - namespace np = boost::numpy; + namespace p = boost::python; + namespace np = boost::numpy; Initialise the Python runtime, and the numpy module. Failure to call these results in segmentation errors:: - int main(int argc, char **argv) - { - Py_Initialize(); - np::initialize(); + int main(int argc, char **argv) + { + Py_Initialize(); + np::initialize(); Zero filled n-dimensional arrays can be created using the shape and data-type of the array as a parameter. Here, the shape is 3x3 and the datatype is the built-in float type:: - p::tuple shape = p::make_tuple(3, 3); - np::dtype dtype = np::dtype::get_builtin(); - np::ndarray a = np::zeros(shape, dtype); + p::tuple shape = p::make_tuple(3, 3); + np::dtype dtype = np::dtype::get_builtin(); + np::ndarray a = np::zeros(shape, dtype); You can also create an empty array like this :: - np::ndarray b = np::empty(shape,dtype); - + np::ndarray b = np::empty(shape,dtype); + Print the original and reshaped array. The array a which is a list is first converted to a string, and each value in the list is extracted using extract< >:: - std::cout << "Original array:\n" << p::extract(p::str(a)) << std::endl; + std::cout << "Original array:\n" << p::extract(p::str(a)) << std::endl; - // Reshape the array into a 1D array - a = a.reshape(p::make_tuple(9)); - // Print it again. - std::cout << "Reshaped array:\n" << p::extract(p::str(a)) << std::endl; - } + // Reshape the array into a 1D array + a = a.reshape(p::make_tuple(9)); + // Print it again. + std::cout << "Reshaped array:\n" << p::extract(p::str(a)) << std::endl; + } diff --git a/libs/numpy/src/CMakeLists.txt b/libs/numpy/src/CMakeLists.txt index 6b96664..ac67f76 100644 --- a/libs/numpy/src/CMakeLists.txt +++ b/libs/numpy/src/CMakeLists.txt @@ -20,7 +20,7 @@ add_library(boost_numpy ${LIBRARY_TYPE} target_link_libraries(boost_numpy ${Boost_LIBRARIES} ${PYTHON_LIBRARIES}) install(TARGETS boost_numpy - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib${LIB_SUFFIX} + LIBRARY DESTINATION lib${LIB_SUFFIX} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) diff --git a/libs/numpy/src/dtype.cpp b/libs/numpy/src/dtype.cpp index 51fc916..83a2bd2 100644 --- a/libs/numpy/src/dtype.cpp +++ b/libs/numpy/src/dtype.cpp @@ -57,7 +57,9 @@ BUILTIN_INT_DTYPE(8); BUILTIN_INT_DTYPE(16); BUILTIN_INT_DTYPE(32); BUILTIN_INT_DTYPE(64); +#ifdef NPY_FLOAT16 BUILTIN_FLOAT_DTYPE(16); +#endif BUILTIN_FLOAT_DTYPE(32); BUILTIN_FLOAT_DTYPE(64); BUILTIN_COMPLEX_DTYPE(64); diff --git a/libs/numpy/src/ndarray.cpp b/libs/numpy/src/ndarray.cpp index ce43154..481692e 100644 --- a/libs/numpy/src/ndarray.cpp +++ b/libs/numpy/src/ndarray.cpp @@ -22,7 +22,7 @@ namespace numpy namespace detail { -ndarray::bitflag numpy_to_bitflag(int const f) +ndarray::bitflag numpy_to_bitflag(int const f) { ndarray::bitflag r = ndarray::NONE; if (f & NPY_C_CONTIGUOUS) r = (r | ndarray::C_CONTIGUOUS); @@ -32,7 +32,7 @@ ndarray::bitflag numpy_to_bitflag(int const f) return r; } -int const bitflag_to_numpy(ndarray::bitflag f) +int bitflag_to_numpy(ndarray::bitflag f) { int r = 0; if (f & ndarray::C_CONTIGUOUS) r |= NPY_C_CONTIGUOUS; @@ -184,7 +184,7 @@ void ndarray::set_base(object const & base) } } -ndarray::bitflag const ndarray::get_flags() const +ndarray::bitflag ndarray::get_flags() const { return numpy::detail::numpy_to_bitflag(get_struct()->flags); } diff --git a/libs/numpy/src/numpy.cpp b/libs/numpy/src/numpy.cpp index 0cc3f5f..e5bc216 100644 --- a/libs/numpy/src/numpy.cpp +++ b/libs/numpy/src/numpy.cpp @@ -12,22 +12,40 @@ namespace boost namespace numpy { +// NumPy's import_* macros always return if they encounter an error, +// but in Python 2 there's no return value, while Python 3 returns +// null on an error. The machinery below produces the same behavior +// on both Python versions: initialize returns false with an exception +// raised if there is an exception. + +static #if PY_MAJOR_VERSION == 2 -static void wrap_import_array() { - import_array(); -} +void #else -static void * wrap_import_array() { - import_array(); -} +PyObject * #endif - -void initialize(bool register_scalar_converters) +wrap_imports() { - wrap_import_array(); + import_array(); import_ufunc(); +#if PY_MAJOR_VERSION > 2 + Py_RETURN_NONE; +#endif +} + +bool initialize(bool register_scalar_converters) +{ +#if PY_MAJOR_VERSION == 2 + wrap_imports(); + if (PyErr_Occurred()) return false; +#else + PyObject * r = wrap_imports(); + if (!r) return false; + Py_DECREF(r); +#endif if (register_scalar_converters) dtype::register_scalar_converters(); + return true; } } diff --git a/libs/numpy/src/ufunc.cpp b/libs/numpy/src/ufunc.cpp index aa6c793..a6a728f 100644 --- a/libs/numpy/src/ufunc.cpp +++ b/libs/numpy/src/ufunc.cpp @@ -50,7 +50,7 @@ char * multi_iter::get_data(int i) const return reinterpret_cast(PyArray_MultiIter_DATA(ptr(), i)); } -int const multi_iter::get_nd() const +int multi_iter::get_nd() const { return reinterpret_cast(ptr())->nd; } @@ -60,7 +60,7 @@ Py_intptr_t const * multi_iter::get_shape() const return reinterpret_cast(ptr())->dimensions; } -Py_intptr_t const multi_iter::shape(int n) const +Py_intptr_t multi_iter::shape(int n) const { return reinterpret_cast(ptr())->dimensions[n]; } diff --git a/libs/numpy/test/CMakeLists.txt b/libs/numpy/test/CMakeLists.txt index 0075f92..6d0e5c6 100644 --- a/libs/numpy/test/CMakeLists.txt +++ b/libs/numpy/test/CMakeLists.txt @@ -16,11 +16,19 @@ set( TestCommand ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${runCmakeTest} ) # custom macro with most of the redundant code for making a python test macro( addPythonTest _name _srcpy ) + ADD_CUSTOM_TARGET( + ${_srcpy} ALL + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_srcpy} + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_CURRENT_SOURCE_DIR}/${_srcpy} + ${CMAKE_CURRENT_BINARY_DIR}/${_srcpy} + ) + # make the pyd library link against boost_numpy python and boost TARGET_LINK_LIBRARIES(${_name} boost_numpy) - + # make a test of the module using the python source file in the test directory - ADD_TEST(${_name} ${TestCommand} ${TEST_SOURCE_DIR}/${_srcpy}) + ADD_TEST(${_name} ${TestCommand} ${CMAKE_CURRENT_BINARY_DIR}/${_srcpy}) # set the regex to use to recognize a failure since `python testfoo.py` # does not seem to return non-zero with a test failure diff --git a/libs/numpy/test/dtype.py b/libs/numpy/test/dtype.py index a280cc3..c10d251 100644 --- a/libs/numpy/test/dtype.py +++ b/libs/numpy/test/dtype.py @@ -8,6 +8,7 @@ import dtype_mod import unittest import numpy +import sys class DtypeTestCase(unittest.TestCase): @@ -27,8 +28,9 @@ def testIntegers(self): self.assertEquivalent(fu(True), numpy.dtype(u)) self.assertEquivalent(fs(int(1)), numpy.dtype(s)) self.assertEquivalent(fu(int(1)), numpy.dtype(u)) - self.assertEquivalent(fs(long(1)), numpy.dtype(s)) - self.assertEquivalent(fu(long(1)), numpy.dtype(u)) + if sys.version_info[0] == 2: + self.assertEquivalent(fs(long(1)), numpy.dtype(s)) + self.assertEquivalent(fu(long(1)), numpy.dtype(u)) for name in ("bool_", "byte", "ubyte", "short", "ushort", "intc", "uintc"): t = getattr(numpy, name) ft = getattr(dtype_mod, "accept_%s" % name) @@ -37,7 +39,8 @@ def testIntegers(self): self.assertEquivalent(ft(True), numpy.dtype(t)) if name != "bool_": self.assertEquivalent(ft(int(1)), numpy.dtype(t)) - self.assertEquivalent(ft(long(1)), numpy.dtype(t)) + if sys.version_info[0] == 2: + self.assertEquivalent(ft(long(1)), numpy.dtype(t)) def testFloats(self): diff --git a/libs/numpy/test/runCmakeTest.sh.in b/libs/numpy/test/runCmakeTest.sh.in index efaa756..4ce2966 100755 --- a/libs/numpy/test/runCmakeTest.sh.in +++ b/libs/numpy/test/runCmakeTest.sh.in @@ -1,3 +1,3 @@ #!/bin/bash export PYTHONPATH=@CMAKE_LIBRARY_OUTPUT_DIRECTORY@:${PYTHONPATH} -python $1 \ No newline at end of file +@PYTHON_EXECUTABLE@ $1