From 0c79aba2c782ccdc789b243adf7cb6a8d4fa6b7b Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 7 Dec 2016 22:03:26 +0100 Subject: [PATCH] extracted from storm repo, refactored formula --- CMakeLists.txt | 64 + lib/.gitignore | 3 + lib/stormpy/__init__.py | 70 + lib/stormpy/expressions/__init__.py | 2 + lib/stormpy/info/__init__.py | 2 + lib/stormpy/logic/__init__.py | 2 + lib/stormpy/storage/__init__.py | 3 + lib/stormpy/storage/action.py | 36 + lib/stormpy/storage/state.py | 34 + resources/pybind11/.appveyor.yml | 32 + resources/pybind11/.gitignore | 35 + resources/pybind11/.gitmodules | 3 + resources/pybind11/.travis.yml | 112 ++ resources/pybind11/CMakeLists.txt | 184 ++ resources/pybind11/CONTRIBUTING.md | 37 + resources/pybind11/LICENSE | 36 + resources/pybind11/MANIFEST.in | 2 + resources/pybind11/README.md | 123 ++ .../pybind11/docs/_static/theme_overrides.css | 11 + .../pybind11/docs/advanced/cast/chrono.rst | 81 + .../pybind11/docs/advanced/cast/custom.rst | 85 + .../pybind11/docs/advanced/cast/eigen.rst | 50 + .../docs/advanced/cast/functional.rst | 113 ++ .../pybind11/docs/advanced/cast/index.rst | 41 + .../pybind11/docs/advanced/cast/overview.rst | 144 ++ resources/pybind11/docs/advanced/cast/stl.rst | 154 ++ resources/pybind11/docs/advanced/classes.rst | 634 ++++++ .../pybind11/docs/advanced/exceptions.rst | 142 ++ .../pybind11/docs/advanced/functions.rst | 311 +++ resources/pybind11/docs/advanced/misc.rst | 229 +++ .../pybind11/docs/advanced/pycpp/index.rst | 13 + .../pybind11/docs/advanced/pycpp/numpy.rst | 299 +++ .../pybind11/docs/advanced/pycpp/object.rst | 96 + .../docs/advanced/pycpp/utilities.rst | 57 + .../pybind11/docs/advanced/smart_ptrs.rst | 143 ++ resources/pybind11/docs/basics.rst | 287 +++ resources/pybind11/docs/benchmark.py | 90 + resources/pybind11/docs/benchmark.rst | 99 + resources/pybind11/docs/changelog.rst | 222 +++ resources/pybind11/docs/classes.rst | 410 ++++ resources/pybind11/docs/compiling.rst | 53 + resources/pybind11/docs/conf.py | 308 +++ resources/pybind11/docs/faq.rst | 251 +++ resources/pybind11/docs/index.rst | 45 + resources/pybind11/docs/intro.rst | 93 + resources/pybind11/docs/limitations.rst | 20 + resources/pybind11/docs/pybind11-logo.png | Bin 0 -> 58510 bytes .../docs/pybind11_vs_boost_python1.png | Bin 0 -> 44653 bytes .../docs/pybind11_vs_boost_python1.svg | 427 ++++ .../docs/pybind11_vs_boost_python2.png | Bin 0 -> 41121 bytes .../docs/pybind11_vs_boost_python2.svg | 427 ++++ resources/pybind11/docs/reference.rst | 247 +++ resources/pybind11/docs/release.rst | 22 + resources/pybind11/include/pybind11/attr.h | 362 ++++ resources/pybind11/include/pybind11/cast.h | 1464 ++++++++++++++ resources/pybind11/include/pybind11/chrono.h | 160 ++ resources/pybind11/include/pybind11/common.h | 560 ++++++ resources/pybind11/include/pybind11/complex.h | 47 + resources/pybind11/include/pybind11/descr.h | 177 ++ resources/pybind11/include/pybind11/eigen.h | 239 +++ resources/pybind11/include/pybind11/eval.h | 105 + .../pybind11/include/pybind11/functional.h | 79 + resources/pybind11/include/pybind11/numpy.h | 1169 +++++++++++ .../pybind11/include/pybind11/operators.h | 154 ++ resources/pybind11/include/pybind11/options.h | 65 + .../pybind11/include/pybind11/pybind11.h | 1735 +++++++++++++++++ resources/pybind11/include/pybind11/pytypes.h | 899 +++++++++ resources/pybind11/include/pybind11/stl.h | 256 +++ .../pybind11/include/pybind11/stl_bind.h | 541 +++++ resources/pybind11/include/pybind11/typeid.h | 53 + resources/pybind11/pybind11/__init__.py | 11 + resources/pybind11/pybind11/_version.py | 2 + resources/pybind11/setup.cfg | 11 + resources/pybind11/setup.py | 74 + resources/pybind11/tests/CMakeLists.txt | 111 ++ resources/pybind11/tests/conftest.py | 227 +++ resources/pybind11/tests/constructor_stats.h | 249 +++ resources/pybind11/tests/object.h | 175 ++ resources/pybind11/tests/pybind11_tests.cpp | 45 + resources/pybind11/tests/pybind11_tests.h | 12 + .../tests/test_alias_initialization.cpp | 62 + .../tests/test_alias_initialization.py | 79 + resources/pybind11/tests/test_buffers.cpp | 117 ++ resources/pybind11/tests/test_buffers.py | 57 + resources/pybind11/tests/test_callbacks.cpp | 149 ++ resources/pybind11/tests/test_callbacks.py | 98 + resources/pybind11/tests/test_chrono.cpp | 59 + resources/pybind11/tests/test_chrono.py | 116 ++ resources/pybind11/tests/test_class_args.cpp | 68 + resources/pybind11/tests/test_class_args.py | 6 + .../tests/test_constants_and_functions.cpp | 55 + .../tests/test_constants_and_functions.py | 21 + .../tests/test_copy_move_policies.cpp | 41 + .../pybind11/tests/test_copy_move_policies.py | 15 + .../pybind11/tests/test_docstring_options.cpp | 53 + .../pybind11/tests/test_docstring_options.py | 32 + resources/pybind11/tests/test_eigen.cpp | 134 ++ resources/pybind11/tests/test_eigen.py | 135 ++ resources/pybind11/tests/test_enum.cpp | 68 + resources/pybind11/tests/test_enum.py | 108 + resources/pybind11/tests/test_eval.cpp | 79 + resources/pybind11/tests/test_eval.py | 19 + resources/pybind11/tests/test_eval_call.py | 4 + resources/pybind11/tests/test_exceptions.cpp | 173 ++ resources/pybind11/tests/test_exceptions.py | 74 + resources/pybind11/tests/test_inheritance.cpp | 100 + resources/pybind11/tests/test_inheritance.py | 55 + resources/pybind11/tests/test_issues.cpp | 396 ++++ resources/pybind11/tests/test_issues.py | 252 +++ resources/pybind11/tests/test_keep_alive.cpp | 40 + resources/pybind11/tests/test_keep_alive.py | 97 + .../tests/test_kwargs_and_defaults.cpp | 56 + .../tests/test_kwargs_and_defaults.py | 57 + .../tests/test_methods_and_attributes.cpp | 169 ++ .../tests/test_methods_and_attributes.py | 189 ++ resources/pybind11/tests/test_modules.cpp | 58 + resources/pybind11/tests/test_modules.py | 54 + .../tests/test_multiple_inheritance.cpp | 84 + .../tests/test_multiple_inheritance.py | 64 + resources/pybind11/tests/test_numpy_array.cpp | 153 ++ resources/pybind11/tests/test_numpy_array.py | 273 +++ .../pybind11/tests/test_numpy_dtypes.cpp | 363 ++++ resources/pybind11/tests/test_numpy_dtypes.py | 219 +++ .../pybind11/tests/test_numpy_vectorize.cpp | 41 + .../pybind11/tests/test_numpy_vectorize.py | 74 + .../pybind11/tests/test_opaque_types.cpp | 62 + resources/pybind11/tests/test_opaque_types.py | 49 + .../tests/test_operator_overloading.cpp | 76 + .../tests/test_operator_overloading.py | 41 + resources/pybind11/tests/test_pickling.cpp | 81 + resources/pybind11/tests/test_pickling.py | 32 + .../pybind11/tests/test_python_types.cpp | 380 ++++ resources/pybind11/tests/test_python_types.py | 374 ++++ .../tests/test_sequences_and_iterators.cpp | 275 +++ .../tests/test_sequences_and_iterators.py | 90 + resources/pybind11/tests/test_smart_ptr.cpp | 224 +++ resources/pybind11/tests/test_smart_ptr.py | 198 ++ resources/pybind11/tests/test_stl_binders.cpp | 95 + resources/pybind11/tests/test_stl_binders.py | 140 ++ .../pybind11/tests/test_virtual_functions.cpp | 347 ++++ .../pybind11/tests/test_virtual_functions.py | 254 +++ resources/pybind11/tools/FindEigen3.cmake | 81 + .../pybind11/tools/FindPythonLibsNew.cmake | 194 ++ resources/pybind11/tools/check-style.sh | 69 + resources/pybind11/tools/libsize.py | 38 + resources/pybind11/tools/mkdoc.py | 309 +++ setup.py | 87 + src/CMakeLists.txt | 56 + src/common.h | 127 ++ src/core/bisimulation.cpp | 22 + src/core/bisimulation.h | 8 + src/core/common.h | 3 + src/core/core.cpp | 49 + src/core/core.h | 10 + src/core/input.cpp | 34 + src/core/input.h | 8 + src/core/modelchecking.cpp | 76 + src/core/modelchecking.h | 8 + src/helpers.h | 29 + src/logic/formulae.cpp | 59 + src/logic/formulae.h | 8 + src/mod_core.cpp | 17 + src/mod_expressions.cpp | 21 + src/mod_info.cpp | 13 + src/mod_logic.cpp | 9 + src/mod_storage.cpp | 11 + src/storage/common.h | 1 + src/storage/matrix.cpp | 129 ++ src/storage/matrix.h | 8 + src/storage/model.cpp | 77 + src/storage/model.h | 8 + tests/.gitignore | 1 + tests/conftest.py | 3 + tests/core/test_bisimulation.py | 39 + tests/core/test_core.py | 14 + tests/core/test_modelchecking.py | 45 + tests/core/test_parse.py | 32 + tests/expressions/test_expressions.py | 9 + tests/helpers/helper.py | 5 + tests/info/test_info.py | 8 + tests/logic/test_formulas.py | 51 + tests/storage/test_matrix.py | 96 + tests/storage/test_model.py | 96 + tests/storage/test_model_iterators.py | 82 + 184 files changed, 24750 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 lib/.gitignore create mode 100644 lib/stormpy/__init__.py create mode 100644 lib/stormpy/expressions/__init__.py create mode 100644 lib/stormpy/info/__init__.py create mode 100644 lib/stormpy/logic/__init__.py create mode 100644 lib/stormpy/storage/__init__.py create mode 100644 lib/stormpy/storage/action.py create mode 100644 lib/stormpy/storage/state.py create mode 100644 resources/pybind11/.appveyor.yml create mode 100644 resources/pybind11/.gitignore create mode 100644 resources/pybind11/.gitmodules create mode 100644 resources/pybind11/.travis.yml create mode 100755 resources/pybind11/CMakeLists.txt create mode 100755 resources/pybind11/CONTRIBUTING.md create mode 100755 resources/pybind11/LICENSE create mode 100755 resources/pybind11/MANIFEST.in create mode 100755 resources/pybind11/README.md create mode 100755 resources/pybind11/docs/_static/theme_overrides.css create mode 100755 resources/pybind11/docs/advanced/cast/chrono.rst create mode 100755 resources/pybind11/docs/advanced/cast/custom.rst create mode 100755 resources/pybind11/docs/advanced/cast/eigen.rst create mode 100755 resources/pybind11/docs/advanced/cast/functional.rst create mode 100755 resources/pybind11/docs/advanced/cast/index.rst create mode 100755 resources/pybind11/docs/advanced/cast/overview.rst create mode 100755 resources/pybind11/docs/advanced/cast/stl.rst create mode 100755 resources/pybind11/docs/advanced/classes.rst create mode 100755 resources/pybind11/docs/advanced/exceptions.rst create mode 100755 resources/pybind11/docs/advanced/functions.rst create mode 100755 resources/pybind11/docs/advanced/misc.rst create mode 100755 resources/pybind11/docs/advanced/pycpp/index.rst create mode 100755 resources/pybind11/docs/advanced/pycpp/numpy.rst create mode 100755 resources/pybind11/docs/advanced/pycpp/object.rst create mode 100755 resources/pybind11/docs/advanced/pycpp/utilities.rst create mode 100755 resources/pybind11/docs/advanced/smart_ptrs.rst create mode 100755 resources/pybind11/docs/basics.rst create mode 100755 resources/pybind11/docs/benchmark.py create mode 100755 resources/pybind11/docs/benchmark.rst create mode 100755 resources/pybind11/docs/changelog.rst create mode 100755 resources/pybind11/docs/classes.rst create mode 100755 resources/pybind11/docs/compiling.rst create mode 100755 resources/pybind11/docs/conf.py create mode 100755 resources/pybind11/docs/faq.rst create mode 100755 resources/pybind11/docs/index.rst create mode 100755 resources/pybind11/docs/intro.rst create mode 100755 resources/pybind11/docs/limitations.rst create mode 100755 resources/pybind11/docs/pybind11-logo.png create mode 100755 resources/pybind11/docs/pybind11_vs_boost_python1.png create mode 100755 resources/pybind11/docs/pybind11_vs_boost_python1.svg create mode 100755 resources/pybind11/docs/pybind11_vs_boost_python2.png create mode 100755 resources/pybind11/docs/pybind11_vs_boost_python2.svg create mode 100755 resources/pybind11/docs/reference.rst create mode 100755 resources/pybind11/docs/release.rst create mode 100755 resources/pybind11/include/pybind11/attr.h create mode 100755 resources/pybind11/include/pybind11/cast.h create mode 100755 resources/pybind11/include/pybind11/chrono.h create mode 100755 resources/pybind11/include/pybind11/common.h create mode 100755 resources/pybind11/include/pybind11/complex.h create mode 100755 resources/pybind11/include/pybind11/descr.h create mode 100755 resources/pybind11/include/pybind11/eigen.h create mode 100755 resources/pybind11/include/pybind11/eval.h create mode 100755 resources/pybind11/include/pybind11/functional.h create mode 100755 resources/pybind11/include/pybind11/numpy.h create mode 100755 resources/pybind11/include/pybind11/operators.h create mode 100755 resources/pybind11/include/pybind11/options.h create mode 100755 resources/pybind11/include/pybind11/pybind11.h create mode 100755 resources/pybind11/include/pybind11/pytypes.h create mode 100755 resources/pybind11/include/pybind11/stl.h create mode 100755 resources/pybind11/include/pybind11/stl_bind.h create mode 100755 resources/pybind11/include/pybind11/typeid.h create mode 100755 resources/pybind11/pybind11/__init__.py create mode 100755 resources/pybind11/pybind11/_version.py create mode 100755 resources/pybind11/setup.cfg create mode 100755 resources/pybind11/setup.py create mode 100755 resources/pybind11/tests/CMakeLists.txt create mode 100755 resources/pybind11/tests/conftest.py create mode 100755 resources/pybind11/tests/constructor_stats.h create mode 100755 resources/pybind11/tests/object.h create mode 100755 resources/pybind11/tests/pybind11_tests.cpp create mode 100755 resources/pybind11/tests/pybind11_tests.h create mode 100755 resources/pybind11/tests/test_alias_initialization.cpp create mode 100755 resources/pybind11/tests/test_alias_initialization.py create mode 100755 resources/pybind11/tests/test_buffers.cpp create mode 100755 resources/pybind11/tests/test_buffers.py create mode 100755 resources/pybind11/tests/test_callbacks.cpp create mode 100755 resources/pybind11/tests/test_callbacks.py create mode 100755 resources/pybind11/tests/test_chrono.cpp create mode 100755 resources/pybind11/tests/test_chrono.py create mode 100755 resources/pybind11/tests/test_class_args.cpp create mode 100755 resources/pybind11/tests/test_class_args.py create mode 100755 resources/pybind11/tests/test_constants_and_functions.cpp create mode 100755 resources/pybind11/tests/test_constants_and_functions.py create mode 100755 resources/pybind11/tests/test_copy_move_policies.cpp create mode 100755 resources/pybind11/tests/test_copy_move_policies.py create mode 100755 resources/pybind11/tests/test_docstring_options.cpp create mode 100755 resources/pybind11/tests/test_docstring_options.py create mode 100755 resources/pybind11/tests/test_eigen.cpp create mode 100755 resources/pybind11/tests/test_eigen.py create mode 100755 resources/pybind11/tests/test_enum.cpp create mode 100755 resources/pybind11/tests/test_enum.py create mode 100755 resources/pybind11/tests/test_eval.cpp create mode 100755 resources/pybind11/tests/test_eval.py create mode 100755 resources/pybind11/tests/test_eval_call.py create mode 100755 resources/pybind11/tests/test_exceptions.cpp create mode 100755 resources/pybind11/tests/test_exceptions.py create mode 100755 resources/pybind11/tests/test_inheritance.cpp create mode 100755 resources/pybind11/tests/test_inheritance.py create mode 100755 resources/pybind11/tests/test_issues.cpp create mode 100755 resources/pybind11/tests/test_issues.py create mode 100755 resources/pybind11/tests/test_keep_alive.cpp create mode 100755 resources/pybind11/tests/test_keep_alive.py create mode 100755 resources/pybind11/tests/test_kwargs_and_defaults.cpp create mode 100755 resources/pybind11/tests/test_kwargs_and_defaults.py create mode 100755 resources/pybind11/tests/test_methods_and_attributes.cpp create mode 100755 resources/pybind11/tests/test_methods_and_attributes.py create mode 100755 resources/pybind11/tests/test_modules.cpp create mode 100755 resources/pybind11/tests/test_modules.py create mode 100755 resources/pybind11/tests/test_multiple_inheritance.cpp create mode 100755 resources/pybind11/tests/test_multiple_inheritance.py create mode 100755 resources/pybind11/tests/test_numpy_array.cpp create mode 100755 resources/pybind11/tests/test_numpy_array.py create mode 100755 resources/pybind11/tests/test_numpy_dtypes.cpp create mode 100755 resources/pybind11/tests/test_numpy_dtypes.py create mode 100755 resources/pybind11/tests/test_numpy_vectorize.cpp create mode 100755 resources/pybind11/tests/test_numpy_vectorize.py create mode 100755 resources/pybind11/tests/test_opaque_types.cpp create mode 100755 resources/pybind11/tests/test_opaque_types.py create mode 100755 resources/pybind11/tests/test_operator_overloading.cpp create mode 100755 resources/pybind11/tests/test_operator_overloading.py create mode 100755 resources/pybind11/tests/test_pickling.cpp create mode 100755 resources/pybind11/tests/test_pickling.py create mode 100755 resources/pybind11/tests/test_python_types.cpp create mode 100755 resources/pybind11/tests/test_python_types.py create mode 100755 resources/pybind11/tests/test_sequences_and_iterators.cpp create mode 100755 resources/pybind11/tests/test_sequences_and_iterators.py create mode 100755 resources/pybind11/tests/test_smart_ptr.cpp create mode 100755 resources/pybind11/tests/test_smart_ptr.py create mode 100755 resources/pybind11/tests/test_stl_binders.cpp create mode 100755 resources/pybind11/tests/test_stl_binders.py create mode 100755 resources/pybind11/tests/test_virtual_functions.cpp create mode 100755 resources/pybind11/tests/test_virtual_functions.py create mode 100755 resources/pybind11/tools/FindEigen3.cmake create mode 100755 resources/pybind11/tools/FindPythonLibsNew.cmake create mode 100755 resources/pybind11/tools/check-style.sh create mode 100755 resources/pybind11/tools/libsize.py create mode 100755 resources/pybind11/tools/mkdoc.py create mode 100755 setup.py create mode 100644 src/CMakeLists.txt create mode 100644 src/common.h create mode 100644 src/core/bisimulation.cpp create mode 100644 src/core/bisimulation.h create mode 100644 src/core/common.h create mode 100644 src/core/core.cpp create mode 100644 src/core/core.h create mode 100644 src/core/input.cpp create mode 100644 src/core/input.h create mode 100644 src/core/modelchecking.cpp create mode 100644 src/core/modelchecking.h create mode 100644 src/helpers.h create mode 100644 src/logic/formulae.cpp create mode 100644 src/logic/formulae.h create mode 100644 src/mod_core.cpp create mode 100644 src/mod_expressions.cpp create mode 100644 src/mod_info.cpp create mode 100644 src/mod_logic.cpp create mode 100644 src/mod_storage.cpp create mode 100644 src/storage/common.h create mode 100644 src/storage/matrix.cpp create mode 100644 src/storage/matrix.h create mode 100644 src/storage/model.cpp create mode 100644 src/storage/model.h create mode 100644 tests/.gitignore create mode 100644 tests/conftest.py create mode 100644 tests/core/test_bisimulation.py create mode 100644 tests/core/test_core.py create mode 100644 tests/core/test_modelchecking.py create mode 100644 tests/core/test_parse.py create mode 100644 tests/expressions/test_expressions.py create mode 100644 tests/helpers/helper.py create mode 100644 tests/info/test_info.py create mode 100644 tests/logic/test_formulas.py create mode 100644 tests/storage/test_matrix.py create mode 100644 tests/storage/test_model.py create mode 100644 tests/storage/test_model_iterators.py diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b7af91a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,64 @@ +cmake_minimum_required(VERSION 3.0.0) +project(pystorm) + + +find_package(storm REQUIRED) +add_subdirectory(resources/pybind11) + + +file(GLOB_RECURSE STORM_CORE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/core/*.cpp) + +pybind11_add_module(stormpy.core ${CMAKE_CURRENT_SOURCE_DIR}/src/mod_core.cpp ${STORM_CORE_SOURCES}) +target_include_directories(stormpy.core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${storm_INCLUDE_DIR}) +target_link_libraries(stormpy.core PRIVATE storm) + +file(GLOB_RECURSE STORM_INFO_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/info/*.cpp) + +pybind11_add_module(stormpy.info ${CMAKE_CURRENT_SOURCE_DIR}/src/mod_info.cpp ${STORM_INFO_SOURCES}) +target_include_directories(stormpy.info PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${storm_INCLUDE_DIR}) +target_link_libraries(stormpy.info PRIVATE storm) + + +file(GLOB_RECURSE STORM_EXPRESSIONS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/expressions/*.cpp) + +pybind11_add_module(stormpy.expressions ${CMAKE_CURRENT_SOURCE_DIR}/src/mod_expressions.cpp ${STORM_EXPRESSIONS_SOURCES}) +target_include_directories(stormpy.expressions PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${storm_INCLUDE_DIR}) +target_link_libraries(stormpy.expressions PRIVATE storm) + + +file(GLOB_RECURSE STORM_LOGIC_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/logic/*.cpp) + +pybind11_add_module(stormpy.logic ${CMAKE_CURRENT_SOURCE_DIR}/src/mod_logic.cpp ${STORM_LOGIC_SOURCES}) +target_include_directories(stormpy.logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${storm_INCLUDE_DIR}) +target_link_libraries(stormpy.logic PRIVATE storm) + +file(GLOB_RECURSE STORM_STORAGE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/storage/*.cpp) + +pybind11_add_module(stormpy.storage ${CMAKE_CURRENT_SOURCE_DIR}/src/mod_storage.cpp ${STORM_STORAGE_SOURCES}) +target_include_directories(stormpy.storage PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${storm_INCLUDE_DIR}) +target_link_libraries(stormpy.storage PRIVATE storm) + +#set(STORMPY_OUTPUT_DIR "${PROJECT_BINARY_DIR}/stormpy") +#set(STORMPY_SOURCE_DIR "${PROJECT_SOURCE_DIR}/stormpy") +# +#if(STORM_HAVE_CLN) +# set(STORMPY_USE_CLN 1) +#else() +# set(STORMPY_USE_CLN 0) +#endif() +# +## Set configuration file +#get_directory_property(STORMPY_INCLUDE_DIRS_PROP INCLUDE_DIRECTORIES) +#foreach(arg ${STORMPY_INCLUDE_DIRS_PROP}) +# set(STORMPY_INCLUDE_DIRS "${STORMPY_INCLUDE_DIRS}${sep}${arg}") +# set(sep ":") +#endforeach() +#set(STORMPY_COMPILE_ARGS ${CMAKE_CXX_FLAGS}) +#set(STORMPY_LIBRARY_DIRS "${PROJECT_BINARY_DIR}/src/storm") +#set(STORMPY_RPATH "${PROJECT_BINARY_DIR}/src/storm") +#configure_file ( +# "${PROJECT_SOURCE_DIR}/stormpy/setup.cfg.in" +# "${PROJECT_SOURCE_DIR}/stormpy/setup.cfg" +#) +# + diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 0000000..c70bcf8 --- /dev/null +++ b/lib/.gitignore @@ -0,0 +1,3 @@ +*.so +__pycache__/ +stormpy.egg-info/ diff --git a/lib/stormpy/__init__.py b/lib/stormpy/__init__.py new file mode 100644 index 0000000..3dee81d --- /dev/null +++ b/lib/stormpy/__init__.py @@ -0,0 +1,70 @@ +""" +It looks like you want to know about 'stormpy'. + + _.-;:q=._ + .' j=""^k;:\. + ; .F ";`Y + ,;.J_ ;'j + ,-;"^7F : .F _________________ + ,-'-_<. ;gj. _.,---""'' .' + ; _,._`\. : `T"5, ; + : `?8w7 `J ,-'" -^q. ` ; + \;._ _,=' ; n58L Y. .' + F;"; .' k_ `^' j' ; + J;:: ; "y:-=' ; + L;;== |:; jT\ ; + L;:;J J:L 7:;' _ ; + I;|:.L |:k J:.' , ' . ; + |;J:.| ;.I F.: . : + ;J;:L:: |.| |.J , ' ` ; ; + .' J:`J.`. :.J |. L . ; ; + ; L :k:`._ ,',j J; | ` , ; ; + .' I :`=.:."_".' L J `.' + .' |.: `"-=-' |.J ; + _.-' `: : ;:; _ ; + _.-'" J: : /.;' ; ; + ='_ k;.\. _.;:Y' , .' + `"---..__ `Y;."-=';:=' , .' + `""--..__ `"==="' - .' + ``""---...__ itz .-' + ``""---' +""" + +from . import core +from .core import * +from . import storage +from .storage import * + +core.set_up("") + +def build_model(program, formulae): + intermediate = core._build_model(program, formulae) + assert not intermediate.supports_parameters + if intermediate.model_type == ModelType.DTMC: + return intermediate.as_dtmc() + elif intermediate.model_type == ModelType.MDP: + return intermediate.as_mdp() + else: + raise RuntimeError("Not supported non-parametric model constructed") + +def build_parametric_model(program, formulae): + intermediate = core._build_parametric_model(program, formulae) + assert intermediate.supports_parameters + if intermediate.model_type == ModelType.DTMC: + return intermediate.as_pdtmc() + elif intermediate.model_type == ModelType.MDP: + return intermediate.as_pmdp() + else: + raise RuntimeError("Not supported parametric model constructed") + +def perform_bisimulation(model, formula, bisimulation_type): + if model.supports_parameters: + return core._perform_parametric_bisimulation(model, formula, bisimulation_type) + else: + return core._perform_bisimulation(model, formula, bisimulation_type) + +def model_checking(model, formula): + if model.supports_parameters: + return core._parametric_model_checking(model, formula) + else: + return core._model_checking(model, formula) diff --git a/lib/stormpy/expressions/__init__.py b/lib/stormpy/expressions/__init__.py new file mode 100644 index 0000000..b185f36 --- /dev/null +++ b/lib/stormpy/expressions/__init__.py @@ -0,0 +1,2 @@ +from . import expressions +from .expressions import * diff --git a/lib/stormpy/info/__init__.py b/lib/stormpy/info/__init__.py new file mode 100644 index 0000000..d8e3cfa --- /dev/null +++ b/lib/stormpy/info/__init__.py @@ -0,0 +1,2 @@ +from . import info +from .info import * diff --git a/lib/stormpy/logic/__init__.py b/lib/stormpy/logic/__init__.py new file mode 100644 index 0000000..9ab7620 --- /dev/null +++ b/lib/stormpy/logic/__init__.py @@ -0,0 +1,2 @@ +from . import logic +from .logic import * diff --git a/lib/stormpy/storage/__init__.py b/lib/stormpy/storage/__init__.py new file mode 100644 index 0000000..c68800f --- /dev/null +++ b/lib/stormpy/storage/__init__.py @@ -0,0 +1,3 @@ +from . import storage +from .storage import * +from . import state,action diff --git a/lib/stormpy/storage/action.py b/lib/stormpy/storage/action.py new file mode 100644 index 0000000..420f5b3 --- /dev/null +++ b/lib/stormpy/storage/action.py @@ -0,0 +1,36 @@ +class Action: + """ Represents an action in the model """ + + def __init__(self, row_group_start, row_group_end, row, model): + """ Initialize + :param row_group_start: Start index of the row group in the matrix + :param row_group_end: End index of the row group in the matrix + :param row: Index of the corresponding row in the matrix + :param model: Corresponding model + """ + self.row_group_start = row_group_start + self.row_group_end = row_group_end + self.row = row - 1 + self.model = model + assert row >= -1 and row + row_group_start <= row_group_end + + def __iter__(self): + return self + + def __next__(self): + if self.row + self.row_group_start >= self.row_group_end - 1: + raise StopIteration + else: + self.row += 1 + return self + + def __str__(self): + return "{}".format(self.row) + + def transitions(self): + """ Get transitions associated with the action + :return List of tranistions + """ + row = self.row_group_start + self.row + #return self.model.transition_matrix().get_row(self.row_group_start + self.row) + return self.model.transition_matrix.row_iter(row, row) diff --git a/lib/stormpy/storage/state.py b/lib/stormpy/storage/state.py new file mode 100644 index 0000000..6a315e7 --- /dev/null +++ b/lib/stormpy/storage/state.py @@ -0,0 +1,34 @@ +from . import action + +class State: + """ Represents a state in the model """ + + def __init__(self, id, model): + """ Initialize + :param id: Id of the state + :param model: Corresponding model + """ + self.id = id - 1 + self.model = model + + def __iter__(self): + return self + + def __next__(self): + if self.id >= self.model.nr_states - 1: + raise StopIteration + else: + self.id += 1 + return self + + def __str__(self): + return "{}".format(self.id) + + def actions(self): + """ Get actions associated with the state + :return List of actions + """ + row_group_indices = self.model.transition_matrix._row_group_indices + start = row_group_indices[self.id] + end = row_group_indices[self.id+1] + return action.Action(start, end, 0, self.model) diff --git a/resources/pybind11/.appveyor.yml b/resources/pybind11/.appveyor.yml new file mode 100644 index 0000000..c657858 --- /dev/null +++ b/resources/pybind11/.appveyor.yml @@ -0,0 +1,32 @@ +version: 1.0.{build} +os: Visual Studio 2015 +test: off +platform: +- x86 +- x64 +environment: + matrix: + - CONDA: 27 + - CONDA: 35 +install: +- ps: | + if ($env:PLATFORM -eq "x64") { $env:CMAKE_ARCH = "x64" } + if ($env:PYTHON) { + if ($env:PLATFORM -eq "x64") { $env:PYTHON = "$env:PYTHON-x64" } + $env:PATH = "C:\Python$env:PYTHON\;C:\Python$env:PYTHON\Scripts\;$env:PATH" + pip install --disable-pip-version-check --user --upgrade pip wheel + pip install pytest numpy scipy + } elseif ($env:CONDA) { + if ($env:CONDA -eq "27") { $env:CONDA = "" } + if ($env:PLATFORM -eq "x64") { $env:CONDA = "$env:CONDA-x64" } + $env:PATH = "C:\Miniconda$env:CONDA\;C:\Miniconda$env:CONDA\Scripts\;$env:PATH" + conda install -y -q pytest numpy scipy + } +- ps: | + Start-FileDownload 'http://bitbucket.org/eigen/eigen/get/3.3.0.zip' + 7z x 3.3.0.zip -y > $null + $env:CMAKE_INCLUDE_PATH = "eigen-eigen-26667be4f70b" +build_script: +- cmake -A "%CMAKE_ARCH%" -DPYBIND11_WERROR=ON +- set MSBuildLogger="C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" +- cmake --build . --config Release --target pytest -- /v:m /logger:%MSBuildLogger% diff --git a/resources/pybind11/.gitignore b/resources/pybind11/.gitignore new file mode 100644 index 0000000..4df6229 --- /dev/null +++ b/resources/pybind11/.gitignore @@ -0,0 +1,35 @@ +CMakeCache.txt +CMakeFiles +Makefile +cmake_install.cmake +.DS_Store +*.so +*.pyd +*.dll +*.sln +*.sdf +*.opensdf +*.vcxproj +*.filters +example.dir +Win32 +x64 +Release +Debug +.vs +CTestTestfile.cmake +Testing +autogen +MANIFEST +/.ninja_* +/*.ninja +/docs/.build +*.py[co] +*.egg-info +*~ +.DS_Store +/dist +/build +/cmake/ +.cache/ +sosize-*.txt diff --git a/resources/pybind11/.gitmodules b/resources/pybind11/.gitmodules new file mode 100644 index 0000000..5191885 --- /dev/null +++ b/resources/pybind11/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tools/clang"] + path = tools/clang + url = https://github.com/wjakob/clang-cindex-python3 diff --git a/resources/pybind11/.travis.yml b/resources/pybind11/.travis.yml new file mode 100644 index 0000000..ff4662f --- /dev/null +++ b/resources/pybind11/.travis.yml @@ -0,0 +1,112 @@ +language: cpp +sudo: false +matrix: + include: + - os: linux + env: PYTHON=2.7 CPP=11 GCC=4.8 + addons: + apt: + sources: [ubuntu-toolchain-r-test, kubuntu-backports] + packages: [g++-4.8, cmake] + - os: linux + env: PYTHON=3.5 CPP=11 GCC=4.8 + addons: + apt: + sources: [ubuntu-toolchain-r-test, kubuntu-backports, deadsnakes] + packages: [g++-4.8, cmake, python3.5-dev] + - sudo: true + services: docker + env: PYTHON=2.7 CPP=14 GCC=6 + - sudo: true + services: docker + env: PYTHON=3.5 CPP=14 GCC=6 DEBUG=1 + - os: osx + osx_image: xcode7.3 + env: PYTHON=2.7 CPP=14 CLANG + - os: osx + osx_image: xcode7.3 + env: PYTHON=3.5 CPP=14 CLANG + # A barebones build makes sure everything still works without optional deps (numpy/scipy/eigen) + # and also tests the automatic discovery functions in CMake (Python version, C++ standard). + - os: linux + env: BAREBONES + addons: + apt: + sources: [ubuntu-toolchain-r-test, kubuntu-backports] + packages: [g++-4.8, cmake] + install: pip install pytest + # Documentation build: + - os: linux + language: docs + env: DOCS STYLE LINT + install: pip install sphinx sphinx_rtd_theme flake8 pep8-naming + script: + - make -C docs html SPHINX_OPTIONS=-W + - tools/check-style.sh + - flake8 +cache: + directories: + - $HOME/.cache/pip + - $HOME/Library/Caches/pip +before_install: +- | + # Configure build variables + if [ "$TRAVIS_OS_NAME" = "linux" ]; then + if [ -z "$GCC" ]; then export GCC=4.8; fi + export CXX=g++-$GCC CC=gcc-$GCC; + if [ "$GCC" = "6" ]; then export DOCKER=debian:testing CXX=g++ CC=gcc; fi + elif [ "$TRAVIS_OS_NAME" = "osx" ]; then + export CXX=clang++ CC=clang; + fi + if [ -n "$CPP" ]; then export CPP=-std=c++$CPP; fi + if [ "${PYTHON:0:1}" = "3" ]; then export PY=3; fi + if [ -n "$DEBUG" ]; then export CMAKE_EXTRA_ARGS="-DCMAKE_BUILD_TYPE=Debug"; fi +- | + # Initialize enviornment + if [ -n "$DOCKER" ]; then + docker pull $DOCKER + export containerid=$(docker run --detach --tty \ + --volume="$PWD":/pybind11 --workdir=/pybind11 \ + --env="CC=$CC" --env="CXX=$CXX" --env="DEBIAN_FRONTEND=$DEBIAN_FRONTEND" \ + --env=GCC_COLORS=\ \ + $DOCKER) + docker exec --tty "$containerid" sh -c 'for s in 0 15; do sleep $s; apt-get update && apt-get -qy dist-upgrade && break; done' + export SCRIPT_RUN_PREFIX="docker exec --tty $containerid" + else + if [ "$TRAVIS_OS_NAME" = "linux" ]; then + pip install --user --upgrade pip virtualenv + virtualenv -p python$PYTHON venv + elif [ "$TRAVIS_OS_NAME" = "osx" ]; then + if [ "$PY" = "3" ]; then + brew update; brew install python$PY; + else + curl -fsSL -O https://bootstrap.pypa.io/get-pip.py + sudo -H python get-pip.py + fi + pip$PY install --user --upgrade pip virtualenv + python$PY -m virtualenv venv + fi + source venv/bin/activate + fi +install: +- | + # Install dependencies + if [ -n "$DOCKER" ]; then + docker exec --tty "$containerid" sh -c "for s in 0 15; do sleep \$s; apt-get -qy --no-install-recommends install \ + python$PYTHON-dev python$PY-pytest python$PY-scipy \ + libeigen3-dev cmake make g++ && break; done" + else + pip install numpy scipy pytest + + wget -q -O eigen.tar.gz https://bitbucket.org/eigen/eigen/get/3.3.0.tar.gz + tar xzf eigen.tar.gz + export CMAKE_EXTRA_ARGS="${CMAKE_EXTRA_ARGS} -DCMAKE_INCLUDE_PATH=$PWD/eigen-eigen-26667be4f70b" + fi +script: +- $SCRIPT_RUN_PREFIX cmake ${CMAKE_EXTRA_ARGS} + -DPYBIND11_PYTHON_VERSION=$PYTHON + -DPYBIND11_CPP_STANDARD=$CPP + -DPYBIND11_WERROR=ON +- $SCRIPT_RUN_PREFIX make pytest -j 2 +after_script: +- if [ -n "$DOCKER" ]; then docker stop "$containerid"; docker rm "$containerid"; fi diff --git a/resources/pybind11/CMakeLists.txt b/resources/pybind11/CMakeLists.txt new file mode 100755 index 0000000..6aa2bea --- /dev/null +++ b/resources/pybind11/CMakeLists.txt @@ -0,0 +1,184 @@ +# CMakeLists.txt -- Build system for the pybind11 modules +# +# Copyright (c) 2015 Wenzel Jakob +# +# All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +cmake_minimum_required(VERSION 2.8.12) + +project(pybind11) + +# Check if pybind11 is being used directly or via add_subdirectory +set(PYBIND11_MASTER_PROJECT OFF) +if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(PYBIND11_MASTER_PROJECT ON) +endif() + +option(PYBIND11_INSTALL "Install pybind11 header files?" ${PYBIND11_MASTER_PROJECT}) +option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJECT}) +option(PYBIND11_WERROR "Report all warnings as errors" OFF) + +# Add a CMake parameter for choosing a desired Python version +set(PYBIND11_PYTHON_VERSION "" CACHE STRING "Python version to use for compiling modules") + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/tools") +set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6 3.7) +find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} REQUIRED) + +include(CheckCXXCompilerFlag) + +if(NOT MSVC AND NOT PYBIND11_CPP_STANDARD) + check_cxx_compiler_flag("-std=c++14" HAS_CPP14_FLAG) + check_cxx_compiler_flag("-std=c++11" HAS_CPP11_FLAG) + + if (HAS_CPP14_FLAG) + set(PYBIND11_CPP_STANDARD -std=c++14) + elseif (HAS_CPP11_FLAG) + set(PYBIND11_CPP_STANDARD -std=c++11) + else() + message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!") + endif() + + set(PYBIND11_CPP_STANDARD ${PYBIND11_CPP_STANDARD} CACHE STRING + "C++ standard flag, e.g. -std=c++11 or -std=c++14. Defaults to latest available." FORCE) +endif() + +# Cache variables so pybind11_add_module can be used in parent projects +set(PYBIND11_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/include" CACHE INTERNAL "") +set(PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS} CACHE INTERNAL "") +set(PYTHON_LIBRARIES ${PYTHON_LIBRARIES} CACHE INTERNAL "") +set(PYTHON_MODULE_PREFIX ${PYTHON_MODULE_PREFIX} CACHE INTERNAL "") +set(PYTHON_MODULE_EXTENSION ${PYTHON_MODULE_EXTENSION} CACHE INTERNAL "") + +# Build a Python extension module: +# pybind11_add_module( source1 [source2 ...]) +# +function(pybind11_add_module target_name) + add_library(${target_name} MODULE ${ARGN}) + target_include_directories(${target_name} + PRIVATE ${PYBIND11_INCLUDE_DIR} + PRIVATE ${PYTHON_INCLUDE_DIRS}) + + # The prefix and extension are provided by FindPythonLibsNew.cmake + set_target_properties(${target_name} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}") + set_target_properties(${target_name} PROPERTIES SUFFIX "${PYTHON_MODULE_EXTENSION}") + + if(WIN32 OR CYGWIN) + # Link against the Python shared library on Windows + target_link_libraries(${target_name} PRIVATE ${PYTHON_LIBRARIES}) + elseif(APPLE) + # It's quite common to have multiple copies of the same Python version + # installed on one's system. E.g.: one copy from the OS and another copy + # that's statically linked into an application like Blender or Maya. + # If we link our plugin library against the OS Python here and import it + # into Blender or Maya later on, this will cause segfaults when multiple + # conflicting Python instances are active at the same time (even when they + # are of the same version). + + # Windows is not affected by this issue since it handles DLL imports + # differently. The solution for Linux and Mac OS is simple: we just don't + # link against the Python library. The resulting shared library will have + # missing symbols, but that's perfectly fine -- they will be resolved at + # import time. + + target_link_libraries(${target_name} PRIVATE "-undefined dynamic_lookup") + endif() + + if(NOT MSVC) + # Make sure C++11/14 are enabled + target_compile_options(${target_name} PUBLIC ${PYBIND11_CPP_STANDARD}) + + # Enable link time optimization and set the default symbol + # visibility to hidden (very important to obtain small binaries) + string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) + if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG) + # Check for Link Time Optimization support (GCC/Clang) + check_cxx_compiler_flag("-flto" HAS_LTO_FLAG) + if(HAS_LTO_FLAG AND NOT CYGWIN) + target_compile_options(${target_name} PRIVATE -flto) + endif() + + # Intel equivalent to LTO is called IPO + if(CMAKE_CXX_COMPILER_ID MATCHES "Intel") + check_cxx_compiler_flag("-ipo" HAS_IPO_FLAG) + if(HAS_IPO_FLAG) + target_compile_options(${target_name} PRIVATE -ipo) + endif() + endif() + + # Default symbol visibility + target_compile_options(${target_name} PRIVATE "-fvisibility=hidden") + + # Strip unnecessary sections of the binary on Linux/Mac OS + if(CMAKE_STRIP) + if(APPLE) + add_custom_command(TARGET ${target_name} POST_BUILD + COMMAND ${CMAKE_STRIP} -u -r $) + else() + add_custom_command(TARGET ${target_name} POST_BUILD + COMMAND ${CMAKE_STRIP} $) + endif() + endif() + endif() + elseif(MSVC) + # /MP enables multithreaded builds (relevant when there are many files), /bigobj is + # needed for bigger binding projects due to the limit to 64k addressable sections + target_compile_options(${target_name} PRIVATE /MP /bigobj) + + # Enforce link time code generation on MSVC, except in debug mode + target_compile_options(${target_name} PRIVATE $<$>:/GL>) + + # Fancy generator expressions don't work with linker flags, for reasons unknown + set_property(TARGET ${target_name} APPEND_STRING PROPERTY LINK_FLAGS_RELEASE /LTCG) + set_property(TARGET ${target_name} APPEND_STRING PROPERTY LINK_FLAGS_MINSIZEREL /LTCG) + set_property(TARGET ${target_name} APPEND_STRING PROPERTY LINK_FLAGS_RELWITHDEBINFO /LTCG) + endif() +endfunction() + +# Compile with compiler warnings turned on +function(pybind11_enable_warnings target_name) + if(MSVC) + target_compile_options(${target_name} PRIVATE /W4) + else() + target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion) + endif() + + if(PYBIND11_WERROR) + if(MSVC) + target_compile_options(${target_name} PRIVATE /WX) + else() + target_compile_options(${target_name} PRIVATE -Werror) + endif() + endif() +endfunction() + +set(PYBIND11_HEADERS + include/pybind11/attr.h + include/pybind11/cast.h + include/pybind11/chrono.h + include/pybind11/common.h + include/pybind11/complex.h + include/pybind11/descr.h + include/pybind11/options.h + include/pybind11/eigen.h + include/pybind11/eval.h + include/pybind11/functional.h + include/pybind11/numpy.h + include/pybind11/operators.h + include/pybind11/pybind11.h + include/pybind11/pytypes.h + include/pybind11/stl.h + include/pybind11/stl_bind.h + include/pybind11/typeid.h +) +string(REPLACE "include/" "${CMAKE_CURRENT_SOURCE_DIR}/include/" + PYBIND11_HEADERS "${PYBIND11_HEADERS}") + +if (PYBIND11_TEST) + add_subdirectory(tests) +endif() + +if (PYBIND11_INSTALL) + install(FILES ${PYBIND11_HEADERS} DESTINATION include/pybind11) +endif() diff --git a/resources/pybind11/CONTRIBUTING.md b/resources/pybind11/CONTRIBUTING.md new file mode 100755 index 0000000..2beaf8d --- /dev/null +++ b/resources/pybind11/CONTRIBUTING.md @@ -0,0 +1,37 @@ +Thank you for your interest in this project! Please refer to the following +sections on how to contribute code and bug reports. + +### Reporting bugs + +At the moment, this project is run in the spare time of a single person +([Wenzel Jakob](http://rgl.epfl.ch/people/wjakob)) with very limited resources +for issue tracker tickets. Thus, before submitting a question or bug report, +please take a moment of your time and ensure that your issue isn't already +discussed in the project documentation provided at +[http://pybind11.readthedocs.org/en/latest](http://pybind11.readthedocs.org/en/latest). + +Assuming that you have identified a previously unknown problem or an important +question, it's essential that you submit a self-contained and minimal piece of +code that reproduces the problem. In other words: no external dependencies, +isolate the function(s) that cause breakage, submit matched and complete C++ +and Python snippets that can be easily compiled and run on my end. + +## Pull requests +Contributions are submitted, reviewed, and accepted using Github pull requests. +Please refer to [this +article](https://help.github.com/articles/using-pull-requests) for details and +adhere to the following rules to make the process as smooth as possible: + +* Make a new branch for every feature you're working on. +* Make small and clean pull requests that are easy to review but make sure they + do add value by themselves. +* Add tests for any new functionality and run the test suite (``make pytest``) + to ensure that no existing features break. +* This project has a strong focus on providing general solutions using a + minimal amount of code, thus small pull requests are greatly preferred. + +### License + +pybind11 is provided under a BSD-style license that can be found in the +``LICENSE`` file. By using, distributing, or contributing to this project, you +agree to the terms and conditions of this license. diff --git a/resources/pybind11/LICENSE b/resources/pybind11/LICENSE new file mode 100755 index 0000000..ccf4e97 --- /dev/null +++ b/resources/pybind11/LICENSE @@ -0,0 +1,36 @@ +Copyright (c) 2016 Wenzel Jakob , All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. 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. + +3. Neither the name of the copyright holder nor the names of its 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. + +You are under no obligation whatsoever to provide any bug fixes, patches, or +upgrades to the features, functionality or performance of the source code +("Enhancements") to anyone; however, if you choose to make your Enhancements +available either publicly, or directly to the author of this software, without +imposing a separate written license agreement for such Enhancements, then you +hereby grant the following license: a non-exclusive, royalty-free perpetual +license to install, use, modify, prepare derivative works, incorporate into +other computer software, distribute, and sublicense such enhancements or +derivative works thereof, in binary and source code form. diff --git a/resources/pybind11/MANIFEST.in b/resources/pybind11/MANIFEST.in new file mode 100755 index 0000000..aa51d01 --- /dev/null +++ b/resources/pybind11/MANIFEST.in @@ -0,0 +1,2 @@ +include include/pybind11/*.h +include LICENSE README.md CONTRIBUTING.md diff --git a/resources/pybind11/README.md b/resources/pybind11/README.md new file mode 100755 index 0000000..9d4827a --- /dev/null +++ b/resources/pybind11/README.md @@ -0,0 +1,123 @@ +![pybind11 logo](https://github.com/pybind/pybind11/raw/master/docs/pybind11-logo.png) + +# pybind11 — Seamless operability between C++11 and Python + +[![Documentation Status](https://readthedocs.org/projects/pybind11/badge/?version=latest)](http://pybind11.readthedocs.org/en/latest/?badge=latest) +[![Build Status](https://travis-ci.org/pybind/pybind11.svg?branch=master)](https://travis-ci.org/pybind/pybind11) +[![Build status](https://ci.appveyor.com/api/projects/status/riaj54pn4h08xy40?svg=true)](https://ci.appveyor.com/project/wjakob/pybind11) + +**pybind11** is a lightweight header-only library that exposes C++ types in Python +and vice versa, mainly to create Python bindings of existing C++ code. Its +goals and syntax are similar to the excellent +[Boost.Python](http://www.boost.org/doc/libs/1_58_0/libs/python/doc/) library +by David Abrahams: to minimize boilerplate code in traditional extension +modules by inferring type information using compile-time introspection. + +The main issue with Boost.Python—and the reason for creating such a similar +project—is Boost. Boost is an enormously large and complex suite of utility +libraries that works with almost every C++ compiler in existence. This +compatibility has its cost: arcane template tricks and workarounds are +necessary to support the oldest and buggiest of compiler specimens. Now that +C++11-compatible compilers are widely available, this heavy machinery has +become an excessively large and unnecessary dependency. + +Think of this library as a tiny self-contained version of Boost.Python with +everything stripped away that isn't relevant for binding generation. Without +comments, the core header files only require ~2.5K lines of code and depend 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 (specifically: +tuples, lambda functions and variadic templates). Since its creation, this +library has grown beyond Boost.Python in many ways, leading to dramatically +simpler binding code in many common situations. + +Tutorial and reference documentation is provided at +[http://pybind11.readthedocs.org/en/latest](http://pybind11.readthedocs.org/en/latest). +A PDF version of the manual is available +[here](https://media.readthedocs.org/pdf/pybind11/latest/pybind11.pdf). + +## Core features +pybind11 can map the following core C++ features to Python + +- Functions accepting and returning custom data structures per value, reference, or pointer +- Instance methods and static methods +- Overloaded functions +- Instance attributes and static attributes +- Arbitrary exception types +- Enumerations +- Callbacks +- Iterators and ranges +- Custom operators +- Single and multiple inheritance +- STL data structures +- Iterators and ranges +- Smart pointers with reference counting like ``std::shared_ptr`` +- Internal references with correct reference counting +- C++ classes with virtual (and pure virtual) methods can be extended in Python + +## Goodies +In addition to the core functionality, pybind11 provides some extra goodies: + +- pybind11 uses C++11 move constructors and move assignment operators whenever + possible to efficiently transfer custom data types. + +- It is possible to bind C++11 lambda functions with captured variables. The + lambda capture data is stored inside the resulting Python function object. + +- It's easy to expose the internal storage of custom data types through + Pythons' buffer protocols. This is handy e.g. for fast conversion between + C++ matrix classes like Eigen and NumPy without expensive copy operations. + +- pybind11 can automatically vectorize functions so that they are transparently + applied to all entries of one or more NumPy array arguments. + +- Python's slice-based access and assignment operations can be supported with + just a few lines of code. + +- Everything is contained in just a few header files; there is no need to link + against any additional libraries. + +- Binaries are generally smaller by a factor of at least 2 compared to + equivalent bindings generated by Boost.Python. A recent pybind11 conversion + of PyRosetta, an enormous Boost.Python binding project, + [reported](http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf) a binary + size reduction of **5.4x** and compile time reduction by **5.8x**. + +- When supported by the compiler, two new C++14 features (relaxed constexpr and + return value deduction) are used to precompute function signatures at compile + time, leading to smaller binaries. + +- With little extra effort, C++ types can be pickled and unpickled similar to + regular Python objects. + +## Supported compilers + +1. Clang/LLVM (any non-ancient version with C++11 support) +2. GCC (any non-ancient version with C++11 support) +3. Microsoft Visual Studio 2015 or newer +4. Intel C++ compiler 16 or newer (15 with a [workaround](https://github.com/pybind/pybind11/issues/276)) +5. Cygwin/GCC (tested on 2.5.1) + +## About + +This project was created by [Wenzel Jakob](https://www.mitsuba-renderer.org/~wenzel/). +Significant features and/or improvements to the code were contributed by +Jonas Adler, +Sylvain Corlay, +Trent Houliston, +Axel Huebl, +@hulucc, +Sergey Lyskov +Johan Mabille, +Tomasz Miąsko, +Dean Moldovan, +Ben Pritchard, +Jason Rhinelander, +Boris Schäling, +Pim Schellart, and +Ivan Smirnov. + +### License + +pybind11 is provided under a BSD-style license that can be found in the +``LICENSE`` file. By using, distributing, or contributing to this project, +you agree to the terms and conditions of this license. diff --git a/resources/pybind11/docs/_static/theme_overrides.css b/resources/pybind11/docs/_static/theme_overrides.css new file mode 100755 index 0000000..1071809 --- /dev/null +++ b/resources/pybind11/docs/_static/theme_overrides.css @@ -0,0 +1,11 @@ +.wy-table-responsive table td, +.wy-table-responsive table th { + white-space: initial !important; +} +.rst-content table.docutils td { + vertical-align: top !important; +} +div[class^='highlight'] pre { + white-space: pre; + white-space: pre-wrap; +} diff --git a/resources/pybind11/docs/advanced/cast/chrono.rst b/resources/pybind11/docs/advanced/cast/chrono.rst new file mode 100755 index 0000000..6d4a5ee --- /dev/null +++ b/resources/pybind11/docs/advanced/cast/chrono.rst @@ -0,0 +1,81 @@ +Chrono +====== + +When including the additional header file :file:`pybind11/chrono.h` conversions +from C++11 chrono datatypes to python datetime objects are automatically enabled. +This header also enables conversions of python floats (often from sources such +as `time.monotonic()`, `time.perf_counter()` and `time.process_time()`) into +durations. + +An overview of clocks in C++11 +------------------------------ + +A point of confusion when using these conversions is the differences between +clocks provided in C++11. There are three clock types defined by the C++11 +standard and users can define their own if needed. Each of these clocks have +different properties and when converting to and from python will give different +results. + +The first clock defined by the standard is ``std::chrono::system_clock``. This +clock measures the current date and time. However, this clock changes with to +updates to the operating system time. For example, if your time is synchronised +with a time server this clock will change. This makes this clock a poor choice +for timing purposes but good for measuring the wall time. + +The second clock defined in the standard is ``std::chrono::steady_clock``. +This clock ticks at a steady rate and is never adjusted. This makes it excellent +for timing purposes, however the value in this clock does not correspond to the +current date and time. Often this clock will be the amount of time your system +has been on, although it does not have to be. This clock will never be the same +clock as the system clock as the system clock can change but steady clocks +cannot. + +The third clock defined in the standard is ``std::chrono::high_resolution_clock``. +This clock is the clock that has the highest resolution out of the clocks in the +system. It is normally a typedef to either the system clock or the steady clock +but can be its own independent clock. This is important as when using these +conversions as the types you get in python for this clock might be different +depending on the system. +If it is a typedef of the system clock, python will get datetime objects, but if +it is a different clock they will be timedelta objects. + +Provided conversions +-------------------- + +.. rubric:: C++ to Python + +- ``std::chrono::system_clock::time_point`` → ``datetime.datetime`` + System clock times are converted to python datetime instances. They are + in the local timezone, but do not have any timezone information attached + to them (they are naive datetime objects). + +- ``std::chrono::duration`` → ``datetime.timedelta`` + Durations are converted to timedeltas, any precision in the duration + greater than microseconds is lost by rounding towards zero. + +- ``std::chrono::[other_clocks]::time_point`` → ``datetime.timedelta`` + Any clock time that is not the system clock is converted to a time delta. + This timedelta measures the time from the clocks epoch to now. + +.. rubric:: Python to C++ + +- ``datetime.datetime`` → ``std::chrono::system_clock::time_point`` + Date/time objects are converted into system clock timepoints. Any + timezone information is ignored and the type is treated as a naive + object. + +- ``datetime.timedelta`` → ``std::chrono::duration`` + Time delta are converted into durations with microsecond precision. + +- ``datetime.timedelta`` → ``std::chrono::[other_clocks]::time_point`` + Time deltas that are converted into clock timepoints are treated as + the amount of time from the start of the clocks epoch. + +- ``float`` → ``std::chrono::duration`` + Floats that are passed to C++ as durations be interpreted as a number of + seconds. These will be converted to the duration using ``duration_cast`` + from the float. + +- ``float`` → ``std::chrono::[other_clocks]::time_point`` + Floats that are passed to C++ as time points will be interpreted as the + number of seconds from the start of the clocks epoch. diff --git a/resources/pybind11/docs/advanced/cast/custom.rst b/resources/pybind11/docs/advanced/cast/custom.rst new file mode 100755 index 0000000..c854e7f --- /dev/null +++ b/resources/pybind11/docs/advanced/cast/custom.rst @@ -0,0 +1,85 @@ +Custom type casters +=================== + +In very rare cases, applications may require custom type casters that cannot be +expressed using the abstractions provided by pybind11, thus requiring raw +Python C API calls. This is fairly advanced usage and should only be pursued by +experts who are familiar with the intricacies of Python reference counting. + +The following snippets demonstrate how this works for a very simple ``inty`` +type that that should be convertible from Python types that provide a +``__int__(self)`` method. + +.. code-block:: cpp + + struct inty { long long_value; }; + + void print(inty s) { + std::cout << s.long_value << std::endl; + } + +The following Python snippet demonstrates the intended usage from the Python side: + +.. code-block:: python + + class A: + def __int__(self): + return 123 + + from example import print + print(A()) + +To register the necessary conversion routines, it is necessary to add +a partial overload to the ``pybind11::detail::type_caster`` template. +Although this is an implementation detail, adding partial overloads to this +type is explicitly allowed. + +.. code-block:: cpp + + namespace pybind11 { namespace detail { + template <> struct type_caster { + public: + /** + * This macro establishes the name 'inty' in + * function signatures and declares a local variable + * 'value' of type inty + */ + PYBIND11_TYPE_CASTER(inty, _("inty")); + + /** + * Conversion part 1 (Python->C++): convert a PyObject into a inty + * instance or return false upon failure. The second argument + * indicates whether implicit conversions should be applied. + */ + bool load(handle src, bool) { + /* Extract PyObject from handle */ + PyObject *source = src.ptr(); + /* Try converting into a Python integer value */ + PyObject *tmp = PyNumber_Long(source); + if (!tmp) + return false; + /* Now try to convert into a C++ int */ + value.long_value = PyLong_AsLong(tmp); + Py_DECREF(tmp); + /* Ensure return code was OK (to avoid out-of-range errors etc) */ + return !(value.long_value == -1 && !PyErr_Occurred()); + } + + /** + * Conversion part 2 (C++ -> Python): convert an inty instance into + * a Python object. The second and third arguments are used to + * indicate the return value policy and parent object (for + * ``return_value_policy::reference_internal``) and are generally + * ignored by implicit casters. + */ + static handle cast(inty src, return_value_policy /* policy */, handle /* parent */) { + return PyLong_FromLong(src.long_value); + } + }; + }} // namespace pybind11::detail + +.. warning:: + + When using custom type casters, it's important to declare them consistently + in every compilation unit of the Python extension module. Otherwise, + undefined behavior can ensue. diff --git a/resources/pybind11/docs/advanced/cast/eigen.rst b/resources/pybind11/docs/advanced/cast/eigen.rst new file mode 100755 index 0000000..b83ca9a --- /dev/null +++ b/resources/pybind11/docs/advanced/cast/eigen.rst @@ -0,0 +1,50 @@ +Eigen +===== + +`Eigen `_ is C++ header-based library for dense and +sparse linear algebra. Due to its popularity and widespread adoption, pybind11 +provides transparent conversion support between Eigen and Scientific Python linear +algebra data types. + +Specifically, when including the optional header file :file:`pybind11/eigen.h`, +pybind11 will automatically and transparently convert + +1. Static and dynamic Eigen dense vectors and matrices to instances of + ``numpy.ndarray`` (and vice versa). + +2. Returned matrix expressions such as blocks (including columns or rows) and + diagonals will be converted to ``numpy.ndarray`` of the expression + values. + +3. Returned matrix-like objects such as Eigen::DiagonalMatrix or + Eigen::SelfAdjointView will be converted to ``numpy.ndarray`` containing the + expressed value. + +4. Eigen sparse vectors and matrices to instances of + ``scipy.sparse.csr_matrix``/``scipy.sparse.csc_matrix`` (and vice versa). + +This makes it possible to bind most kinds of functions that rely on these types. +One major caveat are functions that take Eigen matrices *by reference* and modify +them somehow, in which case the information won't be propagated to the caller. + +.. code-block:: cpp + + /* The Python bindings of these functions won't replicate + the intended effect of modifying the function arguments */ + void scale_by_2(Eigen::Vector3f &v) { + v *= 2; + } + void scale_by_2(Eigen::Ref &v) { + v *= 2; + } + +To see why this is, refer to the section on :ref:`opaque` (although that +section specifically covers STL data types, the underlying issue is the same). +The :ref:`numpy` sections discuss an efficient alternative for exposing the +underlying native Eigen types as opaque objects in a way that still integrates +with NumPy and SciPy. + +.. seealso:: + + The file :file:`tests/test_eigen.cpp` contains a complete example that + shows how to pass Eigen sparse and dense data types in more detail. diff --git a/resources/pybind11/docs/advanced/cast/functional.rst b/resources/pybind11/docs/advanced/cast/functional.rst new file mode 100755 index 0000000..5d0a01d --- /dev/null +++ b/resources/pybind11/docs/advanced/cast/functional.rst @@ -0,0 +1,113 @@ +Functional +########## + +The following features must be enabled by including :file:`pybind11/functional.h`. + + +Callbacks and passing anonymous functions +========================================= + +The C++11 standard brought lambda functions and the generic polymorphic +function wrapper ``std::function<>`` to the C++ programming language, which +enable powerful new ways of working with functions. Lambda functions come in +two flavors: stateless lambda function resemble classic function pointers that +link to an anonymous piece of code, while stateful lambda functions +additionally depend on captured variables that are stored in an anonymous +*lambda closure object*. + +Here is a simple example of a C++ function that takes an arbitrary function +(stateful or stateless) with signature ``int -> int`` as an argument and runs +it with the value 10. + +.. code-block:: cpp + + int func_arg(const std::function &f) { + return f(10); + } + +The example below is more involved: it takes a function of signature ``int -> int`` +and returns another function of the same kind. The return value is a stateful +lambda function, which stores the value ``f`` in the capture object and adds 1 to +its return value upon execution. + +.. code-block:: cpp + + std::function func_ret(const std::function &f) { + return [f](int i) { + return f(i) + 1; + }; + } + +This example demonstrates using python named parameters in C++ callbacks which +requires using ``py::cpp_function`` as a wrapper. Usage is similar to defining +methods of classes: + +.. code-block:: cpp + + py::cpp_function func_cpp() { + return py::cpp_function([](int i) { return i+1; }, + py::arg("number")); + } + +After including the extra header file :file:`pybind11/functional.h`, it is almost +trivial to generate binding code for all of these functions. + +.. code-block:: cpp + + #include + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + m.def("func_arg", &func_arg); + m.def("func_ret", &func_ret); + m.def("func_cpp", &func_cpp); + + return m.ptr(); + } + +The following interactive session shows how to call them from Python. + +.. code-block:: pycon + + $ python + >>> import example + >>> def square(i): + ... return i * i + ... + >>> example.func_arg(square) + 100L + >>> square_plus_1 = example.func_ret(square) + >>> square_plus_1(4) + 17L + >>> plus_1 = func_cpp() + >>> plus_1(number=43) + 44L + +.. warning:: + + Keep in mind that passing a function from C++ to Python (or vice versa) + will instantiate a piece of wrapper code that translates function + invocations between the two languages. Naturally, this translation + increases the computational cost of each function call somewhat. A + problematic situation can arise when a function is copied back and forth + between Python and C++ many times in a row, in which case the underlying + wrappers will accumulate correspondingly. The resulting long sequence of + C++ -> Python -> C++ -> ... roundtrips can significantly decrease + performance. + + There is one exception: pybind11 detects case where a stateless function + (i.e. a function pointer or a lambda function without captured variables) + is passed as an argument to another C++ function exposed in Python. In this + case, there is no overhead. Pybind11 will extract the underlying C++ + function pointer from the wrapped function to sidestep a potential C++ -> + Python -> C++ roundtrip. This is demonstrated in :file:`tests/test_callbacks.cpp`. + +.. note:: + + This functionality is very useful when generating bindings for callbacks in + C++ libraries (e.g. GUI libraries, asynchronous networking libraries, etc.). + + The file :file:`tests/test_callbacks.cpp` contains a complete example + that demonstrates how to work with callbacks and anonymous functions in + more detail. diff --git a/resources/pybind11/docs/advanced/cast/index.rst b/resources/pybind11/docs/advanced/cast/index.rst new file mode 100755 index 0000000..36586af --- /dev/null +++ b/resources/pybind11/docs/advanced/cast/index.rst @@ -0,0 +1,41 @@ +Type conversions +################ + +Apart from enabling cross-language function calls, a fundamental problem +that a binding tool like pybind11 must address is to provide access to +native Python types in C++ and vice versa. There are three fundamentally +different ways to do this—which approach is preferable for a particular type +depends on the situation at hand. + +1. Use a native C++ type everywhere. In this case, the type must be wrapped + using pybind11-generated bindings so that Python can interact with it. + +2. Use a native Python type everywhere. It will need to be wrapped so that + C++ functions can interact with it. + +3. Use a native C++ type on the C++ side and a native Python type on the + Python side. pybind11 refers to this as a *type conversion*. + + Type conversions are the most "natural" option in the sense that native + (non-wrapped) types are used everywhere. The main downside is that a copy + of the data must be made on every Python ↔ C++ transition: this is + needed since the C++ and Python versions of the same type generally won't + have the same memory layout. + + pybind11 can perform many kinds of conversions automatically. An overview + is provided in the table ":ref:`conversion_table`". + +The following subsections discuss the differences between these options in more +detail. The main focus in this section is on type conversions, which represent +the last case of the above list. + +.. toctree:: + :maxdepth: 1 + + overview + stl + functional + chrono + eigen + custom + diff --git a/resources/pybind11/docs/advanced/cast/overview.rst b/resources/pybind11/docs/advanced/cast/overview.rst new file mode 100755 index 0000000..8408572 --- /dev/null +++ b/resources/pybind11/docs/advanced/cast/overview.rst @@ -0,0 +1,144 @@ +Overview +######## + +.. rubric:: 1. Native type in C++, wrapper in Python + +Exposing a custom C++ type using :class:`py::class_` was covered in detail +in the :doc:`/classes` section. There, the underlying data structure is +always the original C++ class while the :class:`py::class_` wrapper provides +a Python interface. Internally, when an object like this is sent from C++ to +Python, pybind11 will just add the outer wrapper layer over the native C++ +object. Getting it back from Python is just a matter of peeling off the +wrapper. + +.. rubric:: 2. Wrapper in C++, native type in Python + +This is the exact opposite situation. Now, we have a type which is native to +Python, like a ``tuple`` or a ``list``. One way to get this data into C++ is +with the :class:`py::object` family of wrappers. These are explained in more +detail in the :doc:`/advanced/pycpp/object` section. We'll just give a quick +example here: + +.. code-block:: cpp + + void print_list(py::list my_list) { + for (auto item : my_list) + std::cout << item << " "; + } + +.. code-block:: pycon + + >>> print_list([1, 2, 3]) + 1 2 3 + +The Python ``list`` is not converted in any way -- it's just wrapped in a C++ +:class:`py::list` class. At its core it's still a Python object. Copying a +:class:`py::list` will do the usual reference-counting like in Python. +Returning the object to Python will just remove the thin wrapper. + +.. rubric:: 3. Converting between native C++ and Python types + +In the previous two cases we had a native type in one language and a wrapper in +the other. Now, we have native types on both sides and we convert between them. + +.. code-block:: cpp + + void print_vector(const std::vector &v) { + for (auto item : v) + std::cout << item << "\n"; + } + +.. code-block:: pycon + + >>> print_vector([1, 2, 3]) + 1 2 3 + +In this case, pybind11 will construct a new ``std::vector`` and copy each +element from the Python ``list``. The newly constructed object will be passed +to ``print_vector``. The same thing happens in the other direction: a new +``list`` is made to match the value returned from C++. + +Lots of these conversions are supported out of the box, as shown in the table +below. They are very convenient, but keep in mind that these conversions are +fundamentally based on copying data. This is perfectly fine for small immutable +types but it may become quite expensive for large data structures. This can be +avoided by overriding the automatic conversion with a custom wrapper (i.e. the +above-mentioned approach 1). This requires some manual effort and more details +are available in the :ref:`opaque` section. + +.. _conversion_table: + +List of all builtin conversions +------------------------------- + +The following basic data types are supported out of the box (some may require +an additional extension header to be included). To pass other data structures +as arguments and return values, refer to the section on binding :ref:`classes`. + ++------------------------------------+---------------------------+-------------------------------+ +| Data type | Description | Header file | ++====================================+===========================+===============================+ +| ``int8_t``, ``uint8_t`` | 8-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``int16_t``, ``uint16_t`` | 16-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``int32_t``, ``uint32_t`` | 32-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``int64_t``, ``uint64_t`` | 64-bit integers | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``ssize_t``, ``size_t`` | Platform-dependent size | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``float``, ``double`` | Floating point types | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``bool`` | Two-state Boolean type | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``char`` | Character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``wchar_t`` | Wide character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``const char *`` | UTF-8 string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``const wchar_t *`` | Wide string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::string`` | STL dynamic UTF-8 string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::wstring`` | STL dynamic wide string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::pair`` | Pair of two custom types | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::tuple<...>`` | Arbitrary tuple of types | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::reference_wrapper<...>`` | Reference type wrapper | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::complex`` | Complex numbers | :file:`pybind11/complex.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::array`` | STL static array | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::vector`` | STL dynamic array | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::list`` | STL linked list | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::map`` | STL ordered map | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::unordered_map`` | STL unordered map | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::set`` | STL ordered set | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::unordered_set`` | STL unordered set | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::optional`` | STL optional type (C++17) | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::experimental::optional`` | STL optional type (exp.) | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::function<...>`` | STL polymorphic function | :file:`pybind11/functional.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::chrono::duration<...>`` | STL time duration | :file:`pybind11/chrono.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::chrono::time_point<...>`` | STL date/time | :file:`pybind11/chrono.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``Eigen::Matrix<...>`` | Eigen: dense matrix | :file:`pybind11/eigen.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``Eigen::Map<...>`` | Eigen: mapped memory | :file:`pybind11/eigen.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``Eigen::SparseMatrix<...>`` | Eigen: sparse matrix | :file:`pybind11/eigen.h` | ++------------------------------------+---------------------------+-------------------------------+ diff --git a/resources/pybind11/docs/advanced/cast/stl.rst b/resources/pybind11/docs/advanced/cast/stl.rst new file mode 100755 index 0000000..bbd2373 --- /dev/null +++ b/resources/pybind11/docs/advanced/cast/stl.rst @@ -0,0 +1,154 @@ +STL containers +############## + +Automatic conversion +==================== + +When including the additional header file :file:`pybind11/stl.h`, conversions +between ``std::vector<>``, ``std::list<>``, ``std::set<>``, and ``std::map<>`` +and the Python ``list``, ``set`` and ``dict`` data structures are automatically +enabled. The types ``std::pair<>`` and ``std::tuple<>`` are already supported +out of the box with just the core :file:`pybind11/pybind11.h` header. + +The major downside of these implicit conversions is that containers must be +converted (i.e. copied) on every Python->C++ and C++->Python transition, which +can have implications on the program semantics and performance. Please read the +next sections for more details and alternative approaches that avoid this. + +.. note:: + + Arbitrary nesting of any of these types is possible. + +.. seealso:: + + The file :file:`tests/test_python_types.cpp` contains a complete + example that demonstrates how to pass STL data types in more detail. + +.. _opaque: + +Making opaque types +=================== + +pybind11 heavily relies on a template matching mechanism to convert parameters +and return values that are constructed from STL data types such as vectors, +linked lists, hash tables, etc. This even works in a recursive manner, for +instance to deal with lists of hash maps of pairs of elementary and custom +types, etc. + +However, a fundamental limitation of this approach is that internal conversions +between Python and C++ types involve a copy operation that prevents +pass-by-reference semantics. What does this mean? + +Suppose we bind the following function + +.. code-block:: cpp + + void append_1(std::vector &v) { + v.push_back(1); + } + +and call it from Python, the following happens: + +.. code-block:: pycon + + >>> v = [5, 6] + >>> append_1(v) + >>> print(v) + [5, 6] + +As you can see, when passing STL data structures by reference, modifications +are not propagated back the Python side. A similar situation arises when +exposing STL data structures using the ``def_readwrite`` or ``def_readonly`` +functions: + +.. code-block:: cpp + + /* ... definition ... */ + + class MyClass { + std::vector contents; + }; + + /* ... binding code ... */ + + py::class_(m, "MyClass") + .def(py::init<>) + .def_readwrite("contents", &MyClass::contents); + +In this case, properties can be read and written in their entirety. However, an +``append`` operation involving such a list type has no effect: + +.. code-block:: pycon + + >>> m = MyClass() + >>> m.contents = [5, 6] + >>> print(m.contents) + [5, 6] + >>> m.contents.append(7) + >>> print(m.contents) + [5, 6] + +Finally, the involved copy operations can be costly when dealing with very +large lists. To deal with all of the above situations, pybind11 provides a +macro named ``PYBIND11_MAKE_OPAQUE(T)`` that disables the template-based +conversion machinery of types, thus rendering them *opaque*. The contents of +opaque objects are never inspected or extracted, hence they *can* be passed by +reference. For instance, to turn ``std::vector`` into an opaque type, add +the declaration + +.. code-block:: cpp + + PYBIND11_MAKE_OPAQUE(std::vector); + +before any binding code (e.g. invocations to ``class_::def()``, etc.). This +macro must be specified at the top level (and outside of any namespaces), since +it instantiates a partial template overload. If your binding code consists of +multiple compilation units, it must be present in every file preceding any +usage of ``std::vector``. Opaque types must also have a corresponding +``class_`` declaration to associate them with a name in Python, and to define a +set of available operations, e.g.: + +.. code-block:: cpp + + py::class_>(m, "IntVector") + .def(py::init<>()) + .def("clear", &std::vector::clear) + .def("pop_back", &std::vector::pop_back) + .def("__len__", [](const std::vector &v) { return v.size(); }) + .def("__iter__", [](std::vector &v) { + return py::make_iterator(v.begin(), v.end()); + }, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */ + // .... + +The ability to expose STL containers as native Python objects is a fairly +common request, hence pybind11 also provides an optional header file named +:file:`pybind11/stl_bind.h` that does exactly this. The mapped containers try +to match the behavior of their native Python counterparts as much as possible. + +The following example showcases usage of :file:`pybind11/stl_bind.h`: + +.. code-block:: cpp + + // Don't forget this + #include + + PYBIND11_MAKE_OPAQUE(std::vector); + PYBIND11_MAKE_OPAQUE(std::map); + + // ... + + // later in binding code: + py::bind_vector>(m, "VectorInt"); + py::bind_map>(m, "MapStringDouble"); + +Please take a look at the :ref:`macro_notes` before using the +``PYBIND11_MAKE_OPAQUE`` macro. + +.. seealso:: + + The file :file:`tests/test_opaque_types.cpp` contains a complete + example that demonstrates how to create and expose opaque types using + pybind11 in more detail. + + The file :file:`tests/test_stl_binders.cpp` shows how to use the + convenience STL container wrappers. diff --git a/resources/pybind11/docs/advanced/classes.rst b/resources/pybind11/docs/advanced/classes.rst new file mode 100755 index 0000000..4a423b5 --- /dev/null +++ b/resources/pybind11/docs/advanced/classes.rst @@ -0,0 +1,634 @@ +Classes +####### + +This section presents advanced binding code for classes and it is assumed +that you are already familiar with the basics from :doc:`/classes`. + +.. _overriding_virtuals: + +Overriding virtual functions in Python +====================================== + +Suppose that a C++ class or interface has a virtual function that we'd like to +to override from within Python (we'll focus on the class ``Animal``; ``Dog`` is +given as a specific example of how one would do this with traditional C++ +code). + +.. code-block:: cpp + + class Animal { + public: + virtual ~Animal() { } + virtual std::string go(int n_times) = 0; + }; + + class Dog : public Animal { + public: + std::string go(int n_times) override { + std::string result; + for (int i=0; igo(3); + } + +Normally, the binding code for these classes would look as follows: + +.. code-block:: cpp + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + py::class_ animal(m, "Animal"); + animal + .def("go", &Animal::go); + + py::class_(m, "Dog", animal) + .def(py::init<>()); + + m.def("call_go", &call_go); + + return m.ptr(); + } + +However, these bindings are impossible to extend: ``Animal`` is not +constructible, and we clearly require some kind of "trampoline" that +redirects virtual calls back to Python. + +Defining a new type of ``Animal`` from within Python is possible but requires a +helper class that is defined as follows: + +.. code-block:: cpp + + class PyAnimal : public Animal { + public: + /* Inherit the constructors */ + using Animal::Animal; + + /* Trampoline (need one for each virtual function) */ + std::string go(int n_times) override { + PYBIND11_OVERLOAD_PURE( + std::string, /* Return type */ + Animal, /* Parent class */ + go, /* Name of function */ + n_times /* Argument(s) */ + ); + } + }; + +The macro :func:`PYBIND11_OVERLOAD_PURE` should be used for pure virtual +functions, and :func:`PYBIND11_OVERLOAD` should be used for functions which have +a default implementation. There are also two alternate macros +:func:`PYBIND11_OVERLOAD_PURE_NAME` and :func:`PYBIND11_OVERLOAD_NAME` which +take a string-valued name argument between the *Parent class* and *Name of the +function* slots. This is useful when the C++ and Python versions of the +function have different names, e.g. ``operator()`` vs ``__call__``. + +The binding code also needs a few minor adaptations (highlighted): + +.. code-block:: cpp + :emphasize-lines: 4,6,7 + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + py::class_ animal(m, "Animal"); + animal + .def(py::init<>()) + .def("go", &Animal::go); + + py::class_(m, "Dog", animal) + .def(py::init<>()); + + m.def("call_go", &call_go); + + return m.ptr(); + } + +Importantly, pybind11 is made aware of the trampoline helper class by +specifying it as an extra template argument to :class:`class_`. (This can also +be combined with other template arguments such as a custom holder type; the +order of template types does not matter). Following this, we are able to +define a constructor as usual. + +Note, however, that the above is sufficient for allowing python classes to +extend ``Animal``, but not ``Dog``: see ref:`virtual_and_inheritance` for the +necessary steps required to providing proper overload support for inherited +classes. + +The Python session below shows how to override ``Animal::go`` and invoke it via +a virtual method call. + +.. code-block:: pycon + + >>> from example import * + >>> d = Dog() + >>> call_go(d) + u'woof! woof! woof! ' + >>> class Cat(Animal): + ... def go(self, n_times): + ... return "meow! " * n_times + ... + >>> c = Cat() + >>> call_go(c) + u'meow! meow! meow! ' + +Please take a look at the :ref:`macro_notes` before using this feature. + +.. note:: + + When the overridden type returns a reference or pointer to a type that + pybind11 converts from Python (for example, numeric values, std::string, + and other built-in value-converting types), there are some limitations to + be aware of: + + - because in these cases there is no C++ variable to reference (the value + is stored in the referenced Python variable), pybind11 provides one in + the PYBIND11_OVERLOAD macros (when needed) with static storage duration. + Note that this means that invoking the overloaded method on *any* + instance will change the referenced value stored in *all* instances of + that type. + + - Attempts to modify a non-const reference will not have the desired + effect: it will change only the static cache variable, but this change + will not propagate to underlying Python instance, and the change will be + replaced the next time the overload is invoked. + +.. seealso:: + + The file :file:`tests/test_virtual_functions.cpp` contains a complete + example that demonstrates how to override virtual functions using pybind11 + in more detail. + +.. _virtual_and_inheritance: + +Combining virtual functions and inheritance +=========================================== + +When combining virtual methods with inheritance, you need to be sure to provide +an override for each method for which you want to allow overrides from derived +python classes. For example, suppose we extend the above ``Animal``/``Dog`` +example as follows: + +.. code-block:: cpp + + class Animal { + public: + virtual std::string go(int n_times) = 0; + virtual std::string name() { return "unknown"; } + }; + class Dog : public class Animal { + public: + std::string go(int n_times) override { + std::string result; + for (int i=0; i class PyAnimal : public AnimalBase { + using AnimalBase::AnimalBase; // Inherit constructors + std::string go(int n_times) override { PYBIND11_OVERLOAD_PURE(std::string, AnimalBase, go, n_times); } + std::string name() override { PYBIND11_OVERLOAD(std::string, AnimalBase, name, ); } + }; + template class PyDog : public PyAnimal { + using PyAnimal::PyAnimal; // Inherit constructors + // Override PyAnimal's pure virtual go() with a non-pure one: + std::string go(int n_times) override { PYBIND11_OVERLOAD(std::string, DogBase, go, n_times); } + std::string bark() override { PYBIND11_OVERLOAD(std::string, DogBase, bark, ); } + }; + +This technique has the advantage of requiring just one trampoline method to be +declared per virtual method and pure virtual method override. It does, +however, require the compiler to generate at least as many methods (and +possibly more, if both pure virtual and overridden pure virtual methods are +exposed, as above). + +The classes are then registered with pybind11 using: + +.. code-block:: cpp + + py::class_> animal(m, "Animal"); + py::class_> dog(m, "Dog"); + py::class_> husky(m, "Husky"); + // ... add animal, dog, husky definitions + +Note that ``Husky`` did not require a dedicated trampoline template class at +all, since it neither declares any new virtual methods nor provides any pure +virtual method implementations. + +With either the repeated-virtuals or templated trampoline methods in place, you +can now create a python class that inherits from ``Dog``: + +.. code-block:: python + + class ShihTzu(Dog): + def bark(self): + return "yip!" + +.. seealso:: + + See the file :file:`tests/test_virtual_functions.cpp` for complete examples + using both the duplication and templated trampoline approaches. + +Extended trampoline class functionality +======================================= + +The trampoline classes described in the previous sections are, by default, only +initialized when needed. More specifically, they are initialized when a python +class actually inherits from a registered type (instead of merely creating an +instance of the registered type), or when a registered constructor is only +valid for the trampoline class but not the registered class. This is primarily +for performance reasons: when the trampoline class is not needed for anything +except virtual method dispatching, not initializing the trampoline class +improves performance by avoiding needing to do a run-time check to see if the +inheriting python instance has an overloaded method. + +Sometimes, however, it is useful to always initialize a trampoline class as an +intermediate class that does more than just handle virtual method dispatching. +For example, such a class might perform extra class initialization, extra +destruction operations, and might define new members and methods to enable a +more python-like interface to a class. + +In order to tell pybind11 that it should *always* initialize the trampoline +class when creating new instances of a type, the class constructors should be +declared using ``py::init_alias()`` instead of the usual +``py::init()``. This forces construction via the trampoline class, +ensuring member initialization and (eventual) destruction. + +.. seealso:: + + See the file :file:`tests/test_alias_initialization.cpp` for complete examples + showing both normal and forced trampoline instantiation. + +.. _custom_constructors: + +Custom constructors +=================== + +The syntax for binding constructors was previously introduced, but it only +works when a constructor with the given parameters actually exists on the C++ +side. To extend this to more general cases, let's take a look at what actually +happens under the hood: the following statement + +.. code-block:: cpp + + py::class_(m, "Example") + .def(py::init()); + +is short hand notation for + +.. code-block:: cpp + + py::class_(m, "Example") + .def("__init__", + [](Example &instance, int arg) { + new (&instance) Example(arg); + } + ); + +In other words, :func:`init` creates an anonymous function that invokes an +in-place constructor. Memory allocation etc. is already take care of beforehand +within pybind11. + +.. _classes_with_non_public_destructors: + +Non-public destructors +====================== + +If a class has a private or protected destructor (as might e.g. be the case in +a singleton pattern), a compile error will occur when creating bindings via +pybind11. The underlying issue is that the ``std::unique_ptr`` holder type that +is responsible for managing the lifetime of instances will reference the +destructor even if no deallocations ever take place. In order to expose classes +with private or protected destructors, it is possible to override the holder +type via a holder type argument to ``class_``. Pybind11 provides a helper class +``py::nodelete`` that disables any destructor invocations. In this case, it is +crucial that instances are deallocated on the C++ side to avoid memory leaks. + +.. code-block:: cpp + + /* ... definition ... */ + + class MyClass { + private: + ~MyClass() { } + }; + + /* ... binding code ... */ + + py::class_>(m, "MyClass") + .def(py::init<>) + +Implicit conversions +==================== + +Suppose that instances of two types ``A`` and ``B`` are used in a project, and +that an ``A`` can easily be converted into an instance of type ``B`` (examples of this +could be a fixed and an arbitrary precision number type). + +.. code-block:: cpp + + py::class_(m, "A") + /// ... members ... + + py::class_(m, "B") + .def(py::init()) + /// ... members ... + + m.def("func", + [](const B &) { /* .... */ } + ); + +To invoke the function ``func`` using a variable ``a`` containing an ``A`` +instance, we'd have to write ``func(B(a))`` in Python. On the other hand, C++ +will automatically apply an implicit type conversion, which makes it possible +to directly write ``func(a)``. + +In this situation (i.e. where ``B`` has a constructor that converts from +``A``), the following statement enables similar implicit conversions on the +Python side: + +.. code-block:: cpp + + py::implicitly_convertible(); + +.. note:: + + Implicit conversions from ``A`` to ``B`` only work when ``B`` is a custom + data type that is exposed to Python via pybind11. + +.. _static_properties: + +Static properties +================= + +The section on :ref:`properties` discussed the creation of instance properties +that are implemented in terms of C++ getters and setters. + +Static properties can also be created in a similar way to expose getters and +setters of static class attributes. It is important to note that the implicit +``self`` argument also exists in this case and is used to pass the Python +``type`` subclass instance. This parameter will often not be needed by the C++ +side, and the following example illustrates how to instantiate a lambda getter +function that ignores it: + +.. code-block:: cpp + + py::class_(m, "Foo") + .def_property_readonly_static("foo", [](py::object /* self */) { return Foo(); }); + +Operator overloading +==================== + +Suppose that we're given the following ``Vector2`` class with a vector addition +and scalar multiplication operation, all implemented using overloaded operators +in C++. + +.. code-block:: cpp + + class Vector2 { + public: + Vector2(float x, float y) : x(x), y(y) { } + + Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); } + Vector2 operator*(float value) const { return Vector2(x * value, y * value); } + Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; } + Vector2& operator*=(float v) { x *= v; y *= v; return *this; } + + friend Vector2 operator*(float f, const Vector2 &v) { + return Vector2(f * v.x, f * v.y); + } + + std::string toString() const { + return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; + } + private: + float x, y; + }; + +The following snippet shows how the above operators can be conveniently exposed +to Python. + +.. code-block:: cpp + + #include + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + py::class_(m, "Vector2") + .def(py::init()) + .def(py::self + py::self) + .def(py::self += py::self) + .def(py::self *= float()) + .def(float() * py::self) + .def("__repr__", &Vector2::toString); + + return m.ptr(); + } + +Note that a line like + +.. code-block:: cpp + + .def(py::self * float()) + +is really just short hand notation for + +.. code-block:: cpp + + .def("__mul__", [](const Vector2 &a, float b) { + return a * b; + }, py::is_operator()) + +This can be useful for exposing additional operators that don't exist on the +C++ side, or to perform other types of customization. The ``py::is_operator`` +flag marker is needed to inform pybind11 that this is an operator, which +returns ``NotImplemented`` when invoked with incompatible arguments rather than +throwing a type error. + +.. note:: + + To use the more convenient ``py::self`` notation, the additional + header file :file:`pybind11/operators.h` must be included. + +.. seealso:: + + The file :file:`tests/test_operator_overloading.cpp` contains a + complete example that demonstrates how to work with overloaded operators in + more detail. + +Pickling support +================ + +Python's ``pickle`` module provides a powerful facility to serialize and +de-serialize a Python object graph into a binary data stream. To pickle and +unpickle C++ classes using pybind11, two additional functions must be provided. +Suppose the class in question has the following signature: + +.. code-block:: cpp + + class Pickleable { + public: + Pickleable(const std::string &value) : m_value(value) { } + const std::string &value() const { return m_value; } + + void setExtra(int extra) { m_extra = extra; } + int extra() const { return m_extra; } + private: + std::string m_value; + int m_extra = 0; + }; + +The binding code including the requisite ``__setstate__`` and ``__getstate__`` methods [#f3]_ +looks as follows: + +.. code-block:: cpp + + py::class_(m, "Pickleable") + .def(py::init()) + .def("value", &Pickleable::value) + .def("extra", &Pickleable::extra) + .def("setExtra", &Pickleable::setExtra) + .def("__getstate__", [](const Pickleable &p) { + /* Return a tuple that fully encodes the state of the object */ + return py::make_tuple(p.value(), p.extra()); + }) + .def("__setstate__", [](Pickleable &p, py::tuple t) { + if (t.size() != 2) + throw std::runtime_error("Invalid state!"); + + /* Invoke the in-place constructor. Note that this is needed even + when the object just has a trivial default constructor */ + new (&p) Pickleable(t[0].cast()); + + /* Assign any additional state */ + p.setExtra(t[1].cast()); + }); + +An instance can now be pickled as follows: + +.. code-block:: python + + try: + import cPickle as pickle # Use cPickle on Python 2.7 + except ImportError: + import pickle + + p = Pickleable("test_value") + p.setExtra(15) + data = pickle.dumps(p, 2) + +Note that only the cPickle module is supported on Python 2.7. The second +argument to ``dumps`` is also crucial: it selects the pickle protocol version +2, since the older version 1 is not supported. Newer versions are also fine—for +instance, specify ``-1`` to always use the latest available version. Beware: +failure to follow these instructions will cause important pybind11 memory +allocation routines to be skipped during unpickling, which will likely lead to +memory corruption and/or segmentation faults. + +.. seealso:: + + The file :file:`tests/test_pickling.cpp` contains a complete example + that demonstrates how to pickle and unpickle types using pybind11 in more + detail. + +.. [#f3] http://docs.python.org/3/library/pickle.html#pickling-class-instances + +Multiple Inheritance +==================== + +pybind11 can create bindings for types that derive from multiple base types +(aka. *multiple inheritance*). To do so, specify all bases in the template +arguments of the ``class_`` declaration: + +.. code-block:: cpp + + py::class_(m, "MyType") + ... + +The base types can be specified in arbitrary order, and they can even be +interspersed with alias types and holder types (discussed earlier in this +document)---pybind11 will automatically find out which is which. The only +requirement is that the first template argument is the type to be declared. + +There are two caveats regarding the implementation of this feature: + +1. When only one base type is specified for a C++ type that actually has + multiple bases, pybind11 will assume that it does not participate in + multiple inheritance, which can lead to undefined behavior. In such cases, + add the tag ``multiple_inheritance``: + + .. code-block:: cpp + + py::class_(m, "MyType", py::multiple_inheritance()); + + The tag is redundant and does not need to be specified when multiple base + types are listed. + +2. As was previously discussed in the section on :ref:`overriding_virtuals`, it + is easy to create Python types that derive from C++ classes. It is even + possible to make use of multiple inheritance to declare a Python class which + has e.g. a C++ and a Python class as bases. However, any attempt to create a + type that has *two or more* C++ classes in its hierarchy of base types will + fail with a fatal error message: ``TypeError: multiple bases have instance + lay-out conflict``. Core Python types that are implemented in C (e.g. + ``dict``, ``list``, ``Exception``, etc.) also fall under this combination + and cannot be combined with C++ types bound using pybind11 via multiple + inheritance. diff --git a/resources/pybind11/docs/advanced/exceptions.rst b/resources/pybind11/docs/advanced/exceptions.rst new file mode 100755 index 0000000..3483379 --- /dev/null +++ b/resources/pybind11/docs/advanced/exceptions.rst @@ -0,0 +1,142 @@ +Exceptions +########## + +Built-in exception translation +============================== + +When C++ code invoked from Python throws an ``std::exception``, it is +automatically converted into a Python ``Exception``. pybind11 defines multiple +special exception classes that will map to different types of Python +exceptions: + +.. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}| + ++--------------------------------------+------------------------------+ +| C++ exception type | Python exception type | ++======================================+==============================+ +| :class:`std::exception` | ``RuntimeError`` | ++--------------------------------------+------------------------------+ +| :class:`std::bad_alloc` | ``MemoryError`` | ++--------------------------------------+------------------------------+ +| :class:`std::domain_error` | ``ValueError`` | ++--------------------------------------+------------------------------+ +| :class:`std::invalid_argument` | ``ValueError`` | ++--------------------------------------+------------------------------+ +| :class:`std::length_error` | ``ValueError`` | ++--------------------------------------+------------------------------+ +| :class:`std::out_of_range` | ``ValueError`` | ++--------------------------------------+------------------------------+ +| :class:`std::range_error` | ``ValueError`` | ++--------------------------------------+------------------------------+ +| :class:`pybind11::stop_iteration` | ``StopIteration`` (used to | +| | implement custom iterators) | ++--------------------------------------+------------------------------+ +| :class:`pybind11::index_error` | ``IndexError`` (used to | +| | indicate out of bounds | +| | accesses in ``__getitem__``, | +| | ``__setitem__``, etc.) | ++--------------------------------------+------------------------------+ +| :class:`pybind11::value_error` | ``ValueError`` (used to | +| | indicate wrong value passed | +| | in ``container.remove(...)`` | ++--------------------------------------+------------------------------+ +| :class:`pybind11::key_error` | ``KeyError`` (used to | +| | indicate out of bounds | +| | accesses in ``__getitem__``, | +| | ``__setitem__`` in dict-like | +| | objects, etc.) | ++--------------------------------------+------------------------------+ +| :class:`pybind11::error_already_set` | Indicates that the Python | +| | exception flag has already | +| | been initialized | ++--------------------------------------+------------------------------+ + +When a Python function invoked from C++ throws an exception, it is converted +into a C++ exception of type :class:`error_already_set` whose string payload +contains a textual summary. + +There is also a special exception :class:`cast_error` that is thrown by +:func:`handle::call` when the input arguments cannot be converted to Python +objects. + +Registering custom translators +============================== + +If the default exception conversion policy described above is insufficient, +pybind11 also provides support for registering custom exception translators. +To register a simple exception conversion that translates a C++ exception into +a new Python exception using the C++ exception's ``what()`` method, a helper +function is available: + +.. code-block:: cpp + + py::register_exception(module, "PyExp"); + +This call creates a Python exception class with the name ``PyExp`` in the given +module and automatically converts any encountered exceptions of type ``CppExp`` +into Python exceptions of type ``PyExp``. + +When more advanced exception translation is needed, the function +``py::register_exception_translator(translator)`` can be used to register +functions that can translate arbitrary exception types (and which may include +additional logic to do so). The function takes a stateless callable (e.g. a +function pointer or a lambda function without captured variables) with the call +signature ``void(std::exception_ptr)``. + +When a C++ exception is thrown, the registered exception translators are tried +in reverse order of registration (i.e. the last registered translator gets the +first shot at handling the exception). + +Inside the translator, ``std::rethrow_exception`` should be used within +a try block to re-throw the exception. One or more catch clauses to catch +the appropriate exceptions should then be used with each clause using +``PyErr_SetString`` to set a Python exception or ``ex(string)`` to set +the python exception to a custom exception type (see below). + +To declare a custom Python exception type, declare a ``py::exception`` variable +and use this in the associated exception translator (note: it is often useful +to make this a static declaration when using it inside a lambda expression +without requiring capturing). + + +The following example demonstrates this for a hypothetical exception classes +``MyCustomException`` and ``OtherException``: the first is translated to a +custom python exception ``MyCustomError``, while the second is translated to a +standard python RuntimeError: + +.. code-block:: cpp + + static py::exception exc(m, "MyCustomError"); + py::register_exception_translator([](std::exception_ptr p) { + try { + if (p) std::rethrow_exception(p); + } catch (const MyCustomException &e) { + exc(e.what()); + } catch (const OtherException &e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + } + }); + +Multiple exceptions can be handled by a single translator, as shown in the +example above. If the exception is not caught by the current translator, the +previously registered one gets a chance. + +If none of the registered exception translators is able to handle the +exception, it is handled by the default converter as described in the previous +section. + +.. seealso:: + + The file :file:`tests/test_exceptions.cpp` contains examples + of various custom exception translators and custom exception types. + +.. note:: + + You must call either ``PyErr_SetString`` or a custom exception's call + operator (``exc(string)``) for every exception caught in a custom exception + translator. Failure to do so will cause Python to crash with ``SystemError: + error return without exception set``. + + Exceptions that you do not plan to handle should simply not be caught, or + may be explicity (re-)thrown to delegate it to the other, + previously-declared existing exception translators. diff --git a/resources/pybind11/docs/advanced/functions.rst b/resources/pybind11/docs/advanced/functions.rst new file mode 100755 index 0000000..f291e82 --- /dev/null +++ b/resources/pybind11/docs/advanced/functions.rst @@ -0,0 +1,311 @@ +Functions +######### + +Before proceeding with this section, make sure that you are already familiar +with the basics of binding functions and classes, as explained in :doc:`/basics` +and :doc:`/classes`. The following guide is applicable to both free and member +functions, i.e. *methods* in Python. + +Return value policies +===================== + +Python and C++ use fundamentally different ways of managing the memory and +lifetime of objects managed by them. This can lead to issues when creating +bindings for functions that return a non-trivial type. Just by looking at the +type information, it is not clear whether Python should take charge of the +returned value and eventually free its resources, or if this is handled on the +C++ side. For this reason, pybind11 provides a several `return value policy` +annotations that can be passed to the :func:`module::def` and +:func:`class_::def` functions. The default policy is +:enum:`return_value_policy::automatic`. + +Return value policies are tricky, and it's very important to get them right. +Just to illustrate what can go wrong, consider the following simple example: + +.. code-block:: cpp + + /* Function declaration */ + Data *get_data() { return _data; /* (pointer to a static data structure) */ } + ... + + /* Binding code */ + m.def("get_data", &get_data); // <-- KABOOM, will cause crash when called from Python + +What's going on here? When ``get_data()`` is called from Python, the return +value (a native C++ type) must be wrapped to turn it into a usable Python type. +In this case, the default return value policy (:enum:`return_value_policy::automatic`) +causes pybind11 to assume ownership of the static ``_data`` instance. + +When Python's garbage collector eventually deletes the Python +wrapper, pybind11 will also attempt to delete the C++ instance (via ``operator +delete()``) due to the implied ownership. At this point, the entire application +will come crashing down, though errors could also be more subtle and involve +silent data corruption. + +In the above example, the policy :enum:`return_value_policy::reference` should have +been specified so that the global data instance is only *referenced* without any +implied transfer of ownership, i.e.: + +.. code-block:: cpp + + m.def("get_data", &get_data, return_value_policy::reference); + +On the other hand, this is not the right policy for many other situations, +where ignoring ownership could lead to resource leaks. +As a developer using pybind11, it's important to be familiar with the different +return value policies, including which situation calls for which one of them. +The following table provides an overview of available policies: + +.. tabularcolumns:: |p{0.5\textwidth}|p{0.45\textwidth}| + ++--------------------------------------------------+----------------------------------------------------------------------------+ +| Return value policy | Description | ++==================================================+============================================================================+ +| :enum:`return_value_policy::take_ownership` | Reference an existing object (i.e. do not create a new copy) and take | +| | ownership. Python will call the destructor and delete operator when the | +| | object's reference count reaches zero. Undefined behavior ensues when the | +| | C++ side does the same, or when the data was not dynamically allocated. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::copy` | Create a new copy of the returned object, which will be owned by Python. | +| | This policy is comparably safe because the lifetimes of the two instances | +| | are decoupled. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::move` | Use ``std::move`` to move the return value contents into a new instance | +| | that will be owned by Python. This policy is comparably safe because the | +| | lifetimes of the two instances (move source and destination) are decoupled.| ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::reference` | Reference an existing object, but do not take ownership. The C++ side is | +| | responsible for managing the object's lifetime and deallocating it when | +| | it is no longer used. Warning: undefined behavior will ensue when the C++ | +| | side deletes an object that is still referenced and used by Python. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::reference_internal` | Indicates that the lifetime of the return value is tied to the lifetime | +| | of a parent object, namely the implicit ``this``, or ``self`` argument of | +| | the called method or property. Internally, this policy works just like | +| | :enum:`return_value_policy::reference` but additionally applies a | +| | ``keep_alive<0, 1>`` *call policy* (described in the next section) that | +| | prevents the parent object from being garbage collected as long as the | +| | return value is referenced by Python. This is the default policy for | +| | property getters created via ``def_property``, ``def_readwrite``, etc. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::automatic` | This is the default return value policy, which falls back to the policy | +| | :enum:`return_value_policy::take_ownership` when the return value is a | +| | pointer. Otherwise, it uses :enum:`return_value::move` or | +| | :enum:`return_value::copy` for rvalue and lvalue references, respectively. | +| | See above for a description of what all of these different policies do. | ++--------------------------------------------------+----------------------------------------------------------------------------+ +| :enum:`return_value_policy::automatic_reference` | As above, but use policy :enum:`return_value_policy::reference` when the | +| | return value is a pointer. This is the default conversion policy for | +| | function arguments when calling Python functions manually from C++ code | +| | (i.e. via handle::operator()). You probably won't need to use this. | ++--------------------------------------------------+----------------------------------------------------------------------------+ + +Return value policies can also be applied to properties: + +.. code-block:: cpp + + class_(m, "MyClass") + .def_property("data", &MyClass::getData, &MyClass::setData, + py::return_value_policy::copy); + +Technically, the code above applies the policy to both the getter and the +setter function, however, the setter doesn't really care about *return* +value policies which makes this a convenient terse syntax. Alternatively, +targeted arguments can be passed through the :class:`cpp_function` constructor: + +.. code-block:: cpp + + class_(m, "MyClass") + .def_property("data" + py::cpp_function(&MyClass::getData, py::return_value_policy::copy), + py::cpp_function(&MyClass::setData) + ); + +.. warning:: + + Code with invalid return value policies might access unitialized memory or + free data structures multiple times, which can lead to hard-to-debug + non-determinism and segmentation faults, hence it is worth spending the + time to understand all the different options in the table above. + +.. note:: + + One important aspect of the above policies is that they only apply to + instances which pybind11 has *not* seen before, in which case the policy + clarifies essential questions about the return value's lifetime and + ownership. When pybind11 knows the instance already (as identified by its + type and address in memory), it will return the existing Python object + wrapper rather than creating a new copy. + +.. note:: + + The next section on :ref:`call_policies` discusses *call policies* that can be + specified *in addition* to a return value policy from the list above. Call + policies indicate reference relationships that can involve both return values + and parameters of functions. + +.. note:: + + As an alternative to elaborate call policies and lifetime management logic, + consider using smart pointers (see the section on :ref:`smart_pointers` for + details). Smart pointers can tell whether an object is still referenced from + C++ or Python, which generally eliminates the kinds of inconsistencies that + can lead to crashes or undefined behavior. For functions returning smart + pointers, it is not necessary to specify a return value policy. + +.. _call_policies: + +Additional call policies +======================== + +In addition to the above return value policies, further `call policies` can be +specified to indicate dependencies between parameters. There is currently just +one policy named ``keep_alive``, which indicates that the +argument with index ``Patient`` should be kept alive at least until the +argument with index ``Nurse`` is freed by the garbage collector. Argument +indices start at one, while zero refers to the return value. For methods, index +``1`` refers to the implicit ``this`` pointer, while regular arguments begin at +index ``2``. Arbitrarily many call policies can be specified. When a ``Nurse`` +with value ``None`` is detected at runtime, the call policy does nothing. + +This feature internally relies on the ability to create a *weak reference* to +the nurse object, which is permitted by all classes exposed via pybind11. When +the nurse object does not support weak references, an exception will be thrown. + +Consider the following example: here, the binding code for a list append +operation ties the lifetime of the newly added element to the underlying +container: + +.. code-block:: cpp + + py::class_(m, "List") + .def("append", &List::append, py::keep_alive<1, 2>()); + +.. note:: + + ``keep_alive`` is analogous to the ``with_custodian_and_ward`` (if Nurse, + Patient != 0) and ``with_custodian_and_ward_postcall`` (if Nurse/Patient == + 0) policies from Boost.Python. + +.. seealso:: + + The file :file:`tests/test_keep_alive.cpp` contains a complete example + that demonstrates using :class:`keep_alive` in more detail. + +.. _python_objects_as_args: + +Python objects as arguments +=========================== + +pybind11 exposes all major Python types using thin C++ wrapper classes. These +wrapper classes can also be used as parameters of functions in bindings, which +makes it possible to directly work with native Python types on the C++ side. +For instance, the following statement iterates over a Python ``dict``: + +.. code-block:: cpp + + void print_dict(py::dict dict) { + /* Easily interact with Python types */ + for (auto item : dict) + std::cout << "key=" << item.first << ", " + << "value=" << item.second << std::endl; + } + +It can be exported: + +.. code-block:: cpp + + m.def("print_dict", &print_dict); + +And used in Python as usual: + +.. code-block:: pycon + + >>> print_dict({'foo': 123, 'bar': 'hello'}) + key=foo, value=123 + key=bar, value=hello + +For more information on using Python objects in C++, see :doc:`/advanced/pycpp/index`. + +Accepting \*args and \*\*kwargs +=============================== + +Python provides a useful mechanism to define functions that accept arbitrary +numbers of arguments and keyword arguments: + +.. code-block:: python + + def generic(*args, **kwargs): + ... # do something with args and kwargs + +Such functions can also be created using pybind11: + +.. code-block:: cpp + + void generic(py::args args, py::kwargs kwargs) { + /// .. do something with args + if (kwargs) + /// .. do something with kwargs + } + + /// Binding code + m.def("generic", &generic); + +The class ``py::args`` derives from ``py::tuple`` and ``py::kwargs`` derives +from ``py::dict``. Note that the ``kwargs`` argument is invalid if no keyword +arguments were actually provided. Please refer to the other examples for +details on how to iterate over these, and on how to cast their entries into +C++ objects. A demonstration is also available in +``tests/test_kwargs_and_defaults.cpp``. + +.. warning:: + + Unlike Python, pybind11 does not allow combining normal parameters with the + ``args`` / ``kwargs`` special parameters. + +Default arguments revisited +=========================== + +The section on :ref:`default_args` previously discussed basic usage of default +arguments using pybind11. One noteworthy aspect of their implementation is that +default arguments are converted to Python objects right at declaration time. +Consider the following example: + +.. code-block:: cpp + + py::class_("MyClass") + .def("myFunction", py::arg("arg") = SomeType(123)); + +In this case, pybind11 must already be set up to deal with values of the type +``SomeType`` (via a prior instantiation of ``py::class_``), or an +exception will be thrown. + +Another aspect worth highlighting is that the "preview" of the default argument +in the function signature is generated using the object's ``__repr__`` method. +If not available, the signature may not be very helpful, e.g.: + +.. code-block:: pycon + + FUNCTIONS + ... + | myFunction(...) + | Signature : (MyClass, arg : SomeType = ) -> NoneType + ... + +The first way of addressing this is by defining ``SomeType.__repr__``. +Alternatively, it is possible to specify the human-readable preview of the +default argument manually using the ``arg_v`` notation: + +.. code-block:: cpp + + py::class_("MyClass") + .def("myFunction", py::arg_v("arg", SomeType(123), "SomeType(123)")); + +Sometimes it may be necessary to pass a null pointer value as a default +argument. In this case, remember to cast it to the underlying type in question, +like so: + +.. code-block:: cpp + + py::class_("MyClass") + .def("myFunction", py::arg("arg") = (SomeType *) nullptr); diff --git a/resources/pybind11/docs/advanced/misc.rst b/resources/pybind11/docs/advanced/misc.rst new file mode 100755 index 0000000..c13df7b --- /dev/null +++ b/resources/pybind11/docs/advanced/misc.rst @@ -0,0 +1,229 @@ +Miscellaneous +############# + +.. _macro_notes: + +General notes regarding convenience macros +========================================== + +pybind11 provides a few convenience macros such as +:func:`PYBIND11_MAKE_OPAQUE` and :func:`PYBIND11_DECLARE_HOLDER_TYPE`, and +``PYBIND11_OVERLOAD_*``. Since these are "just" macros that are evaluated +in the preprocessor (which has no concept of types), they *will* get confused +by commas in a template argument such as ``PYBIND11_OVERLOAD(MyReturnValue, myFunc)``. In this case, the preprocessor assumes that the comma indicates +the beginning of the next parameter. Use a ``typedef`` to bind the template to +another name and use it in the macro to avoid this problem. + + +Global Interpreter Lock (GIL) +============================= + +The classes :class:`gil_scoped_release` and :class:`gil_scoped_acquire` can be +used to acquire and release the global interpreter lock in the body of a C++ +function call. In this way, long-running C++ code can be parallelized using +multiple Python threads. Taking :ref:`overriding_virtuals` as an example, this +could be realized as follows (important changes highlighted): + +.. code-block:: cpp + :emphasize-lines: 8,9,33,34 + + class PyAnimal : public Animal { + public: + /* Inherit the constructors */ + using Animal::Animal; + + /* Trampoline (need one for each virtual function) */ + std::string go(int n_times) { + /* Acquire GIL before calling Python code */ + py::gil_scoped_acquire acquire; + + PYBIND11_OVERLOAD_PURE( + std::string, /* Return type */ + Animal, /* Parent class */ + go, /* Name of function */ + n_times /* Argument(s) */ + ); + } + }; + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + py::class_ animal(m, "Animal"); + animal + .def(py::init<>()) + .def("go", &Animal::go); + + py::class_(m, "Dog", animal) + .def(py::init<>()); + + m.def("call_go", [](Animal *animal) -> std::string { + /* Release GIL before calling into (potentially long-running) C++ code */ + py::gil_scoped_release release; + return call_go(animal); + }); + + return m.ptr(); + } + + +Binding sequence data types, iterators, the slicing protocol, etc. +================================================================== + +Please refer to the supplemental example for details. + +.. seealso:: + + The file :file:`tests/test_sequences_and_iterators.cpp` contains a + complete example that shows how to bind a sequence data type, including + length queries (``__len__``), iterators (``__iter__``), the slicing + protocol and other kinds of useful operations. + + +Partitioning code over multiple extension modules +================================================= + +It's straightforward to split binding code over multiple extension modules, +while referencing types that are declared elsewhere. Everything "just" works +without any special precautions. One exception to this rule occurs when +extending a type declared in another extension module. Recall the basic example +from Section :ref:`inheritance`. + +.. code-block:: cpp + + py::class_ pet(m, "Pet"); + pet.def(py::init()) + .def_readwrite("name", &Pet::name); + + py::class_(m, "Dog", pet /* <- specify parent */) + .def(py::init()) + .def("bark", &Dog::bark); + +Suppose now that ``Pet`` bindings are defined in a module named ``basic``, +whereas the ``Dog`` bindings are defined somewhere else. The challenge is of +course that the variable ``pet`` is not available anymore though it is needed +to indicate the inheritance relationship to the constructor of ``class_``. +However, it can be acquired as follows: + +.. code-block:: cpp + + py::object pet = (py::object) py::module::import("basic").attr("Pet"); + + py::class_(m, "Dog", pet) + .def(py::init()) + .def("bark", &Dog::bark); + +Alternatively, you can specify the base class as a template parameter option to +``class_``, which performs an automated lookup of the corresponding Python +type. Like the above code, however, this also requires invoking the ``import`` +function once to ensure that the pybind11 binding code of the module ``basic`` +has been executed: + +.. code-block:: cpp + + py::module::import("basic"); + + py::class_(m, "Dog") + .def(py::init()) + .def("bark", &Dog::bark); + +Naturally, both methods will fail when there are cyclic dependencies. + +Note that compiling code which has its default symbol visibility set to +*hidden* (e.g. via the command line flag ``-fvisibility=hidden`` on GCC/Clang) can interfere with the +ability to access types defined in another extension module. Workarounds +include changing the global symbol visibility (not recommended, because it will +lead unnecessarily large binaries) or manually exporting types that are +accessed by multiple extension modules: + +.. code-block:: cpp + + #ifdef _WIN32 + # define EXPORT_TYPE __declspec(dllexport) + #else + # define EXPORT_TYPE __attribute__ ((visibility("default"))) + #endif + + class EXPORT_TYPE Dog : public Animal { + ... + }; + +Note also that it is possible (although would rarely be required) to share arbitrary +C++ objects between extension modules at runtime. Internal library data is shared +between modules using capsule machinery [#f6]_ which can be also utilized for +storing, modifying and accessing user-defined data. Note that an extension module +will "see" other extensions' data if and only if they were built with the same +pybind11 version. Consider the following example: + +.. code-block:: cpp + + auto data = (MyData *) py::get_shared_data("mydata"); + if (!data) + data = (MyData *) py::set_shared_data("mydata", new MyData(42)); + +If the above snippet was used in several separately compiled extension modules, +the first one to be imported would create a ``MyData`` instance and associate +a ``"mydata"`` key with a pointer to it. Extensions that are imported later +would be then able to access the data behind the same pointer. + +.. [#f6] https://docs.python.org/3/extending/extending.html#using-capsules + + +Generating documentation using Sphinx +===================================== + +Sphinx [#f4]_ has the ability to inspect the signatures and documentation +strings in pybind11-based extension modules to automatically generate beautiful +documentation in a variety formats. The python_example repository [#f5]_ contains a +simple example repository which uses this approach. + +There are two potential gotchas when using this approach: first, make sure that +the resulting strings do not contain any :kbd:`TAB` characters, which break the +docstring parsing routines. You may want to use C++11 raw string literals, +which are convenient for multi-line comments. Conveniently, any excess +indentation will be automatically be removed by Sphinx. However, for this to +work, it is important that all lines are indented consistently, i.e.: + +.. code-block:: cpp + + // ok + m.def("foo", &foo, R"mydelimiter( + The foo function + + Parameters + ---------- + )mydelimiter"); + + // *not ok* + m.def("foo", &foo, R"mydelimiter(The foo function + + Parameters + ---------- + )mydelimiter"); + +By default, pybind11 automatically generates and prepends a signature to the docstring of a function +registered with ``module::def()`` and ``class_::def()``. Sometimes this +behavior is not desirable, because you want to provide your own signature or remove +the docstring completely to exclude the function from the Sphinx documentation. +The class ``options`` allows you to selectively suppress auto-generated signatures: + +.. code-block:: cpp + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + py::options options; + options.disable_function_signatures(); + + m.def("add", [](int a, int b) { return a + b; }, "A function which adds two numbers"); + + return m.ptr(); + } + +Note that changes to the settings affect only function bindings created during the +lifetime of the ``options`` instance. When it goes out of scope at the end of the module's init function, +the default settings are restored to prevent unwanted side effects. + +.. [#f4] http://www.sphinx-doc.org +.. [#f5] http://github.com/pybind/python_example diff --git a/resources/pybind11/docs/advanced/pycpp/index.rst b/resources/pybind11/docs/advanced/pycpp/index.rst new file mode 100755 index 0000000..6885bdc --- /dev/null +++ b/resources/pybind11/docs/advanced/pycpp/index.rst @@ -0,0 +1,13 @@ +Python C++ interface +#################### + +pybind11 exposes Python types and functions using thin C++ wrappers, which +makes it possible to conveniently call Python code from C++ without resorting +to Python's C API. + +.. toctree:: + :maxdepth: 2 + + object + numpy + utilities diff --git a/resources/pybind11/docs/advanced/pycpp/numpy.rst b/resources/pybind11/docs/advanced/pycpp/numpy.rst new file mode 100755 index 0000000..8b46b7c --- /dev/null +++ b/resources/pybind11/docs/advanced/pycpp/numpy.rst @@ -0,0 +1,299 @@ +.. _numpy: + +NumPy +##### + +Buffer protocol +=============== + +Python supports an extremely general and convenient approach for exchanging +data between plugin libraries. Types can expose a buffer view [#f2]_, which +provides fast direct access to the raw internal data representation. Suppose we +want to bind the following simplistic Matrix class: + +.. code-block:: cpp + + class Matrix { + public: + Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) { + m_data = new float[rows*cols]; + } + float *data() { return m_data; } + size_t rows() const { return m_rows; } + size_t cols() const { return m_cols; } + private: + size_t m_rows, m_cols; + float *m_data; + }; + +The following binding code exposes the ``Matrix`` contents as a buffer object, +making it possible to cast Matrices into NumPy arrays. It is even possible to +completely avoid copy operations with Python expressions like +``np.array(matrix_instance, copy = False)``. + +.. code-block:: cpp + + py::class_(m, "Matrix") + .def_buffer([](Matrix &m) -> py::buffer_info { + return py::buffer_info( + m.data(), /* Pointer to buffer */ + sizeof(float), /* Size of one scalar */ + py::format_descriptor::format(), /* Python struct-style format descriptor */ + 2, /* Number of dimensions */ + { m.rows(), m.cols() }, /* Buffer dimensions */ + { sizeof(float) * m.rows(), /* Strides (in bytes) for each index */ + sizeof(float) } + ); + }); + +The snippet above binds a lambda function, which can create ``py::buffer_info`` +description records on demand describing a given matrix. The contents of +``py::buffer_info`` mirror the Python buffer protocol specification. + +.. code-block:: cpp + + struct buffer_info { + void *ptr; + size_t itemsize; + std::string format; + int ndim; + std::vector shape; + std::vector strides; + }; + +To create a C++ function that can take a Python buffer object as an argument, +simply use the type ``py::buffer`` as one of its arguments. Buffers can exist +in a great variety of configurations, hence some safety checks are usually +necessary in the function body. Below, you can see an basic example on how to +define a custom constructor for the Eigen double precision matrix +(``Eigen::MatrixXd``) type, which supports initialization from compatible +buffer objects (e.g. a NumPy matrix). + +.. code-block:: cpp + + /* Bind MatrixXd (or some other Eigen type) to Python */ + typedef Eigen::MatrixXd Matrix; + + typedef Matrix::Scalar Scalar; + constexpr bool rowMajor = Matrix::Flags & Eigen::RowMajorBit; + + py::class_(m, "Matrix") + .def("__init__", [](Matrix &m, py::buffer b) { + typedef Eigen::Stride Strides; + + /* Request a buffer descriptor from Python */ + py::buffer_info info = b.request(); + + /* Some sanity checks ... */ + if (info.format != py::format_descriptor::format()) + throw std::runtime_error("Incompatible format: expected a double array!"); + + if (info.ndim != 2) + throw std::runtime_error("Incompatible buffer dimension!"); + + auto strides = Strides( + info.strides[rowMajor ? 0 : 1] / sizeof(Scalar), + info.strides[rowMajor ? 1 : 0] / sizeof(Scalar)); + + auto map = Eigen::Map( + static_cat(info.ptr), info.shape[0], info.shape[1], strides); + + new (&m) Matrix(map); + }); + +For reference, the ``def_buffer()`` call for this Eigen data type should look +as follows: + +.. code-block:: cpp + + .def_buffer([](Matrix &m) -> py::buffer_info { + return py::buffer_info( + m.data(), /* Pointer to buffer */ + sizeof(Scalar), /* Size of one scalar */ + /* Python struct-style format descriptor */ + py::format_descriptor::format(), + /* Number of dimensions */ + 2, + /* Buffer dimensions */ + { (size_t) m.rows(), + (size_t) m.cols() }, + /* Strides (in bytes) for each index */ + { sizeof(Scalar) * (rowMajor ? m.cols() : 1), + sizeof(Scalar) * (rowMajor ? 1 : m.rows()) } + ); + }) + +For a much easier approach of binding Eigen types (although with some +limitations), refer to the section on :doc:`/advanced/cast/eigen`. + +.. seealso:: + + The file :file:`tests/test_buffers.cpp` contains a complete example + that demonstrates using the buffer protocol with pybind11 in more detail. + +.. [#f2] http://docs.python.org/3/c-api/buffer.html + +Arrays +====== + +By exchanging ``py::buffer`` with ``py::array`` in the above snippet, we can +restrict the function so that it only accepts NumPy arrays (rather than any +type of Python object satisfying the buffer protocol). + +In many situations, we want to define a function which only accepts a NumPy +array of a certain data type. This is possible via the ``py::array_t`` +template. For instance, the following function requires the argument to be a +NumPy array containing double precision values. + +.. code-block:: cpp + + void f(py::array_t array); + +When it is invoked with a different type (e.g. an integer or a list of +integers), the binding code will attempt to cast the input into a NumPy array +of the requested type. Note that this feature requires the +:file:``pybind11/numpy.h`` header to be included. + +Data in NumPy arrays is not guaranteed to packed in a dense manner; +furthermore, entries can be separated by arbitrary column and row strides. +Sometimes, it can be useful to require a function to only accept dense arrays +using either the C (row-major) or Fortran (column-major) ordering. This can be +accomplished via a second template argument with values ``py::array::c_style`` +or ``py::array::f_style``. + +.. code-block:: cpp + + void f(py::array_t array); + +The ``py::array::forcecast`` argument is the default value of the second +template parameter, and it ensures that non-conforming arguments are converted +into an array satisfying the specified requirements instead of trying the next +function overload. + +Structured types +================ + +In order for ``py::array_t`` to work with structured (record) types, we first need +to register the memory layout of the type. This can be done via ``PYBIND11_NUMPY_DTYPE`` +macro which expects the type followed by field names: + +.. code-block:: cpp + + struct A { + int x; + double y; + }; + + struct B { + int z; + A a; + }; + + PYBIND11_NUMPY_DTYPE(A, x, y); + PYBIND11_NUMPY_DTYPE(B, z, a); + + /* now both A and B can be used as template arguments to py::array_t */ + +Vectorizing functions +===================== + +Suppose we want to bind a function with the following signature to Python so +that it can process arbitrary NumPy array arguments (vectors, matrices, general +N-D arrays) in addition to its normal arguments: + +.. code-block:: cpp + + double my_func(int x, float y, double z); + +After including the ``pybind11/numpy.h`` header, this is extremely simple: + +.. code-block:: cpp + + m.def("vectorized_func", py::vectorize(my_func)); + +Invoking the function like below causes 4 calls to be made to ``my_func`` with +each of the array elements. The significant advantage of this compared to +solutions like ``numpy.vectorize()`` is that the loop over the elements runs +entirely on the C++ side and can be crunched down into a tight, optimized loop +by the compiler. The result is returned as a NumPy array of type +``numpy.dtype.float64``. + +.. code-block:: pycon + + >>> x = np.array([[1, 3],[5, 7]]) + >>> y = np.array([[2, 4],[6, 8]]) + >>> z = 3 + >>> result = vectorized_func(x, y, z) + +The scalar argument ``z`` is transparently replicated 4 times. The input +arrays ``x`` and ``y`` are automatically converted into the right types (they +are of type ``numpy.dtype.int64`` but need to be ``numpy.dtype.int32`` and +``numpy.dtype.float32``, respectively) + +Sometimes we might want to explicitly exclude an argument from the vectorization +because it makes little sense to wrap it in a NumPy array. For instance, +suppose the function signature was + +.. code-block:: cpp + + double my_func(int x, float y, my_custom_type *z); + +This can be done with a stateful Lambda closure: + +.. code-block:: cpp + + // Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the vectorization) + m.def("vectorized_func", + [](py::array_t x, py::array_t y, my_custom_type *z) { + auto stateful_closure = [z](int x, float y) { return my_func(x, y, z); }; + return py::vectorize(stateful_closure)(x, y); + } + ); + +In cases where the computation is too complicated to be reduced to +``vectorize``, it will be necessary to create and access the buffer contents +manually. The following snippet contains a complete example that shows how this +works (the code is somewhat contrived, since it could have been done more +simply using ``vectorize``). + +.. code-block:: cpp + + #include + #include + + namespace py = pybind11; + + py::array_t add_arrays(py::array_t input1, py::array_t input2) { + auto buf1 = input1.request(), buf2 = input2.request(); + + if (buf1.ndim != 1 || buf2.ndim != 1) + throw std::runtime_error("Number of dimensions must be one"); + + if (buf1.size != buf2.size) + throw std::runtime_error("Input shapes must match"); + + /* No pointer is passed, so NumPy will allocate the buffer */ + auto result = py::array_t(buf1.size); + + auto buf3 = result.request(); + + double *ptr1 = (double *) buf1.ptr, + *ptr2 = (double *) buf2.ptr, + *ptr3 = (double *) buf3.ptr; + + for (size_t idx = 0; idx < buf1.shape[0]; idx++) + ptr3[idx] = ptr1[idx] + ptr2[idx]; + + return result; + } + + PYBIND11_PLUGIN(test) { + py::module m("test"); + m.def("add_arrays", &add_arrays, "Add two NumPy arrays"); + return m.ptr(); + } + +.. seealso:: + + The file :file:`tests/test_numpy_vectorize.cpp` contains a complete + example that demonstrates using :func:`vectorize` in more detail. diff --git a/resources/pybind11/docs/advanced/pycpp/object.rst b/resources/pybind11/docs/advanced/pycpp/object.rst new file mode 100755 index 0000000..8fc165d --- /dev/null +++ b/resources/pybind11/docs/advanced/pycpp/object.rst @@ -0,0 +1,96 @@ +Python types +############ + +Available wrappers +================== + +All major Python types are available as thin C++ wrapper classes. These +can also be used as function parameters -- see :ref:`python_objects_as_args`. + +Available types include :class:`handle`, :class:`object`, :class:`bool_`, +:class:`int_`, :class:`float_`, :class:`str`, :class:`bytes`, :class:`tuple`, +:class:`list`, :class:`dict`, :class:`slice`, :class:`none`, :class:`capsule`, +:class:`iterable`, :class:`iterator`, :class:`function`, :class:`buffer`, +:class:`array`, and :class:`array_t`. + +Casting back and forth +====================== + +In this kind of mixed code, it is often necessary to convert arbitrary C++ +types to Python, which can be done using :func:`py::cast`: + +.. code-block:: cpp + + MyClass *cls = ..; + py::object obj = py::cast(cls); + +The reverse direction uses the following syntax: + +.. code-block:: cpp + + py::object obj = ...; + MyClass *cls = obj.cast(); + +When conversion fails, both directions throw the exception :class:`cast_error`. + +Calling Python functions +======================== + +It is also possible to call python functions via ``operator()``. + +.. code-block:: cpp + + py::function f = <...>; + py::object result_py = f(1234, "hello", some_instance); + MyClass &result = result_py.cast(); + +Keyword arguments are also supported. In Python, there is the usual call syntax: + +.. code-block:: python + + def f(number, say, to): + ... # function code + + f(1234, say="hello", to=some_instance) # keyword call in Python + +In C++, the same call can be made using: + +.. code-block:: cpp + + using pybind11::literals; // to bring in the `_a` literal + f(1234, "say"_a="hello", "to"_a=some_instance); // keyword call in C++ + +Unpacking of ``*args`` and ``**kwargs`` is also possible and can be mixed with +other arguments: + +.. code-block:: cpp + + // * unpacking + py::tuple args = py::make_tuple(1234, "hello", some_instance); + f(*args); + + // ** unpacking + py::dict kwargs = py::dict("number"_a=1234, "say"_a="hello", "to"_a=some_instance); + f(**kwargs); + + // mixed keywords, * and ** unpacking + py::tuple args = py::make_tuple(1234); + py::dict kwargs = py::dict("to"_a=some_instance); + f(*args, "say"_a="hello", **kwargs); + +Generalized unpacking according to PEP448_ is also supported: + +.. code-block:: cpp + + py::dict kwargs1 = py::dict("number"_a=1234); + py::dict kwargs2 = py::dict("to"_a=some_instance); + f(**kwargs1, "say"_a="hello", **kwargs2); + +.. seealso:: + + The file :file:`tests/test_python_types.cpp` contains a complete + example that demonstrates passing native Python types in more detail. The + file :file:`tests/test_callbacks.cpp` presents a few examples of calling + Python functions from C++, including keywords arguments and unpacking. + +.. _PEP448: https://www.python.org/dev/peps/pep-0448/ diff --git a/resources/pybind11/docs/advanced/pycpp/utilities.rst b/resources/pybind11/docs/advanced/pycpp/utilities.rst new file mode 100755 index 0000000..ba0dbef --- /dev/null +++ b/resources/pybind11/docs/advanced/pycpp/utilities.rst @@ -0,0 +1,57 @@ +Utilities +######### + +Using Python's print function in C++ +==================================== + +The usual way to write output in C++ is using ``std::cout`` while in Python one +would use ``print``. Since these methods use different buffers, mixing them can +lead to output order issues. To resolve this, pybind11 modules can use the +:func:`py::print` function which writes to Python's ``sys.stdout`` for consistency. + +Python's ``print`` function is replicated in the C++ API including optional +keyword arguments ``sep``, ``end``, ``file``, ``flush``. Everything works as +expected in Python: + +.. code-block:: cpp + + py::print(1, 2.0, "three"); // 1 2.0 three + py::print(1, 2.0, "three", "sep"_a="-"); // 1-2.0-three + + auto args = py::make_tuple("unpacked", true); + py::print("->", *args, "end"_a="<-"); // -> unpacked True <- + +Evaluating Python expressions from strings and files +==================================================== + +pybind11 provides the :func:`eval` and :func:`eval_file` functions to evaluate +Python expressions and statements. The following example illustrates how they +can be used. + +Both functions accept a template parameter that describes how the argument +should be interpreted. Possible choices include ``eval_expr`` (isolated +expression), ``eval_single_statement`` (a single statement, return value is +always ``none``), and ``eval_statements`` (sequence of statements, return value +is always ``none``). + +.. code-block:: cpp + + // At beginning of file + #include + + ... + + // Evaluate in scope of main module + py::object scope = py::module::import("__main__").attr("__dict__"); + + // Evaluate an isolated expression + int result = py::eval("my_variable + 10", scope).cast(); + + // Evaluate a sequence of statements + py::eval( + "print('Hello')\n" + "print('world!');", + scope); + + // Evaluate the statements in an separate Python file on disk + py::eval_file("script.py", scope); diff --git a/resources/pybind11/docs/advanced/smart_ptrs.rst b/resources/pybind11/docs/advanced/smart_ptrs.rst new file mode 100755 index 0000000..23072b6 --- /dev/null +++ b/resources/pybind11/docs/advanced/smart_ptrs.rst @@ -0,0 +1,143 @@ +Smart pointers +############## + +std::unique_ptr +=============== + +Given a class ``Example`` with Python bindings, it's possible to return +instances wrapped in C++11 unique pointers, like so + +.. code-block:: cpp + + std::unique_ptr create_example() { return std::unique_ptr(new Example()); } + +.. code-block:: cpp + + m.def("create_example", &create_example); + +In other words, there is nothing special that needs to be done. While returning +unique pointers in this way is allowed, it is *illegal* to use them as function +arguments. For instance, the following function signature cannot be processed +by pybind11. + +.. code-block:: cpp + + void do_something_with_example(std::unique_ptr ex) { ... } + +The above signature would imply that Python needs to give up ownership of an +object that is passed to this function, which is generally not possible (for +instance, the object might be referenced elsewhere). + +std::shared_ptr +=============== + +The binding generator for classes, :class:`class_`, can be passed a template +type that denotes a special *holder* type that is used to manage references to +the object. If no such holder type template argument is given, the default for +a type named ``Type`` is ``std::unique_ptr``, which means that the object +is deallocated when Python's reference count goes to zero. + +It is possible to switch to other types of reference counting wrappers or smart +pointers, which is useful in codebases that rely on them. For instance, the +following snippet causes ``std::shared_ptr`` to be used instead. + +.. code-block:: cpp + + py::class_ /* <- holder type */> obj(m, "Example"); + +Note that any particular class can only be associated with a single holder type. + +One potential stumbling block when using holder types is that they need to be +applied consistently. Can you guess what's broken about the following binding +code? + +.. code-block:: cpp + + class Child { }; + + class Parent { + public: + Parent() : child(std::make_shared()) { } + Child *get_child() { return child.get(); } /* Hint: ** DON'T DO THIS ** */ + private: + std::shared_ptr child; + }; + + PYBIND11_PLUGIN(example) { + py::module m("example"); + + py::class_>(m, "Child"); + + py::class_>(m, "Parent") + .def(py::init<>()) + .def("get_child", &Parent::get_child); + + return m.ptr(); + } + +The following Python code will cause undefined behavior (and likely a +segmentation fault). + +.. code-block:: python + + from example import Parent + print(Parent().get_child()) + +The problem is that ``Parent::get_child()`` returns a pointer to an instance of +``Child``, but the fact that this instance is already managed by +``std::shared_ptr<...>`` is lost when passing raw pointers. In this case, +pybind11 will create a second independent ``std::shared_ptr<...>`` that also +claims ownership of the pointer. In the end, the object will be freed **twice** +since these shared pointers have no way of knowing about each other. + +There are two ways to resolve this issue: + +1. For types that are managed by a smart pointer class, never use raw pointers + in function arguments or return values. In other words: always consistently + wrap pointers into their designated holder types (such as + ``std::shared_ptr<...>``). In this case, the signature of ``get_child()`` + should be modified as follows: + +.. code-block:: cpp + + std::shared_ptr get_child() { return child; } + +2. Adjust the definition of ``Child`` by specifying + ``std::enable_shared_from_this`` (see cppreference_ for details) as a + base class. This adds a small bit of information to ``Child`` that allows + pybind11 to realize that there is already an existing + ``std::shared_ptr<...>`` and communicate with it. In this case, the + declaration of ``Child`` should look as follows: + +.. _cppreference: http://en.cppreference.com/w/cpp/memory/enable_shared_from_this + +.. code-block:: cpp + + class Child : public std::enable_shared_from_this { }; + +.. _smart_pointers: + +Custom smart pointers +===================== + +pybind11 supports ``std::unique_ptr`` and ``std::shared_ptr`` right out of the +box. For any other custom smart pointer, transparent conversions can be enabled +using a macro invocation similar to the following. It must be declared at the +level before any binding code: + +.. code-block:: cpp + + PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr); + +The first argument of :func:`PYBIND11_DECLARE_HOLDER_TYPE` should be a +placeholder name that is used as a template parameter of the second argument. +Thus, feel free to use any identifier, but use it consistently on both sides; +also, don't use the name of a type that already exists in your codebase. + +Please take a look at the :ref:`macro_notes` before using this feature. + +.. seealso:: + + The file :file:`tests/test_smart_ptr.cpp` contains a complete example + that demonstrates how to work with custom reference-counting holder types + in more detail. diff --git a/resources/pybind11/docs/basics.rst b/resources/pybind11/docs/basics.rst new file mode 100755 index 0000000..45272b7 --- /dev/null +++ b/resources/pybind11/docs/basics.rst @@ -0,0 +1,287 @@ +.. _basics: + +First steps +########### + +This sections demonstrates the basic features of pybind11. Before getting +started, make sure that development environment is set up to compile the +included set of test cases. + + +Compiling the test cases +======================== + +Linux/MacOS +----------- + +On Linux you'll need to install the **python-dev** or **python3-dev** packages as +well as **cmake**. On Mac OS, the included python version works out of the box, +but **cmake** must still be installed. + +After installing the prerequisites, run + +.. code-block:: bash + + mkdir build + cd build + cmake .. + make pytest -j 4 + +The last line will both compile and run the tests. + +Windows +------- + +On Windows, only **Visual Studio 2015** and newer are supported since pybind11 relies +on various C++11 language features that break older versions of Visual Studio. + +To compile and run the tests: + +.. code-block:: batch + + mkdir build + cd build + cmake .. + cmake --build . --config Release --target pytest + +This will create a Visual Studio project, compile and run the target, all from the +command line. + +.. Note:: + + If all tests fail, make sure that the Python binary and the testcases are compiled + for the same processor type and bitness (i.e. either **i386** or **x86_64**). You + can specify **x86_64** as the target architecture for the generated Visual Studio + project using ``cmake -A x64 ..``. + +.. seealso:: + + Advanced users who are already familiar with Boost.Python may want to skip + the tutorial and look at the test cases in the :file:`tests` directory, + which exercise all features of pybind11. + +Header and namespace conventions +================================ + +For brevity, all code examples assume that the following two lines are present: + +.. code-block:: cpp + + #include + + namespace py = pybind11; + +Some features may require additional headers, but those will be specified as needed. + +Creating bindings for a simple function +======================================= + +Let's start by creating Python bindings for an extremely simple function, which +adds two numbers and returns their result: + +.. code-block:: cpp + + int add(int i, int j) { + return i + j; + } + +For simplicity [#f1]_, we'll put both this function and the binding code into +a file named :file:`example.cpp` with the following contents: + +.. code-block:: cpp + + #include + + int add(int i, int j) { + return i + j; + } + + namespace py = pybind11; + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + m.def("add", &add, "A function which adds two numbers"); + + return m.ptr(); + } + +.. [#f1] In practice, implementation and binding code will generally be located + in separate files. + +The :func:`PYBIND11_PLUGIN` macro creates a function that will be called when an +``import`` statement is issued from within Python. The next line creates a +module named ``example`` (with the supplied docstring). The method +:func:`module::def` generates binding code that exposes the +``add()`` function to Python. The last line returns the internal Python object +associated with ``m`` to the Python interpreter. + +.. note:: + + Notice how little code was needed to expose our function to Python: all + details regarding the function's parameters and return value were + automatically inferred using template metaprogramming. This overall + approach and the used syntax are borrowed from Boost.Python, though the + underlying implementation is very different. + +pybind11 is a header-only-library, hence it is not necessary to link against +any special libraries (other than Python itself). On Windows, use the CMake +build file discussed in section :ref:`cmake`. On Linux and Mac OS, the above +example can be compiled using the following command + +.. code-block:: bash + + $ c++ -O3 -shared -std=c++11 -I /include `python-config --cflags --ldflags` example.cpp -o example.so + +In general, it is advisable to include several additional build parameters +that can considerably reduce the size of the created binary. Refer to section +:ref:`cmake` for a detailed example of a suitable cross-platform CMake-based +build system. + +Assuming that the created file :file:`example.so` (:file:`example.pyd` on Windows) +is located in the current directory, the following interactive Python session +shows how to load and execute the example. + +.. code-block:: pycon + + $ python + Python 2.7.10 (default, Aug 22 2015, 20:33:39) + [GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.1)] on darwin + Type "help", "copyright", "credits" or "license" for more information. + >>> import example + >>> example.add(1, 2) + 3L + >>> + +.. _keyword_args: + +Keyword arguments +================= + +With a simple modification code, it is possible to inform Python about the +names of the arguments ("i" and "j" in this case). + +.. code-block:: cpp + + m.def("add", &add, "A function which adds two numbers", + py::arg("i"), py::arg("j")); + +:class:`arg` is one of several special tag classes which can be used to pass +metadata into :func:`module::def`. With this modified binding code, we can now +call the function using keyword arguments, which is a more readable alternative +particularly for functions taking many parameters: + +.. code-block:: pycon + + >>> import example + >>> example.add(i=1, j=2) + 3L + +The keyword names also appear in the function signatures within the documentation. + +.. code-block:: pycon + + >>> help(example) + + .... + + FUNCTIONS + add(...) + Signature : (i: int, j: int) -> int + + A function which adds two numbers + +A shorter notation for named arguments is also available: + +.. code-block:: cpp + + // regular notation + m.def("add1", &add, py::arg("i"), py::arg("j")); + // shorthand + using namespace pybind11::literals; + m.def("add2", &add, "i"_a, "j"_a); + +The :var:`_a` suffix forms a C++11 literal which is equivalent to :class:`arg`. +Note that the literal operator must first be made visible with the directive +``using namespace pybind11::literals``. This does not bring in anything else +from the ``pybind11`` namespace except for literals. + +.. _default_args: + +Default arguments +================= + +Suppose now that the function to be bound has default arguments, e.g.: + +.. code-block:: cpp + + int add(int i = 1, int j = 2) { + return i + j; + } + +Unfortunately, pybind11 cannot automatically extract these parameters, since they +are not part of the function's type information. However, they are simple to specify +using an extension of :class:`arg`: + +.. code-block:: cpp + + m.def("add", &add, "A function which adds two numbers", + py::arg("i") = 1, py::arg("j") = 2); + +The default values also appear within the documentation. + +.. code-block:: pycon + + >>> help(example) + + .... + + FUNCTIONS + add(...) + Signature : (i: int = 1, j: int = 2) -> int + + A function which adds two numbers + +The shorthand notation is also available for default arguments: + +.. code-block:: cpp + + // regular notation + m.def("add1", &add, py::arg("i") = 1, py::arg("j") = 2); + // shorthand + m.def("add2", &add, "i"_a=1, "j"_a=2); + +Exporting variables +=================== + +To expose a value from C++, use the ``attr`` function to register it in a module +as shown below. Built-in types and general objects (more on that later) can be +converted using the function ``py::cast``. + +.. code-block:: cpp + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + m.attr("the_answer") = py::cast(42); + m.attr("what") = py::cast("World"); + return m.ptr(); + } + +These are then accessible from Python: + +.. code-block:: pycon + + >>> import example + >>> example.the_answer + 42 + >>> example.what + 'World' + +.. _supported_types: + +Supported data types +==================== + +A large number of data types are supported out of the box and can be used +seamlessly as functions arguments, return values or with ``py::cast`` in general. +For a full overview, see the :doc:`advanced/cast/index` section. diff --git a/resources/pybind11/docs/benchmark.py b/resources/pybind11/docs/benchmark.py new file mode 100755 index 0000000..6f02e92 --- /dev/null +++ b/resources/pybind11/docs/benchmark.py @@ -0,0 +1,90 @@ +import random +import os +import time +import datetime as dt + +nfns = 4 # Functions per class +nargs = 4 # Arguments per function + + +def generate_dummy_code_pybind11(nclasses=10): + decl = "" + bindings = "" + + for cl in range(nclasses): + decl += "class cl%03i;\n" % cl + decl += '\n' + + for cl in range(nclasses): + decl += "class cl%03i {\n" % cl + decl += "public:\n" + bindings += ' py::class_(m, "cl%03i")\n' % (cl, cl) + for fn in range(nfns): + ret = random.randint(0, nclasses - 1) + params = [random.randint(0, nclasses - 1) for i in range(nargs)] + decl += " cl%03i *fn_%03i(" % (ret, fn) + decl += ", ".join("cl%03i *" % p for p in params) + decl += ");\n" + bindings += ' .def("fn_%03i", &cl%03i::fn_%03i)\n' % \ + (fn, cl, fn) + decl += "};\n\n" + bindings += ' ;\n' + + result = "#include \n\n" + result += "namespace py = pybind11;\n\n" + result += decl + '\n' + result += "PYBIND11_PLUGIN(example) {\n" + result += " py::module m(\"example\");" + result += bindings + result += " return m.ptr();" + result += "}" + return result + + +def generate_dummy_code_boost(nclasses=10): + decl = "" + bindings = "" + + for cl in range(nclasses): + decl += "class cl%03i;\n" % cl + decl += '\n' + + for cl in range(nclasses): + decl += "class cl%03i {\n" % cl + decl += "public:\n" + bindings += ' py::class_("cl%03i")\n' % (cl, cl) + for fn in range(nfns): + ret = random.randint(0, nclasses - 1) + params = [random.randint(0, nclasses - 1) for i in range(nargs)] + decl += " cl%03i *fn_%03i(" % (ret, fn) + decl += ", ".join("cl%03i *" % p for p in params) + decl += ");\n" + bindings += ' .def("fn_%03i", &cl%03i::fn_%03i, py::return_value_policy())\n' % \ + (fn, cl, fn) + decl += "};\n\n" + bindings += ' ;\n' + + result = "#include \n\n" + result += "namespace py = boost::python;\n\n" + result += decl + '\n' + result += "BOOST_PYTHON_MODULE(example) {\n" + result += bindings + result += "}" + return result + + +for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]: + print ("{") + for i in range(0, 10): + nclasses = 2 ** i + with open("test.cpp", "w") as f: + f.write(codegen(nclasses)) + n1 = dt.datetime.now() + os.system("g++ -Os -shared -rdynamic -undefined dynamic_lookup " + "-fvisibility=hidden -std=c++14 test.cpp -I include " + "-I /System/Library/Frameworks/Python.framework/Headers -o test.so") + n2 = dt.datetime.now() + elapsed = (n2 - n1).total_seconds() + size = os.stat('test.so').st_size + print(" {%i, %f, %i}," % (nclasses * nfns, elapsed, size)) + print ("}") diff --git a/resources/pybind11/docs/benchmark.rst b/resources/pybind11/docs/benchmark.rst new file mode 100755 index 0000000..8babaa3 --- /dev/null +++ b/resources/pybind11/docs/benchmark.rst @@ -0,0 +1,99 @@ +Benchmark +========= + +The following is the result of a synthetic benchmark comparing both compilation +time and module size of pybind11 against Boost.Python. A detailed report about a +Boost.Python to pybind11 conversion of a real project is available here: [#f1]_. + +.. [#f1] http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf + +Setup +----- + +A python script (see the ``docs/benchmark.py`` file) was used to generate a set +of files with dummy classes whose count increases for each successive benchmark +(between 1 and 2048 classes in powers of two). Each class has four methods with +a randomly generated signature with a return value and four arguments. (There +was no particular reason for this setup other than the desire to generate many +unique function signatures whose count could be controlled in a simple way.) + +Here is an example of the binding code for one class: + +.. code-block:: cpp + + ... + class cl034 { + public: + cl279 *fn_000(cl084 *, cl057 *, cl065 *, cl042 *); + cl025 *fn_001(cl098 *, cl262 *, cl414 *, cl121 *); + cl085 *fn_002(cl445 *, cl297 *, cl145 *, cl421 *); + cl470 *fn_003(cl200 *, cl323 *, cl332 *, cl492 *); + }; + ... + + PYBIND11_PLUGIN(example) { + py::module m("example"); + ... + py::class_(m, "cl034") + .def("fn_000", &cl034::fn_000) + .def("fn_001", &cl034::fn_001) + .def("fn_002", &cl034::fn_002) + .def("fn_003", &cl034::fn_003) + ... + return m.ptr(); + } + +The Boost.Python version looks almost identical except that a return value +policy had to be specified as an argument to ``def()``. For both libraries, +compilation was done with + +.. code-block:: bash + + Apple LLVM version 7.0.2 (clang-700.1.81) + +and the following compilation flags + +.. code-block:: bash + + g++ -Os -shared -rdynamic -undefined dynamic_lookup -fvisibility=hidden -std=c++14 + +Compilation time +---------------- + +The following log-log plot shows how the compilation time grows for an +increasing number of class and function declarations. pybind11 includes many +fewer headers, which initially leads to shorter compilation times, but the +performance is ultimately fairly similar (pybind11 is 19.8 seconds faster for +the largest largest file with 2048 classes and a total of 8192 methods -- a +modest **1.2x** speedup relative to Boost.Python, which required 116.35 +seconds). + +.. only:: not latex + + .. image:: pybind11_vs_boost_python1.svg + +.. only:: latex + + .. image:: pybind11_vs_boost_python1.png + +Module size +----------- + +Differences between the two libraries become much more pronounced when +considering the file size of the generated Python plugin: for the largest file, +the binary generated by Boost.Python required 16.8 MiB, which was **2.17 +times** / **9.1 megabytes** larger than the output generated by pybind11. For +very small inputs, Boost.Python has an edge in the plot below -- however, note +that it stores many definitions in an external library, whose size was not +included here, hence the comparison is slightly shifted in Boost.Python's +favor. + +.. only:: not latex + + .. image:: pybind11_vs_boost_python2.svg + +.. only:: latex + + .. image:: pybind11_vs_boost_python2.png + + diff --git a/resources/pybind11/docs/changelog.rst b/resources/pybind11/docs/changelog.rst new file mode 100755 index 0000000..15cf8d9 --- /dev/null +++ b/resources/pybind11/docs/changelog.rst @@ -0,0 +1,222 @@ +.. _changelog: + +Changelog +######### + +Starting with version 1.8, pybind11 releases use a +[semantic versioning](http://semver.org) policy. + +Breaking changes queued for v2.0.0 (Not yet released) +----------------------------------------------------- +* Redesigned virtual call mechanism and user-facing syntax (see + https://github.com/pybind/pybind11/commit/86d825f3302701d81414ddd3d38bcd09433076bc) + +* Remove ``handle.call()`` method + +1.9.0 (Not yet released) +------------------------ +* Queued changes: map indexing suite, documentation for indexing suites. +* Mapping a stateless C++ function to Python and back is now "for free" (i.e. no call overheads) +* Support for translation of arbitrary C++ exceptions to Python counterparts +* Added ``eval`` and ``eval_file`` functions for evaluating expressions and + statements from a string or file +* eigen.h type converter fixed for non-contiguous arrays (e.g. slices) +* Print more informative error messages when ``make_tuple()`` or ``cast()`` fail +* ``std::enable_shared_from_this<>`` now also works for ``const`` values +* A return value policy can now be passed to ``handle::operator()`` +* ``make_iterator()`` improvements for better compatibility with various types + (now uses prefix increment operator); it now also accepts iterators with + different begin/end types as long as they are equality comparable. +* ``arg()`` now accepts a wider range of argument types for default values +* Added ``py::repr()`` function which is equivalent to Python's builtin ``repr()``. +* Added support for registering structured dtypes via ``PYBIND11_NUMPY_DTYPE()`` macro. +* Added ``PYBIND11_STR_TYPE`` macro which maps to the ``builtins.str`` type. +* Added a simplified ``buffer_info`` constructor for 1-dimensional buffers. +* Format descriptor strings should now be accessed via ``format_descriptor::format()`` + (for compatibility purposes, the old syntax ``format_descriptor::value`` will still + work for non-structured data types). +* Added a class wrapping NumPy array descriptors: ``dtype``. +* Added buffer/NumPy support for ``char[N]`` and ``std::array`` types. +* ``array`` gained new constructors accepting dtype objects. +* Added constructors for ``array`` and ``array_t`` explicitly accepting shape and + strides; if strides are not provided, they are deduced assuming C-contiguity. + Also added simplified constructors for 1-dimensional case. +* Added constructors for ``str`` from ``bytes`` and for ``bytes`` from ``str``. + This will do the UTF-8 decoding/encoding as required. +* Added constructors for ``str`` and ``bytes`` from zero-terminated char pointers, + and from char pointers and length. +* Added ``memoryview`` wrapper type which is constructible from ``buffer_info``. +* New syntax to call a Python function from C++ using keyword arguments and unpacking, + e.g. ``foo(1, 2, "z"_a=3)`` or ``bar(1, *args, "z"_a=3, **kwargs)``. +* Added ``py::print()`` function which replicates Python's API and writes to Python's + ``sys.stdout`` by default (as opposed to C's ``stdout`` like ``std::cout``). +* Added ``py::dict`` keyword constructor:``auto d = dict("number"_a=42, "name"_a="World");`` +* Added ``py::str::format()`` method and ``_s`` literal: + ``py::str s = "1 + 2 = {}"_s.format(3);`` +* Attribute and item accessors now have a more complete interface which makes it possible + to chain attributes ``obj.attr("a")[key].attr("b").attr("method")(1, 2, 3)```. +* Added built-in support for ``std::shared_ptr`` holder type. There is no more need + to do it manually via ``PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr)``. +* Default return values policy changes: non-static properties now use ``reference_internal`` + and static properties use ``reference`` (previous default was ``automatic``, i.e. ``copy``). +* Support for ``std::experimental::optional`` and ``std::optional`` (C++17). +* Various minor improvements of library internals (no user-visible changes) + +1.8.1 (July 12, 2016) +---------------------- +* Fixed a rare but potentially very severe issue when the garbage collector ran + during pybind11 type creation. + +1.8.0 (June 14, 2016) +---------------------- +* Redesigned CMake build system which exports a convenient + ``pybind11_add_module`` function to parent projects. +* ``std::vector<>`` type bindings analogous to Boost.Python's ``indexing_suite`` +* Transparent conversion of sparse and dense Eigen matrices and vectors (``eigen.h``) +* Added an ``ExtraFlags`` template argument to the NumPy ``array_t<>`` wrapper + to disable an enforced cast that may lose precision, e.g. to create overloads + for different precisions and complex vs real-valued matrices. +* Prevent implicit conversion of floating point values to integral types in + function arguments +* Fixed incorrect default return value policy for functions returning a shared + pointer +* Don't allow registering a type via ``class_`` twice +* Don't allow casting a ``None`` value into a C++ lvalue reference +* Fixed a crash in ``enum_::operator==`` that was triggered by the ``help()`` command +* Improved detection of whether or not custom C++ types can be copy/move-constructed +* Extended ``str`` type to also work with ``bytes`` instances +* Added a ``"name"_a`` user defined string literal that is equivalent to ``py::arg("name")``. +* When specifying function arguments via ``py::arg``, the test that verifies + the number of arguments now runs at compile time. +* Added ``[[noreturn]]`` attribute to ``pybind11_fail()`` to quench some + compiler warnings +* List function arguments in exception text when the dispatch code cannot find + a matching overload +* Added ``PYBIND11_OVERLOAD_NAME`` and ``PYBIND11_OVERLOAD_PURE_NAME`` macros which + can be used to override virtual methods whose name differs in C++ and Python + (e.g. ``__call__`` and ``operator()``) +* Various minor ``iterator`` and ``make_iterator()`` improvements +* Transparently support ``__bool__`` on Python 2.x and Python 3.x +* Fixed issue with destructor of unpickled object not being called +* Minor CMake build system improvements on Windows +* New ``pybind11::args`` and ``pybind11::kwargs`` types to create functions which + take an arbitrary number of arguments and keyword arguments +* New syntax to call a Python function from C++ using ``*args`` and ``*kwargs`` +* The functions ``def_property_*`` now correctly process docstring arguments (these + formerly caused a segmentation fault) +* Many ``mkdoc.py`` improvements (enumerations, template arguments, ``DOC()`` + macro accepts more arguments) +* Cygwin support +* Documentation improvements (pickling support, ``keep_alive``, macro usage) + +1.7 (April 30, 2016) +---------------------- +* Added a new ``move`` return value policy that triggers C++11 move semantics. + The automatic return value policy falls back to this case whenever a rvalue + reference is encountered +* Significantly more general GIL state routines that are used instead of + Python's troublesome ``PyGILState_Ensure`` and ``PyGILState_Release`` API +* Redesign of opaque types that drastically simplifies their usage +* Extended ability to pass values of type ``[const] void *`` +* ``keep_alive`` fix: don't fail when there is no patient +* ``functional.h``: acquire the GIL before calling a Python function +* Added Python RAII type wrappers ``none`` and ``iterable`` +* Added ``*args`` and ``*kwargs`` pass-through parameters to + ``pybind11.get_include()`` function +* Iterator improvements and fixes +* Documentation on return value policies and opaque types improved + +1.6 (April 30, 2016) +---------------------- +* Skipped due to upload to PyPI gone wrong and inability to recover + (https://github.com/pypa/packaging-problems/issues/74) + +1.5 (April 21, 2016) +---------------------- +* For polymorphic types, use RTTI to try to return the closest type registered with pybind11 +* Pickling support for serializing and unserializing C++ instances to a byte stream in Python +* Added a convenience routine ``make_iterator()`` which turns a range indicated + by a pair of C++ iterators into a iterable Python object +* Added ``len()`` and a variadic ``make_tuple()`` function +* Addressed a rare issue that could confuse the current virtual function + dispatcher and another that could lead to crashes in multi-threaded + applications +* Added a ``get_include()`` function to the Python module that returns the path + of the directory containing the installed pybind11 header files +* Documentation improvements: import issues, symbol visibility, pickling, limitations +* Added casting support for ``std::reference_wrapper<>`` + +1.4 (April 7, 2016) +-------------------------- +* Transparent type conversion for ``std::wstring`` and ``wchar_t`` +* Allow passing ``nullptr``-valued strings +* Transparent passing of ``void *`` pointers using capsules +* Transparent support for returning values wrapped in ``std::unique_ptr<>`` +* Improved docstring generation for compatibility with Sphinx +* Nicer debug error message when default parameter construction fails +* Support for "opaque" types that bypass the transparent conversion layer for STL containers +* Redesigned type casting interface to avoid ambiguities that could occasionally cause compiler errors +* Redesigned property implementation; fixes crashes due to an unfortunate default return value policy +* Anaconda package generation support + +1.3 (March 8, 2016) +-------------------------- + +* Added support for the Intel C++ compiler (v15+) +* Added support for the STL unordered set/map data structures +* Added support for the STL linked list data structure +* NumPy-style broadcasting support in ``pybind11::vectorize`` +* pybind11 now displays more verbose error messages when ``arg::operator=()`` fails +* pybind11 internal data structures now live in a version-dependent namespace to avoid ABI issues +* Many, many bugfixes involving corner cases and advanced usage + +1.2 (February 7, 2016) +-------------------------- + +* Optional: efficient generation of function signatures at compile time using C++14 +* Switched to a simpler and more general way of dealing with function default + arguments. Unused keyword arguments in function calls are now detected and + cause errors as expected +* New ``keep_alive`` call policy analogous to Boost.Python's ``with_custodian_and_ward`` +* New ``pybind11::base<>`` attribute to indicate a subclass relationship +* Improved interface for RAII type wrappers in ``pytypes.h`` +* Use RAII type wrappers consistently within pybind11 itself. This + fixes various potential refcount leaks when exceptions occur +* Added new ``bytes`` RAII type wrapper (maps to ``string`` in Python 2.7) +* Made handle and related RAII classes const correct, using them more + consistently everywhere now +* Got rid of the ugly ``__pybind11__`` attributes on the Python side---they are + now stored in a C++ hash table that is not visible in Python +* Fixed refcount leaks involving NumPy arrays and bound functions +* Vastly improved handling of shared/smart pointers +* Removed an unnecessary copy operation in ``pybind11::vectorize`` +* Fixed naming clashes when both pybind11 and NumPy headers are included +* Added conversions for additional exception types +* Documentation improvements (using multiple extension modules, smart pointers, + other minor clarifications) +* unified infrastructure for parsing variadic arguments in ``class_`` and cpp_function +* Fixed license text (was: ZLIB, should have been: 3-clause BSD) +* Python 3.2 compatibility +* Fixed remaining issues when accessing types in another plugin module +* Added enum comparison and casting methods +* Improved SFINAE-based detection of whether types are copy-constructible +* Eliminated many warnings about unused variables and the use of ``offsetof()`` +* Support for ``std::array<>`` conversions + +1.1 (December 7, 2015) +-------------------------- + +* Documentation improvements (GIL, wrapping functions, casting, fixed many typos) +* Generalized conversion of integer types +* Improved support for casting function objects +* Improved support for ``std::shared_ptr<>`` conversions +* Initial support for ``std::set<>`` conversions +* Fixed type resolution issue for types defined in a separate plugin module +* Cmake build system improvements +* Factored out generic functionality to non-templated code (smaller code size) +* Added a code size / compile time benchmark vs Boost.Python +* Added an appveyor CI script + +1.0 (October 15, 2015) +------------------------ +* Initial release diff --git a/resources/pybind11/docs/classes.rst b/resources/pybind11/docs/classes.rst new file mode 100755 index 0000000..3e8f2ee --- /dev/null +++ b/resources/pybind11/docs/classes.rst @@ -0,0 +1,410 @@ +.. _classes: + +Object-oriented code +#################### + +Creating bindings for a custom type +=================================== + +Let's now look at a more complex example where we'll create bindings for a +custom C++ data structure named ``Pet``. Its definition is given below: + +.. code-block:: cpp + + struct Pet { + Pet(const std::string &name) : name(name) { } + void setName(const std::string &name_) { name = name_; } + const std::string &getName() const { return name; } + + std::string name; + }; + +The binding code for ``Pet`` looks as follows: + +.. code-block:: cpp + + #include + + namespace py = pybind11; + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind11 example plugin"); + + py::class_(m, "Pet") + .def(py::init()) + .def("setName", &Pet::setName) + .def("getName", &Pet::getName); + + return m.ptr(); + } + +:class:`class_` creates bindings for a C++ `class` or `struct`-style data +structure. :func:`init` is a convenience function that takes the types of a +constructor's parameters as template arguments and wraps the corresponding +constructor (see the :ref:`custom_constructors` section for details). An +interactive Python session demonstrating this example is shown below: + +.. code-block:: pycon + + % python + >>> import example + >>> p = example.Pet('Molly') + >>> print(p) + + >>> p.getName() + u'Molly' + >>> p.setName('Charly') + >>> p.getName() + u'Charly' + +.. seealso:: + + Static member functions can be bound in the same way using + :func:`class_::def_static`. + +Keyword and default arguments +============================= +It is possible to specify keyword and default arguments using the syntax +discussed in the previous chapter. Refer to the sections :ref:`keyword_args` +and :ref:`default_args` for details. + +Binding lambda functions +======================== + +Note how ``print(p)`` produced a rather useless summary of our data structure in the example above: + +.. code-block:: pycon + + >>> print(p) + + +To address this, we could bind an utility function that returns a human-readable +summary to the special method slot named ``__repr__``. Unfortunately, there is no +suitable functionality in the ``Pet`` data structure, and it would be nice if +we did not have to change it. This can easily be accomplished by binding a +Lambda function instead: + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def("setName", &Pet::setName) + .def("getName", &Pet::getName) + .def("__repr__", + [](const Pet &a) { + return ""; + } + ); + +Both stateless [#f1]_ and stateful lambda closures are supported by pybind11. +With the above change, the same Python code now produces the following output: + +.. code-block:: pycon + + >>> print(p) + + +.. _properties: + +Instance and static fields +========================== + +We can also directly expose the ``name`` field using the +:func:`class_::def_readwrite` method. A similar :func:`class_::def_readonly` +method also exists for ``const`` fields. + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def_readwrite("name", &Pet::name) + // ... remainder ... + +This makes it possible to write + +.. code-block:: pycon + + >>> p = example.Pet('Molly') + >>> p.name + u'Molly' + >>> p.name = 'Charly' + >>> p.name + u'Charly' + +Now suppose that ``Pet::name`` was a private internal variable +that can only be accessed via setters and getters. + +.. code-block:: cpp + + class Pet { + public: + Pet(const std::string &name) : name(name) { } + void setName(const std::string &name_) { name = name_; } + const std::string &getName() const { return name; } + private: + std::string name; + }; + +In this case, the method :func:`class_::def_property` +(:func:`class_::def_property_readonly` for read-only data) can be used to +provide a field-like interface within Python that will transparently call +the setter and getter functions: + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def_property("name", &Pet::getName, &Pet::setName) + // ... remainder ... + +.. seealso:: + + Similar functions :func:`class_::def_readwrite_static`, + :func:`class_::def_readonly_static` :func:`class_::def_property_static`, + and :func:`class_::def_property_readonly_static` are provided for binding + static variables and properties. Please also see the section on + :ref:`static_properties` in the advanced part of the documentation. + +Dynamic attributes +================== + +Native Python classes can pick up new attributes dynamically: + +.. code-block:: pycon + + >>> class Pet: + ... name = 'Molly' + ... + >>> p = Pet() + >>> p.name = 'Charly' # overwrite existing + >>> p.age = 2 # dynamically add a new attribute + +By default, classes exported from C++ do not support this and the only writable +attributes are the ones explicitly defined using :func:`class_::def_readwrite` +or :func:`class_::def_property`. + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init<>()) + .def_readwrite("name", &Pet::name); + +Trying to set any other attribute results in an error: + +.. code-block:: pycon + + >>> p = example.Pet() + >>> p.name = 'Charly' # OK, attribute defined in C++ + >>> p.age = 2 # fail + AttributeError: 'Pet' object has no attribute 'age' + +To enable dynamic attributes for C++ classes, the :class:`py::dynamic_attr` tag +must be added to the :class:`py::class_` constructor: + +.. code-block:: cpp + + py::class_(m, "Pet", py::dynamic_attr()) + .def(py::init<>()) + .def_readwrite("name", &Pet::name); + +Now everything works as expected: + +.. code-block:: pycon + + >>> p = example.Pet() + >>> p.name = 'Charly' # OK, overwrite value in C++ + >>> p.age = 2 # OK, dynamically add a new attribute + >>> p.__dict__ # just like a native Python class + {'age': 2} + +Note that there is a small runtime cost for a class with dynamic attributes. +Not only because of the addition of a ``__dict__``, but also because of more +expensive garbage collection tracking which must be activated to resolve +possible circular references. Native Python classes incur this same cost by +default, so this is not anything to worry about. By default, pybind11 classes +are more efficient than native Python classes. Enabling dynamic attributes +just brings them on par. + +.. _inheritance: + +Inheritance +=========== + +Suppose now that the example consists of two data structures with an +inheritance relationship: + +.. code-block:: cpp + + struct Pet { + Pet(const std::string &name) : name(name) { } + std::string name; + }; + + struct Dog : Pet { + Dog(const std::string &name) : Pet(name) { } + std::string bark() const { return "woof!"; } + }; + +There are two different ways of indicating a hierarchical relationship to +pybind11: the first specifies the C++ base class as an extra template +parameter of the :class:`class_`: + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def_readwrite("name", &Pet::name); + + // Method 1: template parameter: + py::class_(m, "Dog") + .def(py::init()) + .def("bark", &Dog::bark); + +Alternatively, we can also assign a name to the previously bound ``Pet`` +:class:`class_` object and reference it when binding the ``Dog`` class: + +.. code-block:: cpp + + py::class_ pet(m, "Pet"); + pet.def(py::init()) + .def_readwrite("name", &Pet::name); + + // Method 2: pass parent class_ object: + py::class_(m, "Dog", pet /* <- specify Python parent type */) + .def(py::init()) + .def("bark", &Dog::bark); + +Functionality-wise, both approaches are equivalent. Afterwards, instances will +expose fields and methods of both types: + +.. code-block:: pycon + + >>> p = example.Dog('Molly') + >>> p.name + u'Molly' + >>> p.bark() + u'woof!' + +Overloaded methods +================== + +Sometimes there are several overloaded C++ methods with the same name taking +different kinds of input arguments: + +.. code-block:: cpp + + struct Pet { + Pet(const std::string &name, int age) : name(name), age(age) { } + + void set(int age) { age = age; } + void set(const std::string &name) { name = name; } + + std::string name; + int age; + }; + +Attempting to bind ``Pet::set`` will cause an error since the compiler does not +know which method the user intended to select. We can disambiguate by casting +them to function pointers. Binding multiple functions to the same Python name +automatically creates a chain of function overloads that will be tried in +sequence. + +.. code-block:: cpp + + py::class_(m, "Pet") + .def(py::init()) + .def("set", (void (Pet::*)(int)) &Pet::set, "Set the pet's age") + .def("set", (void (Pet::*)(const std::string &)) &Pet::set, "Set the pet's name"); + +The overload signatures are also visible in the method's docstring: + +.. code-block:: pycon + + >>> help(example.Pet) + + class Pet(__builtin__.object) + | Methods defined here: + | + | __init__(...) + | Signature : (Pet, str, int) -> NoneType + | + | set(...) + | 1. Signature : (Pet, int) -> NoneType + | + | Set the pet's age + | + | 2. Signature : (Pet, str) -> NoneType + | + | Set the pet's name + +.. note:: + + To define multiple overloaded constructors, simply declare one after the + other using the ``.def(py::init<...>())`` syntax. The existing machinery + for specifying keyword and default arguments also works. + +Enumerations and internal types +=============================== + +Let's now suppose that the example class contains an internal enumeration type, +e.g.: + +.. code-block:: cpp + + struct Pet { + enum Kind { + Dog = 0, + Cat + }; + + Pet(const std::string &name, Kind type) : name(name), type(type) { } + + std::string name; + Kind type; + }; + +The binding code for this example looks as follows: + +.. code-block:: cpp + + py::class_ pet(m, "Pet"); + + pet.def(py::init()) + .def_readwrite("name", &Pet::name) + .def_readwrite("type", &Pet::type); + + py::enum_(pet, "Kind") + .value("Dog", Pet::Kind::Dog) + .value("Cat", Pet::Kind::Cat) + .export_values(); + +To ensure that the ``Kind`` type is created within the scope of ``Pet``, the +``pet`` :class:`class_` instance must be supplied to the :class:`enum_`. +constructor. The :func:`enum_::export_values` function exports the enum entries +into the parent scope, which should be skipped for newer C++11-style strongly +typed enums. + +.. code-block:: pycon + + >>> p = Pet('Lucy', Pet.Cat) + >>> p.type + Kind.Cat + >>> int(p.type) + 1L + + +.. note:: + + When the special tag ``py::arithmetic()`` is specified to the ``enum_`` + constructor, pybind11 creates an enumeration that also supports rudimentary + arithmetic and bit-level operations like comparisons, and, or, xor, negation, + etc. + + .. code-block:: cpp + + py::enum_(pet, "Kind", py::arithmetic()) + ... + + By default, these are omitted to conserve space. + +.. [#f1] Stateless closures are those with an empty pair of brackets ``[]`` as the capture object. diff --git a/resources/pybind11/docs/compiling.rst b/resources/pybind11/docs/compiling.rst new file mode 100755 index 0000000..30cd83b --- /dev/null +++ b/resources/pybind11/docs/compiling.rst @@ -0,0 +1,53 @@ +Build systems +############# + +Building with setuptools +======================== + +For projects on PyPI, building with setuptools is the way to go. Sylvain Corlay +has kindly provided an example project which shows how to set up everything, +including automatic generation of documentation using Sphinx. Please refer to +the [python_example]_ repository. + +.. [python_example] https://github.com/pybind/python_example + +Building with cppimport +======================== + + cppimport is a small Python import hook that determines whether there is a C++ + source file whose name matches the requested module. If there is, the file is + compiled as a Python extension using pybind11 and placed in the same folder as + the C++ source file. Python is then able to find the module and load it. + +.. [cppimport] https://github.com/tbenthompson/cppimport + +.. _cmake: + +Building with CMake +=================== + +For C++ codebases that have an existing CMake-based build system, a Python +extension module can be created with just a few lines of code: + +.. code-block:: cmake + + cmake_minimum_required(VERSION 2.8.12) + project(example) + + add_subdirectory(pybind11) + pybind11_add_module(example example.cpp) + +This assumes that the pybind11 repository is located in a subdirectory named +:file:`pybind11` and that the code is located in a file named :file:`example.cpp`. +The CMake command ``add_subdirectory`` will import a function with the signature +``pybind11_add_module( source1 [source2 ...])``. It will take care of all +the details needed to build a Python extension module on any platform. + +The target Python version can be selected by setting the ``PYBIND11_PYTHON_VERSION`` +variable before adding the pybind11 subdirectory. Alternatively, an exact Python +installation can be specified by setting ``PYTHON_EXECUTABLE``. + +A working sample project, including a way to invoke CMake from :file:`setup.py` for +PyPI integration, can be found in the [cmake_example]_ repository. + +.. [cmake_example] https://github.com/pybind/cmake_example diff --git a/resources/pybind11/docs/conf.py b/resources/pybind11/docs/conf.py new file mode 100755 index 0000000..69f0cb3 --- /dev/null +++ b/resources/pybind11/docs/conf.py @@ -0,0 +1,308 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# pybind11 documentation build configuration file, created by +# sphinx-quickstart on Sun Oct 11 19:23:48 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['.templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'pybind11' +copyright = '2015, Wenzel Jakob' +author = 'Wenzel Jakob' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.9' +# The full version, including alpha/beta/rc tags. +release = '1.9.dev0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['.build', 'release.rst'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +#pygments_style = 'monokai' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. + +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + +if not on_rtd: # only import and set the theme if we're building docs locally + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + + html_context = { + 'css_files': [ + '_static/theme_overrides.css' + ] + } +else: + html_context = { + 'css_files': [ + '//media.readthedocs.org/css/sphinx_rtd_theme.css', + '//media.readthedocs.org/css/readthedocs-doc-embed.css', + '_static/theme_overrides.css' + ] + } + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'pybind11doc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +'preamble': '\DeclareUnicodeCharacter{00A0}{}', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'pybind11.tex', 'pybind11 Documentation', + 'Wenzel Jakob', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# latex_logo = 'pybind11-logo.png' + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'pybind11', 'pybind11 Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'pybind11', 'pybind11 Documentation', + author, 'pybind11', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + +primary_domain = 'cpp' +highlight_language = 'cpp' diff --git a/resources/pybind11/docs/faq.rst b/resources/pybind11/docs/faq.rst new file mode 100755 index 0000000..7f9bd35 --- /dev/null +++ b/resources/pybind11/docs/faq.rst @@ -0,0 +1,251 @@ +Frequently asked questions +########################## + +"ImportError: dynamic module does not define init function" +=========================================================== + +1. Make sure that the name specified in ``pybind::module`` and + ``PYBIND11_PLUGIN`` is consistent and identical to the filename of the + extension library. The latter should not contain any extra prefixes (e.g. + ``test.so`` instead of ``libtest.so``). + +2. If the above did not fix your issue, then you are likely using an + incompatible version of Python (for instance, the extension library was + compiled against Python 2, while the interpreter is running on top of some + version of Python 3, or vice versa) + +"Symbol not found: ``__Py_ZeroStruct`` / ``_PyInstanceMethod_Type``" +======================================================================== + +See item 2 of the first answer. + +"SystemError: dynamic module not initialized properly" +====================================================== + +See item 2 of the first answer. + +The Python interpreter immediately crashes when importing my module +=================================================================== + +See item 2 of the first answer. + +CMake doesn't detect the right Python version +============================================= + +The CMake-based build system will try to automatically detect the installed +version of Python and link against that. When this fails, or when there are +multiple versions of Python and it finds the wrong one, delete +``CMakeCache.txt`` and then invoke CMake as follows: + +.. code-block:: bash + + cmake -DPYTHON_EXECUTABLE:FILEPATH= . + +Limitations involving reference arguments +========================================= + +In C++, it's fairly common to pass arguments using mutable references or +mutable pointers, which allows both read and write access to the value +supplied by the caller. This is sometimes done for efficiency reasons, or to +realize functions that have multiple return values. Here are two very basic +examples: + +.. code-block:: cpp + + void increment(int &i) { i++; } + void increment_ptr(int *i) { (*i)++; } + +In Python, all arguments are passed by reference, so there is no general +issue in binding such code from Python. + +However, certain basic Python types (like ``str``, ``int``, ``bool``, +``float``, etc.) are **immutable**. This means that the following attempt +to port the function to Python doesn't have the same effect on the value +provided by the caller -- in fact, it does nothing at all. + +.. code-block:: python + + def increment(i): + i += 1 # nope.. + +pybind11 is also affected by such language-level conventions, which means that +binding ``increment`` or ``increment_ptr`` will also create Python functions +that don't modify their arguments. + +Although inconvenient, one workaround is to encapsulate the immutable types in +a custom type that does allow modifications. + +An other alternative involves binding a small wrapper lambda function that +returns a tuple with all output arguments (see the remainder of the +documentation for examples on binding lambda functions). An example: + +.. code-block:: cpp + + int foo(int &i) { i++; return 123; } + +and the binding code + +.. code-block:: cpp + + m.def("foo", [](int i) { int rv = foo(i); return std::make_tuple(rv, i); }); + + +How can I reduce the build time? +================================ + +It's good practice to split binding code over multiple files, as in the +following example: + +:file:`example.cpp`: + +.. code-block:: cpp + + void init_ex1(py::module &); + void init_ex2(py::module &); + /* ... */ + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind example plugin"); + + init_ex1(m); + init_ex2(m); + /* ... */ + + return m.ptr(); + } + +:file:`ex1.cpp`: + +.. code-block:: cpp + + void init_ex1(py::module &m) { + m.def("add", [](int a, int b) { return a + b; }); + } + +:file:`ex2.cpp`: + +.. code-block:: cpp + + void init_ex1(py::module &m) { + m.def("sub", [](int a, int b) { return a - b; }); + } + +:command:`python`: + +.. code-block:: pycon + + >>> import example + >>> example.add(1, 2) + 3 + >>> example.sub(1, 1) + 0 + +As shown above, the various ``init_ex`` functions should be contained in +separate files that can be compiled independently from one another, and then +linked together into the same final shared object. Following this approach +will: + +1. reduce memory requirements per compilation unit. + +2. enable parallel builds (if desired). + +3. allow for faster incremental builds. For instance, when a single class + definition is changed, only a subset of the binding code will generally need + to be recompiled. + +"recursive template instantiation exceeded maximum depth of 256" +================================================================ + +If you receive an error about excessive recursive template evaluation, try +specifying a larger value, e.g. ``-ftemplate-depth=1024`` on GCC/Clang. The +culprit is generally the generation of function signatures at compile time +using C++14 template metaprogramming. + + +How can I create smaller binaries? +================================== + +To do its job, pybind11 extensively relies on a programming technique known as +*template metaprogramming*, which is a way of performing computation at compile +time using type information. Template metaprogamming usually instantiates code +involving significant numbers of deeply nested types that are either completely +removed or reduced to just a few instructions during the compiler's optimization +phase. However, due to the nested nature of these types, the resulting symbol +names in the compiled extension library can be extremely long. For instance, +the included test suite contains the following symbol: + +.. only:: html + + .. code-block:: none + + _​_​Z​N​8​p​y​b​i​n​d​1​1​1​2​c​p​p​_​f​u​n​c​t​i​o​n​C​1​I​v​8​E​x​a​m​p​l​e​2​J​R​N​S​t​3​_​_​1​6​v​e​c​t​o​r​I​N​S​3​_​1​2​b​a​s​i​c​_​s​t​r​i​n​g​I​w​N​S​3​_​1​1​c​h​a​r​_​t​r​a​i​t​s​I​w​E​E​N​S​3​_​9​a​l​l​o​c​a​t​o​r​I​w​E​E​E​E​N​S​8​_​I​S​A​_​E​E​E​E​E​J​N​S​_​4​n​a​m​e​E​N​S​_​7​s​i​b​l​i​n​g​E​N​S​_​9​i​s​_​m​e​t​h​o​d​E​A​2​8​_​c​E​E​E​M​T​0​_​F​T​_​D​p​T​1​_​E​D​p​R​K​T​2​_ + +.. only:: not html + + .. code-block:: cpp + + __ZN8pybind1112cpp_functionC1Iv8Example2JRNSt3__16vectorINS3_12basic_stringIwNS3_11char_traitsIwEENS3_9allocatorIwEEEENS8_ISA_EEEEEJNS_4nameENS_7siblingENS_9is_methodEA28_cEEEMT0_FT_DpT1_EDpRKT2_ + +which is the mangled form of the following function type: + +.. code-block:: cpp + + pybind11::cpp_function::cpp_function, std::__1::allocator >, std::__1::allocator, std::__1::allocator > > >&, pybind11::name, pybind11::sibling, pybind11::is_method, char [28]>(void (Example2::*)(std::__1::vector, std::__1::allocator >, std::__1::allocator, std::__1::allocator > > >&), pybind11::name const&, pybind11::sibling const&, pybind11::is_method const&, char const (&) [28]) + +The memory needed to store just the mangled name of this function (196 bytes) +is larger than the actual piece of code (111 bytes) it represents! On the other +hand, it's silly to even give this function a name -- after all, it's just a +tiny cog in a bigger piece of machinery that is not exposed to the outside +world. So we'll generally only want to export symbols for those functions which +are actually called from the outside. + +This can be achieved by specifying the parameter ``-fvisibility=hidden`` to GCC +and Clang, which sets the default symbol visibility to *hidden*. It's best to +do this only for release builds, since the symbol names can be helpful in +debugging sessions. On Visual Studio, symbols are already hidden by default, so +nothing needs to be done there. Needless to say, this has a tremendous impact +on the final binary size of the resulting extension library. + +Another aspect that can require a fair bit of code are function signature +descriptions. pybind11 automatically generates human-readable function +signatures for docstrings, e.g.: + +.. code-block:: none + + | __init__(...) + | __init__(*args, **kwargs) + | Overloaded function. + | + | 1. __init__(example.Example1) -> NoneType + | + | Docstring for overload #1 goes here + | + | 2. __init__(example.Example1, int) -> NoneType + | + | Docstring for overload #2 goes here + | + | 3. __init__(example.Example1, example.Example1) -> NoneType + | + | Docstring for overload #3 goes here + + +In C++11 mode, these are generated at run time using string concatenation, +which can amount to 10-20% of the size of the resulting binary. If you can, +enable C++14 language features (using ``-std=c++14`` for GCC/Clang), in which +case signatures are efficiently pre-generated at compile time. Unfortunately, +Visual Studio's C++14 support (``constexpr``) is not good enough as of April +2016, so it always uses the more expensive run-time approach. + +Working with ancient Visual Studio 2009 builds on Windows +========================================================= + +The official Windows distributions of Python are compiled using truly +ancient versions of Visual Studio that lack good C++11 support. Some users +implicitly assume that it would be impossible to load a plugin built with +Visual Studio 2015 into a Python distribution that was compiled using Visual +Studio 2009. However, no such issue exists: it's perfectly legitimate to +interface DLLs that are built with different compilers and/or C libraries. +Common gotchas to watch out for involve not ``free()``-ing memory region +that that were ``malloc()``-ed in another shared library, using data +structures with incompatible ABIs, and so on. pybind11 is very careful not +to make these types of mistakes. diff --git a/resources/pybind11/docs/index.rst b/resources/pybind11/docs/index.rst new file mode 100755 index 0000000..cedf652 --- /dev/null +++ b/resources/pybind11/docs/index.rst @@ -0,0 +1,45 @@ +.. only: not latex + + .. image:: pybind11-logo.png + +pybind11 --- Seamless operability between C++11 and Python +========================================================== + +.. only: not latex + + Contents: + +.. toctree:: + :maxdepth: 1 + + intro + changelog + +.. toctree:: + :caption: The Basics + :maxdepth: 2 + + basics + classes + compiling + +.. toctree:: + :caption: Advanced Topics + :maxdepth: 2 + + advanced/functions + advanced/classes + advanced/exceptions + advanced/smart_ptrs + advanced/cast/index + advanced/pycpp/index + advanced/misc + +.. toctree:: + :caption: Extra Information + :maxdepth: 1 + + faq + benchmark + limitations + reference diff --git a/resources/pybind11/docs/intro.rst b/resources/pybind11/docs/intro.rst new file mode 100755 index 0000000..429a01c --- /dev/null +++ b/resources/pybind11/docs/intro.rst @@ -0,0 +1,93 @@ +.. image:: pybind11-logo.png + +About this project +================== +**pybind11** is a lightweight header-only library that exposes C++ types in Python +and vice versa, mainly to create Python bindings of existing C++ code. Its +goals and syntax are similar to the excellent `Boost.Python`_ library by David +Abrahams: to minimize boilerplate code in traditional extension modules by +inferring type information using compile-time introspection. + +.. _Boost.Python: http://www.boost.org/doc/libs/release/libs/python/doc/index.html + +The main issue with Boost.Python—and the reason for creating such a similar +project—is Boost. Boost is an enormously large and complex suite of utility +libraries that works with almost every C++ compiler in existence. This +compatibility has its cost: arcane template tricks and workarounds are +necessary to support the oldest and buggiest of compiler specimens. Now that +C++11-compatible compilers are widely available, this heavy machinery has +become an excessively large and unnecessary dependency. + +Think of this library as a tiny self-contained version of Boost.Python with +everything stripped away that isn't relevant for binding generation. Without +comments, the core header files only require ~2.5K lines of code and depend 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 (specifically: +tuples, lambda functions and variadic templates). Since its creation, this +library has grown beyond Boost.Python in many ways, leading to dramatically +simpler binding code in many common situations. + +Core features +************* +The following core C++ features can be mapped to Python + +- Functions accepting and returning custom data structures per value, reference, or pointer +- Instance methods and static methods +- Overloaded functions +- Instance attributes and static attributes +- Arbitrary exception types +- Enumerations +- Callbacks +- Iterators and ranges +- Custom operators +- Single and multiple inheritance +- STL data structures +- Iterators and ranges +- Smart pointers with reference counting like ``std::shared_ptr`` +- Internal references with correct reference counting +- C++ classes with virtual (and pure virtual) methods can be extended in Python + +Goodies +******* +In addition to the core functionality, pybind11 provides some extra goodies: + +- It is possible to bind C++11 lambda functions with captured variables. The + lambda capture data is stored inside the resulting Python function object. + +- pybind11 uses C++11 move constructors and move assignment operators whenever + possible to efficiently transfer custom data types. + +- It's easy to expose the internal storage of custom data types through + Pythons' buffer protocols. This is handy e.g. for fast conversion between + C++ matrix classes like Eigen and NumPy without expensive copy operations. + +- pybind11 can automatically vectorize functions so that they are transparently + applied to all entries of one or more NumPy array arguments. + +- Python's slice-based access and assignment operations can be supported with + just a few lines of code. + +- Everything is contained in just a few header files; there is no need to link + against any additional libraries. + +- Binaries are generally smaller by a factor of at least 2 compared to + equivalent bindings generated by Boost.Python. A recent pybind11 conversion + of `PyRosetta`_, an enormous Boost.Python binding project, reported a binary + size reduction of **5.4x** and compile time reduction by **5.8x**. + +- When supported by the compiler, two new C++14 features (relaxed constexpr and + return value deduction) are used to precompute function signatures at compile + time, leading to smaller binaries. + +- With little extra effort, C++ types can be pickled and unpickled similar to + regular Python objects. + +.. _PyRosetta: http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf + +Supported compilers +******************* + +1. Clang/LLVM (any non-ancient version with C++11 support) +2. GCC (any non-ancient version with C++11 support) +3. Microsoft Visual Studio 2015 or newer +4. Intel C++ compiler v15 or newer diff --git a/resources/pybind11/docs/limitations.rst b/resources/pybind11/docs/limitations.rst new file mode 100755 index 0000000..a1a4f1a --- /dev/null +++ b/resources/pybind11/docs/limitations.rst @@ -0,0 +1,20 @@ +Limitations +########### + +pybind11 strives to be a general solution to binding generation, but it also has +certain limitations: + +- pybind11 casts away ``const``-ness in function arguments and return values. + This is in line with the Python language, which has no concept of ``const`` + values. This means that some additional care is needed to avoid bugs that + would be caught by the type checker in a traditional C++ program. + +- The NumPy interface ``pybind11::array`` greatly simplifies accessing + numerical data from C++ (and vice versa), but it's not a full-blown array + class like ``Eigen::Array`` or ``boost.multi_array``. + +These features could be implemented but would lead to a significant increase in +complexity. I've decided to draw the line here to keep this project simple and +compact. Users who absolutely require these features are encouraged to fork +pybind11. + diff --git a/resources/pybind11/docs/pybind11-logo.png b/resources/pybind11/docs/pybind11-logo.png new file mode 100755 index 0000000000000000000000000000000000000000..4cbad54f797d3ced04d4048f282df5e4336d4af4 GIT binary patch literal 58510 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/pybind11/docs/pybind11_vs_boost_python2.png b/resources/pybind11/docs/pybind11_vs_boost_python2.png new file mode 100755 index 0000000000000000000000000000000000000000..9f17272c50663957d6ae6d8e23fdd5a15757e71f GIT binary patch literal 41121 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 BtT6xp literal 0 HcmV?d00001 diff --git a/resources/pybind11/docs/pybind11_vs_boost_python2.svg b/resources/pybind11/docs/pybind11_vs_boost_python2.svg new file mode 100755 index 0000000..5ed6530 --- /dev/null +++ b/resources/pybind11/docs/pybind11_vs_boost_python2.svg @@ -0,0 +1,427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/pybind11/docs/reference.rst b/resources/pybind11/docs/reference.rst new file mode 100755 index 0000000..542259e --- /dev/null +++ b/resources/pybind11/docs/reference.rst @@ -0,0 +1,247 @@ +.. _reference: + +.. warning:: + + Please be advised that the reference documentation discussing pybind11 + internals is currently incomplete. Please refer to the previous sections + and the pybind11 header files for the nitty gritty details. + +Reference +######### + +Macros +====== + +.. function:: PYBIND11_PLUGIN(const char *name) + + This macro creates the entry point that will be invoked when the Python + interpreter imports a plugin library. Please create a + :class:`module` in the function body and return the pointer to its + underlying Python object at the end. + + .. code-block:: cpp + + PYBIND11_PLUGIN(example) { + pybind11::module m("example", "pybind11 example plugin"); + /// Set up bindings here + return m.ptr(); + } + +.. _core_types: + +Convenience classes for arbitrary Python types +============================================== + +Without reference counting +-------------------------- + +.. class:: handle + + The :class:`handle` class is a thin wrapper around an arbitrary Python + object (i.e. a ``PyObject *`` in Python's C API). It does not perform any + automatic reference counting and merely provides a basic C++ interface to + various Python API functions. + +.. seealso:: + + The :class:`object` class inherits from :class:`handle` and adds automatic + reference counting features. + +.. function:: handle::handle() + + The default constructor creates a handle with a ``nullptr``-valued pointer. + +.. function:: handle::handle(const handle&) + + Copy constructor + +.. function:: handle::handle(PyObject *) + + Creates a :class:`handle` from the given raw Python object pointer. + +.. function:: PyObject * handle::ptr() const + + Return the ``PyObject *`` underlying a :class:`handle`. + +.. function:: const handle& handle::inc_ref() const + + Manually increase the reference count of the Python object. Usually, it is + preferable to use the :class:`object` class which derives from + :class:`handle` and calls this function automatically. Returns a reference + to itself. + +.. function:: const handle& handle::dec_ref() const + + Manually decrease the reference count of the Python object. Usually, it is + preferable to use the :class:`object` class which derives from + :class:`handle` and calls this function automatically. Returns a reference + to itself. + +.. function:: void handle::ref_count() const + + Return the object's current reference count + +.. function:: handle handle::get_type() const + + Return a handle to the Python type object underlying the instance + +.. function detail::accessor handle::operator[](handle key) const + + Return an internal functor to invoke the object's sequence protocol. + Casting the returned ``detail::accessor`` instance to a :class:`handle` or + :class:`object` subclass causes a corresponding call to ``__getitem__``. + Assigning a :class:`handle` or :class:`object` subclass causes a call to + ``__setitem__``. + +.. function detail::accessor handle::operator[](const char *key) const + + See the above function (the only difference is that they key is provided as + a string literal). + +.. function detail::accessor handle::attr(handle key) const + + Return an internal functor to access the object's attributes. + Casting the returned ``detail::accessor`` instance to a :class:`handle` or + :class:`object` subclass causes a corresponding call to ``__getattr``. + Assigning a :class:`handle` or :class:`object` subclass causes a call to + ``__setattr``. + +.. function detail::accessor handle::attr(const char *key) const + + See the above function (the only difference is that they key is provided as + a string literal). + +.. function operator handle::bool() const + + Return ``true`` when the :class:`handle` wraps a valid Python object. + +.. function str handle::str() const + + Return a string representation of the object. This is analogous to + the ``str()`` function in Python. + +.. function:: template T handle::cast() const + + Attempt to cast the Python object into the given C++ type. A + :class:`cast_error` will be throw upon failure. + +.. function:: template object handle::call(Args&&... args) const + + Assuming the Python object is a function or implements the ``__call__`` + protocol, ``call()`` invokes the underlying function, passing an arbitrary + set of parameters. The result is returned as a :class:`object` and may need + to be converted back into a Python object using :func:`handle::cast`. + + When some of the arguments cannot be converted to Python objects, the + function will throw a :class:`cast_error` exception. When the Python + function call fails, a :class:`error_already_set` exception is thrown. + +With reference counting +----------------------- + +.. class:: object : public handle + + Like :class:`handle`, the object class is a thin wrapper around an + arbitrary Python object (i.e. a ``PyObject *`` in Python's C API). In + contrast to :class:`handle`, it optionally increases the object's reference + count upon construction, and it *always* decreases the reference count when + the :class:`object` instance goes out of scope and is destructed. When + using :class:`object` instances consistently, it is much easier to get + reference counting right at the first attempt. + +.. function:: object::object(const object &o) + + Copy constructor; always increases the reference count + +.. function:: object::object(const handle &h, bool borrowed) + + Creates a :class:`object` from the given :class:`handle`. The reference + count is only increased if the ``borrowed`` parameter is set to ``true``. + +.. function:: object::object(PyObject *ptr, bool borrowed) + + Creates a :class:`object` from the given raw Python object pointer. The + reference count is only increased if the ``borrowed`` parameter is set to + ``true``. + +.. function:: object::object(object &&other) + + Move constructor; steals the object from ``other`` and preserves its + reference count. + +.. function:: handle object::release() + + Resets the internal pointer to ``nullptr`` without without decreasing the + object's reference count. The function returns a raw handle to the original + Python object. + +.. function:: object::~object() + + Destructor, which automatically calls :func:`handle::dec_ref()`. + +Convenience classes for specific Python types +============================================= + + +.. class:: module : public object + +.. function:: module::module(const char *name, const char *doc = nullptr) + + Create a new top-level Python module with the given name and docstring + +.. function:: module module::def_submodule(const char *name, const char *doc = nullptr) + + Create and return a new Python submodule with the given name and docstring. + This also works recursively, i.e. + + .. code-block:: cpp + + pybind11::module m("example", "pybind11 example plugin"); + pybind11::module m2 = m.def_submodule("sub", "A submodule of 'example'"); + pybind11::module m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'"); + +.. cpp:function:: template module& module::def(const char *name, Func && f, Extra && ... extra) + + Create Python binding for a new function within the module scope. ``Func`` + can be a plain C++ function, a function pointer, or a lambda function. For + details on the ``Extra&& ... extra`` argument, see section :ref:`extras`. + +.. _extras: + +Passing extra arguments to the def function +=========================================== + +.. class:: arg + +.. function:: arg::arg(const char *name) + +.. function:: template arg_v arg::operator=(T &&value) + +.. class:: arg_v : public arg + + Represents a named argument with a default value + +.. class:: sibling + + Used to specify a handle to an existing sibling function; used internally + to implement function overloading in :func:`module::def` and + :func:`class_::def`. + +.. function:: sibling::sibling(handle handle) + +.. class doc + + This is class is internally used by pybind11. + +.. function:: doc::doc(const char *value) + + Create a new docstring with the specified value + +.. class name + + This is class is internally used by pybind11. + +.. function:: name::name(const char *value) + + Used to specify the function name + diff --git a/resources/pybind11/docs/release.rst b/resources/pybind11/docs/release.rst new file mode 100755 index 0000000..a15504e --- /dev/null +++ b/resources/pybind11/docs/release.rst @@ -0,0 +1,22 @@ +To release a new version of pybind11: + +- Update the version number and push to pypi + - Update ``pybind11/_version.py`` (set release version, remove 'dev') + - Update version in ``docs/conf.py`` + - Tag release date in ``docs/changelog.rst``. + - ``git add`` and ``git commit``. + - if new minor version: ``git checkout -b vX.Y``, ``git push -u origin vX.Y`` + - ``git tag -a vX.Y.Z -m 'vX.Y.Z release'``. + - ``git push`` + - ``git push --tags``. + - ``python setup.py sdist upload``. + - ``python setup.py bdist_wheel upload``. +- Update conda-forge (https://github.com/conda-forge/pybind11-feedstock) via PR + - change version number in ``recipe/meta.yml`` + - update checksum to match the one computed by pypi +- Get back to work + - Update ``_version.py`` (add 'dev' and increment minor). + - Update version in ``docs/conf.py`` + - Update version macros in ``include/pybind11/common.h`` + - ``git add`` and ``git commit``. + ``git push`` diff --git a/resources/pybind11/include/pybind11/attr.h b/resources/pybind11/include/pybind11/attr.h new file mode 100755 index 0000000..448612c --- /dev/null +++ b/resources/pybind11/include/pybind11/attr.h @@ -0,0 +1,362 @@ +/* + pybind11/pybind11.h: Infrastructure for processing custom + type and function attributes + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "cast.h" + +NAMESPACE_BEGIN(pybind11) + +/// Annotation for methods +struct is_method { handle class_; is_method(const handle &c) : class_(c) { } }; + +/// Annotation for operators +struct is_operator { }; + +/// Annotation for parent scope +struct scope { handle value; scope(const handle &s) : value(s) { } }; + +/// Annotation for documentation +struct doc { const char *value; doc(const char *value) : value(value) { } }; + +/// Annotation for function names +struct name { const char *value; name(const char *value) : value(value) { } }; + +/// Annotation indicating that a function is an overload associated with a given "sibling" +struct sibling { handle value; sibling(const handle &value) : value(value.ptr()) { } }; + +/// Annotation indicating that a class derives from another given type +template struct base { + PYBIND11_DEPRECATED("base() was deprecated in favor of specifying 'T' as a template argument to class_") + base() { } +}; + +/// Keep patient alive while nurse lives +template struct keep_alive { }; + +/// Annotation indicating that a class is involved in a multiple inheritance relationship +struct multiple_inheritance { }; + +/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class +struct dynamic_attr { }; + +/// Annotation to mark enums as an arithmetic type +struct arithmetic { }; + +NAMESPACE_BEGIN(detail) +/* Forward declarations */ +enum op_id : int; +enum op_type : int; +struct undefined_t; +template struct op_; +template struct init; +template struct init_alias; +inline void keep_alive_impl(int Nurse, int Patient, handle args, handle ret); + +/// Internal data structure which holds metadata about a keyword argument +struct argument_record { + const char *name; ///< Argument name + const char *descr; ///< Human-readable version of the argument value + handle value; ///< Associated Python object + + argument_record(const char *name, const char *descr, handle value) + : name(name), descr(descr), value(value) { } +}; + +/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.) +struct function_record { + function_record() + : is_constructor(false), is_stateless(false), is_operator(false), + has_args(false), has_kwargs(false), is_method(false) { } + + /// Function name + char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ + + // User-specified documentation string + char *doc = nullptr; + + /// Human-readable version of the function signature + char *signature = nullptr; + + /// List of registered keyword arguments + std::vector args; + + /// Pointer to lambda function which converts arguments and performs the actual call + handle (*impl) (function_record *, handle, handle, handle) = nullptr; + + /// Storage for the wrapped function pointer and captured data, if any + void *data[3] = { }; + + /// Pointer to custom destructor for 'data' (if needed) + void (*free_data) (function_record *ptr) = nullptr; + + /// Return value policy associated with this function + return_value_policy policy = return_value_policy::automatic; + + /// True if name == '__init__' + bool is_constructor : 1; + + /// True if this is a stateless function pointer + bool is_stateless : 1; + + /// True if this is an operator (__add__), etc. + bool is_operator : 1; + + /// True if the function has a '*args' argument + bool has_args : 1; + + /// True if the function has a '**kwargs' argument + bool has_kwargs : 1; + + /// True if this is a method + bool is_method : 1; + + /// Number of arguments + uint16_t nargs; + + /// Python method object + PyMethodDef *def = nullptr; + + /// Python handle to the parent scope (a class or a module) + handle scope; + + /// Python handle to the sibling function representing an overload chain + handle sibling; + + /// Pointer to next overload + function_record *next = nullptr; +}; + +/// Special data structure which (temporarily) holds metadata about a bound class +struct type_record { + PYBIND11_NOINLINE type_record() { } + + /// Handle to the parent scope + handle scope; + + /// Name of the class + const char *name = nullptr; + + // Pointer to RTTI type_info data structure + const std::type_info *type = nullptr; + + /// How large is the underlying C++ type? + size_t type_size = 0; + + /// How large is pybind11::instance? + size_t instance_size = 0; + + /// Function pointer to class_<..>::init_holder + void (*init_holder)(PyObject *, const void *) = nullptr; + + /// Function pointer to class_<..>::dealloc + void (*dealloc)(PyObject *) = nullptr; + + /// List of base classes of the newly created type + list bases; + + /// Optional docstring + const char *doc = nullptr; + + /// Multiple inheritance marker + bool multiple_inheritance = false; + + /// Does the class manage a __dict__? + bool dynamic_attr = false; + + PYBIND11_NOINLINE void add_base(const std::type_info *base, void *(*caster)(void *)) { + auto base_info = detail::get_type_info(*base, false); + if (!base_info) { + std::string tname(base->name()); + detail::clean_type_id(tname); + pybind11_fail("generic_type: type \"" + std::string(name) + + "\" referenced unknown base type \"" + tname + "\""); + } + + bases.append((PyObject *) base_info->type); + + if (base_info->type->tp_dictoffset != 0) + dynamic_attr = true; + + if (caster) + base_info->implicit_casts.push_back(std::make_pair(type, caster)); + } +}; + +/** + * Partial template specializations to process custom attributes provided to + * cpp_function_ and class_. These are either used to initialize the respective + * fields in the type_record and function_record data structures or executed at + * runtime to deal with custom call policies (e.g. keep_alive). + */ +template struct process_attribute; + +template struct process_attribute_default { + /// Default implementation: do nothing + static void init(const T &, function_record *) { } + static void init(const T &, type_record *) { } + static void precall(handle) { } + static void postcall(handle, handle) { } +}; + +/// Process an attribute specifying the function's name +template <> struct process_attribute : process_attribute_default { + static void init(const name &n, function_record *r) { r->name = const_cast(n.value); } +}; + +/// Process an attribute specifying the function's docstring +template <> struct process_attribute : process_attribute_default { + static void init(const doc &n, function_record *r) { r->doc = const_cast(n.value); } +}; + +/// Process an attribute specifying the function's docstring (provided as a C-style string) +template <> struct process_attribute : process_attribute_default { + static void init(const char *d, function_record *r) { r->doc = const_cast(d); } + static void init(const char *d, type_record *r) { r->doc = const_cast(d); } +}; +template <> struct process_attribute : process_attribute { }; + +/// Process an attribute indicating the function's return value policy +template <> struct process_attribute : process_attribute_default { + static void init(const return_value_policy &p, function_record *r) { r->policy = p; } +}; + +/// Process an attribute which indicates that this is an overloaded function associated with a given sibling +template <> struct process_attribute : process_attribute_default { + static void init(const sibling &s, function_record *r) { r->sibling = s.value; } +}; + +/// Process an attribute which indicates that this function is a method +template <> struct process_attribute : process_attribute_default { + static void init(const is_method &s, function_record *r) { r->is_method = true; r->scope = s.class_; } +}; + +/// Process an attribute which indicates the parent scope of a method +template <> struct process_attribute : process_attribute_default { + static void init(const scope &s, function_record *r) { r->scope = s.value; } +}; + +/// Process an attribute which indicates that this function is an operator +template <> struct process_attribute : process_attribute_default { + static void init(const is_operator &, function_record *r) { r->is_operator = true; } +}; + +/// Process a keyword argument attribute (*without* a default value) +template <> struct process_attribute : process_attribute_default { + static void init(const arg &a, function_record *r) { + if (r->is_method && r->args.empty()) + r->args.emplace_back("self", nullptr, handle()); + r->args.emplace_back(a.name, nullptr, handle()); + } +}; + +/// Process a keyword argument attribute (*with* a default value) +template <> struct process_attribute : process_attribute_default { + static void init(const arg_v &a, function_record *r) { + if (r->is_method && r->args.empty()) + r->args.emplace_back("self", nullptr, handle()); + + if (!a.value) { +#if !defined(NDEBUG) + auto descr = "'" + std::string(a.name) + ": " + a.type + "'"; + if (r->is_method) { + if (r->name) + descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'"; + else + descr += " in method of '" + (std::string) str(r->scope) + "'"; + } else if (r->name) { + descr += " in function named '" + (std::string) r->name + "'"; + } + pybind11_fail("arg(): could not convert default keyword argument " + + descr + " into a Python object (type not registered yet?)"); +#else + pybind11_fail("arg(): could not convert default keyword argument " + "into a Python object (type not registered yet?). " + "Compile in debug mode for more information."); +#endif + } + r->args.emplace_back(a.name, a.descr, a.value.inc_ref()); + } +}; + +/// Process a parent class attribute +template +struct process_attribute::value>> : process_attribute_default { + static void init(const handle &h, type_record *r) { r->bases.append(h); } +}; + +/// Process a parent class attribute (deprecated, does not support multiple inheritance) +template +struct process_attribute> : process_attribute_default> { + static void init(const base &, type_record *r) { r->add_base(&typeid(T), nullptr); } +}; + +/// Process a multiple inheritance attribute +template <> +struct process_attribute : process_attribute_default { + static void init(const multiple_inheritance &, type_record *r) { r->multiple_inheritance = true; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; } +}; + + +/// Process an 'arithmetic' attribute for enums (does nothing here) +template <> +struct process_attribute : process_attribute_default {}; + +/*** + * Process a keep_alive call policy -- invokes keep_alive_impl during the + * pre-call handler if both Nurse, Patient != 0 and use the post-call handler + * otherwise + */ +template struct process_attribute> : public process_attribute_default> { + template = 0> + static void precall(handle args) { keep_alive_impl(Nurse, Patient, args, handle()); } + template = 0> + static void postcall(handle, handle) { } + template = 0> + static void precall(handle) { } + template = 0> + static void postcall(handle args, handle ret) { keep_alive_impl(Nurse, Patient, args, ret); } +}; + +/// Recursively iterate over variadic template arguments +template struct process_attributes { + static void init(const Args&... args, function_record *r) { + int unused[] = { 0, (process_attribute::type>::init(args, r), 0) ... }; + ignore_unused(unused); + } + static void init(const Args&... args, type_record *r) { + int unused[] = { 0, (process_attribute::type>::init(args, r), 0) ... }; + ignore_unused(unused); + } + static void precall(handle fn_args) { + int unused[] = { 0, (process_attribute::type>::precall(fn_args), 0) ... }; + ignore_unused(unused); + } + static void postcall(handle fn_args, handle fn_ret) { + int unused[] = { 0, (process_attribute::type>::postcall(fn_args, fn_ret), 0) ... }; + ignore_unused(unused); + } +}; + +/// Check the number of named arguments at compile time +template ::value...), + size_t self = constexpr_sum(std::is_same::value...)> +constexpr bool expected_num_args(size_t nargs) { + return named == 0 || (self + named) == nargs; +} + +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/resources/pybind11/include/pybind11/cast.h b/resources/pybind11/include/pybind11/cast.h new file mode 100755 index 0000000..6cdc482 --- /dev/null +++ b/resources/pybind11/include/pybind11/cast.h @@ -0,0 +1,1464 @@ +/* + pybind11/cast.h: Partial template specializations to cast between + C++ and Python types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pytypes.h" +#include "typeid.h" +#include "descr.h" +#include +#include + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + +/// Additional type information which does not fit into the PyTypeObject +struct type_info { + PyTypeObject *type; + size_t type_size; + void (*init_holder)(PyObject *, const void *); + std::vector implicit_conversions; + std::vector> implicit_casts; + std::vector *direct_conversions; + buffer_info *(*get_buffer)(PyObject *, void *) = nullptr; + void *get_buffer_data = nullptr; + /** A simple type never occurs as a (direct or indirect) parent + * of a class that makes use of multiple inheritance */ + bool simple_type = true; +}; + +PYBIND11_NOINLINE inline internals &get_internals() { + static internals *internals_ptr = nullptr; + if (internals_ptr) + return *internals_ptr; + handle builtins(PyEval_GetBuiltins()); + const char *id = PYBIND11_INTERNALS_ID; + if (builtins.contains(id) && isinstance(builtins[id])) { + internals_ptr = capsule(builtins[id]); + } else { + internals_ptr = new internals(); + #if defined(WITH_THREAD) + PyEval_InitThreads(); + PyThreadState *tstate = PyThreadState_Get(); + internals_ptr->tstate = PyThread_create_key(); + PyThread_set_key_value(internals_ptr->tstate, tstate); + internals_ptr->istate = tstate->interp; + #endif + builtins[id] = capsule(internals_ptr); + internals_ptr->registered_exception_translators.push_front( + [](std::exception_ptr p) -> void { + try { + if (p) std::rethrow_exception(p); + } catch (error_already_set &e) { e.restore(); return; + } catch (const builtin_exception &e) { e.set_error(); return; + } catch (const std::bad_alloc &e) { PyErr_SetString(PyExc_MemoryError, e.what()); return; + } catch (const std::domain_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::length_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::out_of_range &e) { PyErr_SetString(PyExc_IndexError, e.what()); return; + } catch (const std::range_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return; + } catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!"); + return; + } + } + ); + } + return *internals_ptr; +} + +PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) { + auto const &type_dict = get_internals().registered_types_py; + do { + auto it = type_dict.find(type); + if (it != type_dict.end()) + return (detail::type_info *) it->second; + type = type->tp_base; + if (!type) + return nullptr; + } while (true); +} + +PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_info &tp, + bool throw_if_missing = false) { + auto &types = get_internals().registered_types_cpp; + + auto it = types.find(std::type_index(tp)); + if (it != types.end()) + return (detail::type_info *) it->second; + if (throw_if_missing) { + std::string tname = tp.name(); + detail::clean_type_id(tname); + pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + tname + "\""); + } + return nullptr; +} + +PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp, bool throw_if_missing) { + detail::type_info *type_info = get_type_info(tp, throw_if_missing); + return handle(type_info ? ((PyObject *) type_info->type) : nullptr); +} + +PYBIND11_NOINLINE inline bool isinstance_generic(handle obj, const std::type_info &tp) { + const auto type = detail::get_type_handle(tp, false); + if (!type) + return false; + + const auto result = PyObject_IsInstance(obj.ptr(), type.ptr()); + if (result == -1) + throw error_already_set(); + return result != 0; +} + +PYBIND11_NOINLINE inline std::string error_string() { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred"); + return "Unknown internal error occurred"; + } + + error_scope scope; // Preserve error state + + std::string errorString; + if (scope.type) { + errorString += handle(scope.type).attr("__name__").cast(); + errorString += ": "; + } + if (scope.value) + errorString += (std::string) str(scope.value); + + PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace); + +#if PY_MAJOR_VERSION >= 3 + if (scope.trace != nullptr) + PyException_SetTraceback(scope.value, scope.trace); +#endif + + if (scope.trace) { + PyTracebackObject *trace = (PyTracebackObject *) scope.trace; + + /* Get the deepest trace possible */ + while (trace->tb_next) + trace = trace->tb_next; + + PyFrameObject *frame = trace->tb_frame; + errorString += "\n\nAt:\n"; + while (frame) { + int lineno = PyFrame_GetLineNumber(frame); + errorString += + " " + handle(frame->f_code->co_filename).cast() + + "(" + std::to_string(lineno) + "): " + + handle(frame->f_code->co_name).cast() + "\n"; + frame = frame->f_back; + } + trace = trace->tb_next; + } + + return errorString; +} + +PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail::type_info *type ) { + auto &instances = get_internals().registered_instances; + auto range = instances.equal_range(ptr); + for (auto it = range.first; it != range.second; ++it) { + auto instance_type = detail::get_type_info(Py_TYPE(it->second)); + if (instance_type && instance_type == type) + return handle((PyObject *) it->second); + } + return handle(); +} + +inline PyThreadState *get_thread_state_unchecked() { +#if PY_VERSION_HEX < 0x03000000 + return _PyThreadState_Current; +#elif PY_VERSION_HEX < 0x03050000 + return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current); +#elif PY_VERSION_HEX < 0x03050200 + return (PyThreadState*) _PyThreadState_Current.value; +#else + return _PyThreadState_UncheckedGet(); +#endif +} + +// Forward declaration +inline void keep_alive_impl(handle nurse, handle patient); + +class type_caster_generic { +public: + PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info) + : typeinfo(get_type_info(type_info)) { } + + PYBIND11_NOINLINE bool load(handle src, bool convert) { + if (!src) + return false; + return load(src, convert, Py_TYPE(src.ptr())); + } + + bool load(handle src, bool convert, PyTypeObject *tobj) { + if (!src || !typeinfo) + return false; + if (src.is_none()) { + value = nullptr; + return true; + } + + if (typeinfo->simple_type) { /* Case 1: no multiple inheritance etc. involved */ + /* Check if we can safely perform a reinterpret-style cast */ + if (PyType_IsSubtype(tobj, typeinfo->type)) { + value = reinterpret_cast *>(src.ptr())->value; + return true; + } + } else { /* Case 2: multiple inheritance */ + /* Check if we can safely perform a reinterpret-style cast */ + if (tobj == typeinfo->type) { + value = reinterpret_cast *>(src.ptr())->value; + return true; + } + + /* If this is a python class, also check the parents recursively */ + auto const &type_dict = get_internals().registered_types_py; + bool new_style_class = PyType_Check(tobj); + if (type_dict.find(tobj) == type_dict.end() && new_style_class && tobj->tp_bases) { + auto parents = reinterpret_borrow(tobj->tp_bases); + for (handle parent : parents) { + bool result = load(src, convert, (PyTypeObject *) parent.ptr()); + if (result) + return true; + } + } + + /* Try implicit casts */ + for (auto &cast : typeinfo->implicit_casts) { + type_caster_generic sub_caster(*cast.first); + if (sub_caster.load(src, convert)) { + value = cast.second(sub_caster.value); + return true; + } + } + } + + /* Perform an implicit conversion */ + if (convert) { + for (auto &converter : typeinfo->implicit_conversions) { + temp = reinterpret_steal(converter(src.ptr(), typeinfo->type)); + if (load(temp, false)) + return true; + } + for (auto &converter : *typeinfo->direct_conversions) { + if (converter(src.ptr(), value)) + return true; + } + } + return false; + } + + PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent, + const std::type_info *type_info, + const std::type_info *type_info_backup, + void *(*copy_constructor)(const void *), + void *(*move_constructor)(const void *), + const void *existing_holder = nullptr) { + void *src = const_cast(_src); + if (src == nullptr) + return none().inc_ref(); + + auto &internals = get_internals(); + + auto it = internals.registered_types_cpp.find(std::type_index(*type_info)); + if (it == internals.registered_types_cpp.end()) { + type_info = type_info_backup; + it = internals.registered_types_cpp.find(std::type_index(*type_info)); + } + + if (it == internals.registered_types_cpp.end()) { + std::string tname = type_info->name(); + detail::clean_type_id(tname); + std::string msg = "Unregistered type : " + tname; + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return handle(); + } + + auto tinfo = (const detail::type_info *) it->second; + + auto it_instances = internals.registered_instances.equal_range(src); + for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) { + auto instance_type = detail::get_type_info(Py_TYPE(it_i->second)); + if (instance_type && instance_type == tinfo) + return handle((PyObject *) it_i->second).inc_ref(); + } + + auto inst = reinterpret_steal(PyType_GenericAlloc(tinfo->type, 0)); + + auto wrapper = (instance *) inst.ptr(); + + wrapper->value = nullptr; + wrapper->owned = false; + + switch (policy) { + case return_value_policy::automatic: + case return_value_policy::take_ownership: + wrapper->value = src; + wrapper->owned = true; + break; + + case return_value_policy::automatic_reference: + case return_value_policy::reference: + wrapper->value = src; + wrapper->owned = false; + break; + + case return_value_policy::copy: + if (copy_constructor) + wrapper->value = copy_constructor(src); + else + throw cast_error("return_value_policy = copy, but the " + "object is non-copyable!"); + wrapper->owned = true; + break; + + case return_value_policy::move: + if (move_constructor) + wrapper->value = move_constructor(src); + else if (copy_constructor) + wrapper->value = copy_constructor(src); + else + throw cast_error("return_value_policy = move, but the " + "object is neither movable nor copyable!"); + wrapper->owned = true; + break; + + case return_value_policy::reference_internal: + wrapper->value = src; + wrapper->owned = false; + detail::keep_alive_impl(inst, parent); + break; + + default: + throw cast_error("unhandled return_value_policy: should not happen!"); + } + + tinfo->init_holder(inst.ptr(), existing_holder); + + internals.registered_instances.emplace(wrapper->value, inst.ptr()); + + return inst.release(); + } + +protected: + const type_info *typeinfo = nullptr; + void *value = nullptr; + object temp; +}; + +/* Determine suitable casting operator */ +template +using cast_op_type = typename std::conditional::type>::value, + typename std::add_pointer>::type, + typename std::add_lvalue_reference>::type>::type; + +// std::is_copy_constructible isn't quite enough: it lets std::vector (and similar) through when +// T is non-copyable, but code containing such a copy constructor fails to actually compile. +template struct is_copy_constructible : std::is_copy_constructible {}; + +// Specialization for types that appear to be copy constructible but also look like stl containers +// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if +// so, copy constructability depends on whether the value_type is copy constructible. +template struct is_copy_constructible::value && + std::is_same::value + >> : std::is_copy_constructible {}; + +/// Generic type caster for objects stored on the heap +template class type_caster_base : public type_caster_generic { + using itype = intrinsic_t; +public: + static PYBIND11_DESCR name() { return type_descr(_()); } + + type_caster_base() : type_caster_base(typeid(type)) { } + explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { } + + static handle cast(const itype &src, return_value_policy policy, handle parent) { + if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) + policy = return_value_policy::copy; + return cast(&src, policy, parent); + } + + static handle cast(itype &&src, return_value_policy, handle parent) { + return cast(&src, return_value_policy::move, parent); + } + + static handle cast(const itype *src, return_value_policy policy, handle parent) { + return type_caster_generic::cast( + src, policy, parent, src ? &typeid(*src) : nullptr, &typeid(type), + make_copy_constructor(src), make_move_constructor(src)); + } + + template using cast_op_type = pybind11::detail::cast_op_type; + + operator itype*() { return (type *) value; } + operator itype&() { if (!value) throw reference_cast_error(); return *((itype *) value); } + +protected: + typedef void *(*Constructor)(const void *stream); +#if !defined(_MSC_VER) + /* Only enabled when the types are {copy,move}-constructible *and* when the type + does not have a private operator new implementaton. */ + template ::value>> static auto make_copy_constructor(const T *value) -> decltype(new T(*value), Constructor(nullptr)) { + return [](const void *arg) -> void * { return new T(*((const T *) arg)); }; } + template static auto make_move_constructor(const T *value) -> decltype(new T(std::move(*((T *) value))), Constructor(nullptr)) { + return [](const void *arg) -> void * { return (void *) new T(std::move(*((T *) arg))); }; } +#else + /* Visual Studio 2015's SFINAE implementation doesn't yet handle the above robustly in all situations. + Use a workaround that only tests for constructibility for now. */ + template ::value>> + static Constructor make_copy_constructor(const T *value) { + return [](const void *arg) -> void * { return new T(*((const T *)arg)); }; } + template ::value>> + static Constructor make_move_constructor(const T *value) { + return [](const void *arg) -> void * { return (void *) new T(std::move(*((T *)arg))); }; } +#endif + + static Constructor make_copy_constructor(...) { return nullptr; } + static Constructor make_move_constructor(...) { return nullptr; } +}; + +template class type_caster : public type_caster_base { }; +template using make_caster = type_caster>; + +// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T +template typename make_caster::template cast_op_type cast_op(make_caster &caster) { + return caster.operator typename make_caster::template cast_op_type(); +} +template typename make_caster::template cast_op_type cast_op(make_caster &&caster) { + return cast_op(caster); +} + +template class type_caster> : public type_caster_base { +public: + static handle cast(const std::reference_wrapper &src, return_value_policy policy, handle parent) { + return type_caster_base::cast(&src.get(), policy, parent); + } + template using cast_op_type = std::reference_wrapper; + operator std::reference_wrapper() { return std::ref(*((type *) this->value)); } +}; + +#define PYBIND11_TYPE_CASTER(type, py_name) \ + protected: \ + type value; \ + public: \ + static PYBIND11_DESCR name() { return type_descr(py_name); } \ + static handle cast(const type *src, return_value_policy policy, handle parent) { \ + return cast(*src, policy, parent); \ + } \ + operator type*() { return &value; } \ + operator type&() { return value; } \ + template using cast_op_type = pybind11::detail::cast_op_type<_T> + + +template +struct type_caster::value>> { + typedef typename std::conditional::type _py_type_0; + typedef typename std::conditional::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>::type _py_type_1; + typedef typename std::conditional::value, double, _py_type_1>::type py_type; +public: + + bool load(handle src, bool) { + py_type py_value; + + if (!src) { + return false; + } if (std::is_floating_point::value) { + py_value = (py_type) PyFloat_AsDouble(src.ptr()); + } else if (sizeof(T) <= sizeof(long)) { + if (PyFloat_Check(src.ptr())) + return false; + if (std::is_signed::value) + py_value = (py_type) PyLong_AsLong(src.ptr()); + else + py_value = (py_type) PyLong_AsUnsignedLong(src.ptr()); + } else { + if (PyFloat_Check(src.ptr())) + return false; + if (std::is_signed::value) + py_value = (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr()); + else + py_value = (py_type) PYBIND11_LONG_AS_UNSIGNED_LONGLONG(src.ptr()); + } + + if ((py_value == (py_type) -1 && PyErr_Occurred()) || + (std::is_integral::value && sizeof(py_type) != sizeof(T) && + (py_value < (py_type) std::numeric_limits::min() || + py_value > (py_type) std::numeric_limits::max()))) { +#if PY_VERSION_HEX < 0x03000000 + bool type_error = PyErr_ExceptionMatches(PyExc_SystemError); +#else + bool type_error = PyErr_ExceptionMatches(PyExc_TypeError); +#endif + PyErr_Clear(); + if (type_error && PyNumber_Check(src.ptr())) { + auto tmp = reinterpret_borrow(std::is_floating_point::value + ? PyNumber_Float(src.ptr()) + : PyNumber_Long(src.ptr())); + PyErr_Clear(); + return load(tmp, false); + } + return false; + } + + value = (T) py_value; + return true; + } + + static handle cast(T src, return_value_policy /* policy */, handle /* parent */) { + if (std::is_floating_point::value) { + return PyFloat_FromDouble((double) src); + } else if (sizeof(T) <= sizeof(long)) { + if (std::is_signed::value) + return PyLong_FromLong((long) src); + else + return PyLong_FromUnsignedLong((unsigned long) src); + } else { + if (std::is_signed::value) + return PyLong_FromLongLong((long long) src); + else + return PyLong_FromUnsignedLongLong((unsigned long long) src); + } + } + + PYBIND11_TYPE_CASTER(T, _::value>("int", "float")); +}; + +template struct void_caster { +public: + bool load(handle, bool) { return false; } + static handle cast(T, return_value_policy /* policy */, handle /* parent */) { + return none().inc_ref(); + } + PYBIND11_TYPE_CASTER(T, _("None")); +}; + +template <> class type_caster : public void_caster {}; + +template <> class type_caster : public type_caster { +public: + using type_caster::cast; + + bool load(handle h, bool) { + if (!h) { + return false; + } else if (h.is_none()) { + value = nullptr; + return true; + } + + /* Check if this is a capsule */ + if (isinstance(h)) { + value = reinterpret_borrow(h); + return true; + } + + /* Check if this is a C++ type */ + if (get_type_info((PyTypeObject *) h.get_type().ptr())) { + value = ((instance *) h.ptr())->value; + return true; + } + + /* Fail */ + return false; + } + + static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) { + if (ptr) + return capsule(ptr).release(); + else + return none().inc_ref(); + } + + template using cast_op_type = void*&; + operator void *&() { return value; } + static PYBIND11_DESCR name() { return type_descr(_("capsule")); } +private: + void *value = nullptr; +}; + +template <> class type_caster : public type_caster { }; + +template <> class type_caster { +public: + bool load(handle src, bool) { + if (!src) return false; + else if (src.ptr() == Py_True) { value = true; return true; } + else if (src.ptr() == Py_False) { value = false; return true; } + else return false; + } + static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) { + return handle(src ? Py_True : Py_False).inc_ref(); + } + PYBIND11_TYPE_CASTER(bool, _("bool")); +}; + +template <> class type_caster { +public: + bool load(handle src, bool) { + object temp; + handle load_src = src; + if (!src) { + return false; + } else if (PyUnicode_Check(load_src.ptr())) { + temp = reinterpret_steal(PyUnicode_AsUTF8String(load_src.ptr())); + if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError + load_src = temp; + } + char *buffer; + ssize_t length; + int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(load_src.ptr(), &buffer, &length); + if (err == -1) { PyErr_Clear(); return false; } // TypeError + value = std::string(buffer, (size_t) length); + success = true; + return true; + } + + static handle cast(const std::string &src, return_value_policy /* policy */, handle /* parent */) { + return PyUnicode_FromStringAndSize(src.c_str(), (ssize_t) src.length()); + } + + PYBIND11_TYPE_CASTER(std::string, _(PYBIND11_STRING_NAME)); +protected: + bool success = false; +}; + +template class type_caster> { +public: + static handle cast(std::unique_ptr &&src, return_value_policy policy, handle parent) { + handle result = type_caster_base::cast(src.get(), policy, parent); + if (result) + src.release(); + return result; + } + static PYBIND11_DESCR name() { return type_caster_base::name(); } +}; + +template <> class type_caster { +public: + bool load(handle src, bool) { + object temp; + handle load_src = src; + if (!src) { + return false; + } else if (!PyUnicode_Check(load_src.ptr())) { + temp = reinterpret_steal(PyUnicode_FromObject(load_src.ptr())); + if (!temp) { PyErr_Clear(); return false; } + load_src = temp; + } + wchar_t *buffer = nullptr; + ssize_t length = -1; +#if PY_MAJOR_VERSION >= 3 + buffer = PyUnicode_AsWideCharString(load_src.ptr(), &length); +#else + temp = reinterpret_steal( + sizeof(wchar_t) == sizeof(short) + ? PyUnicode_AsUTF16String(load_src.ptr()) + : PyUnicode_AsUTF32String(load_src.ptr())); + if (temp) { + int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), (char **) &buffer, &length); + if (err == -1) { buffer = nullptr; } // TypeError + length = length / (ssize_t) sizeof(wchar_t) - 1; ++buffer; // Skip BOM + } +#endif + if (!buffer) { PyErr_Clear(); return false; } + value = std::wstring(buffer, (size_t) length); + success = true; + return true; + } + + static handle cast(const std::wstring &src, return_value_policy /* policy */, handle /* parent */) { + return PyUnicode_FromWideChar(src.c_str(), (ssize_t) src.length()); + } + + PYBIND11_TYPE_CASTER(std::wstring, _(PYBIND11_STRING_NAME)); +protected: + bool success = false; +}; + +template <> class type_caster : public type_caster { +public: + bool load(handle src, bool convert) { + if (src.is_none()) return true; + return type_caster::load(src, convert); + } + + static handle cast(const char *src, return_value_policy /* policy */, handle /* parent */) { + if (src == nullptr) return none().inc_ref(); + return PyUnicode_FromString(src); + } + + static handle cast(char src, return_value_policy /* policy */, handle /* parent */) { + char str[2] = { src, '\0' }; + return PyUnicode_DecodeLatin1(str, 1, nullptr); + } + + operator char*() { return success ? (char *) value.c_str() : nullptr; } + operator char&() { return value[0]; } + + static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); } +}; + +template <> class type_caster : public type_caster { +public: + bool load(handle src, bool convert) { + if (src.is_none()) return true; + return type_caster::load(src, convert); + } + + static handle cast(const wchar_t *src, return_value_policy /* policy */, handle /* parent */) { + if (src == nullptr) return none().inc_ref(); + return PyUnicode_FromWideChar(src, (ssize_t) wcslen(src)); + } + + static handle cast(wchar_t src, return_value_policy /* policy */, handle /* parent */) { + wchar_t wstr[2] = { src, L'\0' }; + return PyUnicode_FromWideChar(wstr, 1); + } + + operator wchar_t*() { return success ? (wchar_t *) value.c_str() : nullptr; } + operator wchar_t&() { return value[0]; } + + static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); } +}; + +template class type_caster> { + typedef std::pair type; +public: + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + const auto seq = reinterpret_borrow(src); + if (seq.size() != 2) + return false; + return first.load(seq[0], convert) && second.load(seq[1], convert); + } + + static handle cast(const type &src, return_value_policy policy, handle parent) { + auto o1 = reinterpret_steal(make_caster::cast(src.first, policy, parent)); + auto o2 = reinterpret_steal(make_caster::cast(src.second, policy, parent)); + if (!o1 || !o2) + return handle(); + tuple result(2); + PyTuple_SET_ITEM(result.ptr(), 0, o1.release().ptr()); + PyTuple_SET_ITEM(result.ptr(), 1, o2.release().ptr()); + return result.release(); + } + + static PYBIND11_DESCR name() { + return type_descr( + _("Tuple[") + make_caster::name() + _(", ") + make_caster::name() + _("]") + ); + } + + template using cast_op_type = type; + + operator type() { + return type(cast_op(first), cast_op(second)); + } +protected: + make_caster first; + make_caster second; +}; + +template class type_caster> { + using type = std::tuple; + using indices = make_index_sequence; + static constexpr auto size = sizeof...(Tuple); + +public: + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + const auto seq = reinterpret_borrow(src); + if (seq.size() != size) + return false; + return load_impl(seq, convert, indices{}); + } + + static handle cast(const type &src, return_value_policy policy, handle parent) { + return cast_impl(src, policy, parent, indices{}); + } + + static PYBIND11_DESCR name() { + return type_descr(_("Tuple[") + detail::concat(make_caster::name()...) + _("]")); + } + + template using cast_op_type = type; + + operator type() { return implicit_cast(indices{}); } + +protected: + template + type implicit_cast(index_sequence) { return type(cast_op(std::get(value))...); } + + static constexpr bool load_impl(const sequence &, bool, index_sequence<>) { return true; } + + template + bool load_impl(const sequence &seq, bool convert, index_sequence) { + for (bool r : {std::get(value).load(seq[Is], convert)...}) + if (!r) + return false; + return true; + } + + static handle cast_impl(const type &, return_value_policy, handle, + index_sequence<>) { return tuple().release(); } + + /* Implementation: Convert a C++ tuple into a Python tuple */ + template + static handle cast_impl(const type &src, return_value_policy policy, handle parent, index_sequence) { + std::array entries {{ + reinterpret_steal(make_caster::cast(std::get(src), policy, parent))... + }}; + for (const auto &entry: entries) + if (!entry) + return handle(); + tuple result(size); + int counter = 0; + for (auto & entry: entries) + PyTuple_SET_ITEM(result.ptr(), counter++, entry.release().ptr()); + return result.release(); + } + +protected: + std::tuple...> value; +}; + +/// Type caster for holder types like std::shared_ptr, etc. +template class type_caster_holder : public type_caster_base { +public: + using base = type_caster_base; + using base::base; + using base::cast; + using base::typeinfo; + using base::value; + using base::temp; + + PYBIND11_NOINLINE bool load(handle src, bool convert) { + return load(src, convert, Py_TYPE(src.ptr())); + } + + bool load(handle src, bool convert, PyTypeObject *tobj) { + if (!src || !typeinfo) + return false; + if (src.is_none()) { + value = nullptr; + return true; + } + + if (typeinfo->simple_type) { /* Case 1: no multiple inheritance etc. involved */ + /* Check if we can safely perform a reinterpret-style cast */ + if (PyType_IsSubtype(tobj, typeinfo->type)) + return load_value_and_holder(src); + } else { /* Case 2: multiple inheritance */ + /* Check if we can safely perform a reinterpret-style cast */ + if (tobj == typeinfo->type) + return load_value_and_holder(src); + + /* If this is a python class, also check the parents recursively */ + auto const &type_dict = get_internals().registered_types_py; + bool new_style_class = PyType_Check(tobj); + if (type_dict.find(tobj) == type_dict.end() && new_style_class && tobj->tp_bases) { + auto parents = reinterpret_borrow(tobj->tp_bases); + for (handle parent : parents) { + bool result = load(src, convert, (PyTypeObject *) parent.ptr()); + if (result) + return true; + } + } + + if (try_implicit_casts(src, convert)) + return true; + } + + if (convert) { + for (auto &converter : typeinfo->implicit_conversions) { + temp = reinterpret_steal(converter(src.ptr(), typeinfo->type)); + if (load(temp, false)) + return true; + } + } + + return false; + } + + bool load_value_and_holder(handle src) { + auto inst = (instance *) src.ptr(); + value = (void *) inst->value; + if (inst->holder_constructed) { + holder = inst->holder; + return true; + } else { + throw cast_error("Unable to cast from non-held to held instance (T& to Holder) " +#if defined(NDEBUG) + "(compile in debug mode for type information)"); +#else + "of type '" + type_id() + "''"); +#endif + } + } + + template ::value, int> = 0> + bool try_implicit_casts(handle, bool) { return false; } + + template ::value, int> = 0> + bool try_implicit_casts(handle src, bool convert) { + for (auto &cast : typeinfo->implicit_casts) { + type_caster_holder sub_caster(*cast.first); + if (sub_caster.load(src, convert)) { + value = cast.second(sub_caster.value); + holder = holder_type(sub_caster.holder, (type *) value); + return true; + } + } + return false; + } + + explicit operator type*() { return this->value; } + explicit operator type&() { return *(this->value); } + explicit operator holder_type*() { return &holder; } + + // Workaround for Intel compiler bug + // see pybind11 issue 94 + #if defined(__ICC) || defined(__INTEL_COMPILER) + operator holder_type&() { return holder; } + #else + explicit operator holder_type&() { return holder; } + #endif + + static handle cast(const holder_type &src, return_value_policy, handle) { + return type_caster_generic::cast( + src.get(), return_value_policy::take_ownership, handle(), + src.get() ? &typeid(*src.get()) : nullptr, &typeid(type), + nullptr, nullptr, &src); + } + +protected: + holder_type holder; +}; + +/// Specialize for the common std::shared_ptr, so users don't need to +template +class type_caster> : public type_caster_holder> { }; + +/// Create a specialization for custom holder types (silently ignores std::shared_ptr) +#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type) \ + namespace pybind11 { namespace detail { \ + template \ + class type_caster::value>> \ + : public type_caster_holder { }; \ + }} + +// PYBIND11_DECLARE_HOLDER_TYPE holder types: +template struct is_holder_type : + std::is_base_of, detail::type_caster> {}; +// Specialization for always-supported unique_ptr holders: +template struct is_holder_type> : + std::true_type {}; + +template struct handle_type_name { static PYBIND11_DESCR name() { return _(); } }; +template <> struct handle_type_name { static PYBIND11_DESCR name() { return _(PYBIND11_BYTES_NAME); } }; +template <> struct handle_type_name { static PYBIND11_DESCR name() { return _("*args"); } }; +template <> struct handle_type_name { static PYBIND11_DESCR name() { return _("**kwargs"); } }; + +template +struct pyobject_caster { + template ::value, int> = 0> + bool load(handle src, bool /* convert */) { value = src; return static_cast(value); } + + template ::value, int> = 0> + bool load(handle src, bool /* convert */) { + if (!isinstance(src)) + return false; + value = reinterpret_borrow(src); + return true; + } + + static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) { + return src.inc_ref(); + } + PYBIND11_TYPE_CASTER(type, handle_type_name::name()); +}; + +template +class type_caster::value>> : public pyobject_caster { }; + +// Our conditions for enabling moving are quite restrictive: +// At compile time: +// - T needs to be a non-const, non-pointer, non-reference type +// - type_caster::operator T&() must exist +// - the type must be move constructible (obviously) +// At run-time: +// - if the type is non-copy-constructible, the object must be the sole owner of the type (i.e. it +// must have ref_count() == 1)h +// If any of the above are not satisfied, we fall back to copying. +template struct move_is_plain_type : std::false_type {}; +template struct move_is_plain_type::value && !std::is_pointer::value && !std::is_reference::value && !std::is_const::value + >> : std::true_type { }; +template struct move_always : std::false_type {}; +template struct move_always::value && + !std::is_copy_constructible::value && std::is_move_constructible::value && + std::is_same>().operator T&()), T&>::value + >> : std::true_type { }; +template struct move_if_unreferenced : std::false_type {}; +template struct move_if_unreferenced::value && + !move_always::value && std::is_move_constructible::value && + std::is_same>().operator T&()), T&>::value + >> : std::true_type { }; +template using move_never = std::integral_constant::value && !move_if_unreferenced::value>; + +// Detect whether returning a `type` from a cast on type's type_caster is going to result in a +// reference or pointer to a local variable of the type_caster. Basically, only +// non-reference/pointer `type`s and reference/pointers from a type_caster_generic are safe; +// everything else returns a reference/pointer to a local variable. +template using cast_is_temporary_value_reference = bool_constant< + (std::is_reference::value || std::is_pointer::value) && + !std::is_base_of>::value +>; + +// Basic python -> C++ casting; throws if casting fails +template type_caster &load_type(type_caster &conv, const handle &handle) { + if (!conv.load(handle, true)) { +#if defined(NDEBUG) + throw cast_error("Unable to cast Python instance to C++ type (compile in debug mode for details)"); +#else + throw cast_error("Unable to cast Python instance of type " + + (std::string) str(handle.get_type()) + " to C++ type '" + type_id() + "''"); +#endif + } + return conv; +} +// Wrapper around the above that also constructs and returns a type_caster +template make_caster load_type(const handle &handle) { + make_caster conv; + load_type(conv, handle); + return conv; +} + +NAMESPACE_END(detail) + +// pytype -> C++ type +template ::value, int> = 0> +T cast(const handle &handle) { + using namespace detail; + static_assert(!cast_is_temporary_value_reference::value, + "Unable to cast type to reference: value is local to type caster"); + return cast_op(load_type(handle)); +} + +// pytype -> pytype (calls converting constructor) +template ::value, int> = 0> +T cast(const handle &handle) { return T(reinterpret_borrow(handle)); } + +// C++ type -> py::object +template ::value, int> = 0> +object cast(const T &value, return_value_policy policy = return_value_policy::automatic_reference, + handle parent = handle()) { + if (policy == return_value_policy::automatic) + policy = std::is_pointer::value ? return_value_policy::take_ownership : return_value_policy::copy; + else if (policy == return_value_policy::automatic_reference) + policy = std::is_pointer::value ? return_value_policy::reference : return_value_policy::copy; + return reinterpret_steal(detail::make_caster::cast(value, policy, parent)); +} + +template T handle::cast() const { return pybind11::cast(*this); } +template <> inline void handle::cast() const { return; } + +template +detail::enable_if_t::value || detail::move_if_unreferenced::value, T> move(object &&obj) { + if (obj.ref_count() > 1) +#if defined(NDEBUG) + throw cast_error("Unable to cast Python instance to C++ rvalue: instance has multiple references" + " (compile in debug mode for details)"); +#else + throw cast_error("Unable to move from Python " + (std::string) str(obj.get_type()) + + " instance to C++ " + type_id() + " instance: instance has multiple references"); +#endif + + // Move into a temporary and return that, because the reference may be a local value of `conv` + T ret = std::move(detail::load_type(obj).operator T&()); + return ret; +} + +// Calling cast() on an rvalue calls pybind::cast with the object rvalue, which does: +// - If we have to move (because T has no copy constructor), do it. This will fail if the moved +// object has multiple references, but trying to copy will fail to compile. +// - If both movable and copyable, check ref count: if 1, move; otherwise copy +// - Otherwise (not movable), copy. +template detail::enable_if_t::value, T> cast(object &&object) { + return move(std::move(object)); +} +template detail::enable_if_t::value, T> cast(object &&object) { + if (object.ref_count() > 1) + return cast(object); + else + return move(std::move(object)); +} +template detail::enable_if_t::value, T> cast(object &&object) { + return cast(object); +} + +template T object::cast() const & { return pybind11::cast(*this); } +template T object::cast() && { return pybind11::cast(std::move(*this)); } +template <> inline void object::cast() const & { return; } +template <> inline void object::cast() && { return; } + +NAMESPACE_BEGIN(detail) + +struct overload_unused {}; // Placeholder type for the unneeded (and dead code) static variable in the OVERLOAD_INT macro +template using overload_caster_t = conditional_t< + cast_is_temporary_value_reference::value, make_caster, overload_unused>; + +// Trampoline use: for reference/pointer types to value-converted values, we do a value cast, then +// store the result in the given variable. For other types, this is a no-op. +template enable_if_t::value, T> cast_ref(object &&o, make_caster &caster) { + return cast_op(load_type(caster, o)); +} +template enable_if_t::value, T> cast_ref(object &&, overload_unused &) { + pybind11_fail("Internal error: cast_ref fallback invoked"); } + +// Trampoline use: Having a pybind11::cast with an invalid reference type is going to static_assert, even +// though if it's in dead code, so we provide a "trampoline" to pybind11::cast that only does anything in +// cases where pybind11::cast is valid. +template enable_if_t::value, T> cast_safe(object &&o) { + return pybind11::cast(std::move(o)); } +template enable_if_t::value, T> cast_safe(object &&) { + pybind11_fail("Internal error: cast_safe fallback invoked"); } +template <> inline void cast_safe(object &&) {} + +NAMESPACE_END(detail) + +template tuple make_tuple(Args&&... args_) { + const size_t size = sizeof...(Args); + std::array args { + { reinterpret_steal(detail::make_caster::cast( + std::forward(args_), policy, nullptr))... } + }; + for (auto &arg_value : args) { + if (!arg_value) { +#if defined(NDEBUG) + throw cast_error("make_tuple(): unable to convert arguments to Python object (compile in debug mode for details)"); +#else + throw cast_error("make_tuple(): unable to convert arguments of types '" + + (std::string) type_id>() + "' to Python object"); +#endif + } + } + tuple result(size); + int counter = 0; + for (auto &arg_value : args) + PyTuple_SET_ITEM(result.ptr(), counter++, arg_value.release().ptr()); + return result; +} + +/// Annotation for keyword arguments +struct arg { + constexpr explicit arg(const char *name) : name(name) { } + template arg_v operator=(T &&value) const; + + const char *name; +}; + +/// Annotation for keyword arguments with values +struct arg_v : arg { + template + arg_v(const char *name, T &&x, const char *descr = nullptr) + : arg(name), + value(reinterpret_steal( + detail::make_caster::cast(x, return_value_policy::automatic, {}) + )), + descr(descr) +#if !defined(NDEBUG) + , type(type_id()) +#endif + { } + + object value; + const char *descr; +#if !defined(NDEBUG) + std::string type; +#endif +}; + +template +arg_v arg::operator=(T &&value) const { return {name, std::forward(value)}; } + +/// Alias for backward compatibility -- to be removed in version 2.0 +template using arg_t = arg_v; + +inline namespace literals { +/// String literal version of arg +constexpr arg operator"" _a(const char *name, size_t) { return arg(name); } +} + +NAMESPACE_BEGIN(detail) + +/// Helper class which loads arguments for C++ functions called from Python +template +class argument_loader { + using itypes = type_list...>; + using indices = make_index_sequence; + +public: + static constexpr auto has_kwargs = std::is_same>::value; + static constexpr auto has_args = has_kwargs || std::is_same>::value; + + static PYBIND11_DESCR arg_names() { return detail::concat(make_caster::name()...); } + + bool load_args(handle args, handle kwargs, bool convert) { + return load_impl(args, kwargs, convert, itypes{}); + } + + template + enable_if_t::value, Return> call(Func &&f) { + return call_impl(std::forward(f), indices{}); + } + + template + enable_if_t::value, void_type> call(Func &&f) { + call_impl(std::forward(f), indices{}); + return void_type(); + } + +private: + bool load_impl(handle args_, handle, bool convert, type_list) { + std::get<0>(value).load(args_, convert); + return true; + } + + bool load_impl(handle args_, handle kwargs_, bool convert, type_list) { + std::get<0>(value).load(args_, convert); + std::get<1>(value).load(kwargs_, convert); + return true; + } + + bool load_impl(handle args, handle, bool convert, ... /* anything else */) { + return load_impl_sequence(args, convert, indices{}); + } + + static constexpr bool load_impl_sequence(handle, bool, index_sequence<>) { return true; } + + template + bool load_impl_sequence(handle src, bool convert, index_sequence) { + for (bool r : {std::get(value).load(PyTuple_GET_ITEM(src.ptr(), Is), convert)...}) + if (!r) + return false; + return true; + } + + template + Return call_impl(Func &&f, index_sequence) { + return std::forward(f)(cast_op(std::get(value))...); + } + +private: + std::tuple...> value; +}; + +NAMESPACE_BEGIN(constexpr_impl) +/// Implementation details for constexpr functions +constexpr int first(int i) { return i; } +template +constexpr int first(int i, T v, Ts... vs) { return v ? i : first(i + 1, vs...); } + +constexpr int last(int /*i*/, int result) { return result; } +template +constexpr int last(int i, int result, T v, Ts... vs) { return last(i + 1, v ? i : result, vs...); } +NAMESPACE_END(constexpr_impl) + +/// Return the index of the first type in Ts which satisfies Predicate +template class Predicate, typename... Ts> +constexpr int constexpr_first() { return constexpr_impl::first(0, Predicate::value...); } + +/// Return the index of the last type in Ts which satisfies Predicate +template class Predicate, typename... Ts> +constexpr int constexpr_last() { return constexpr_impl::last(0, -1, Predicate::value...); } + +/// Helper class which collects only positional arguments for a Python function call. +/// A fancier version below can collect any argument, but this one is optimal for simple calls. +template +class simple_collector { +public: + template + explicit simple_collector(Ts &&...values) + : m_args(pybind11::make_tuple(std::forward(values)...)) { } + + const tuple &args() const & { return m_args; } + dict kwargs() const { return {}; } + + tuple args() && { return std::move(m_args); } + + /// Call a Python function and pass the collected arguments + object call(PyObject *ptr) const { + PyObject *result = PyObject_CallObject(ptr, m_args.ptr()); + if (!result) + throw error_already_set(); + return reinterpret_steal(result); + } + +private: + tuple m_args; +}; + +/// Helper class which collects positional, keyword, * and ** arguments for a Python function call +template +class unpacking_collector { +public: + template + explicit unpacking_collector(Ts &&...values) { + // Tuples aren't (easily) resizable so a list is needed for collection, + // but the actual function call strictly requires a tuple. + auto args_list = list(); + int _[] = { 0, (process(args_list, std::forward(values)), 0)... }; + ignore_unused(_); + + m_args = std::move(args_list); + } + + const tuple &args() const & { return m_args; } + const dict &kwargs() const & { return m_kwargs; } + + tuple args() && { return std::move(m_args); } + dict kwargs() && { return std::move(m_kwargs); } + + /// Call a Python function and pass the collected arguments + object call(PyObject *ptr) const { + PyObject *result = PyObject_Call(ptr, m_args.ptr(), m_kwargs.ptr()); + if (!result) + throw error_already_set(); + return reinterpret_steal(result); + } + +private: + template + void process(list &args_list, T &&x) { + auto o = reinterpret_steal(detail::make_caster::cast(std::forward(x), policy, {})); + if (!o) { +#if defined(NDEBUG) + argument_cast_error(); +#else + argument_cast_error(std::to_string(args_list.size()), type_id()); +#endif + } + args_list.append(o); + } + + void process(list &args_list, detail::args_proxy ap) { + for (const auto &a : ap) + args_list.append(a); + } + + void process(list &/*args_list*/, arg_v a) { + if (m_kwargs.contains(a.name)) { +#if defined(NDEBUG) + multiple_values_error(); +#else + multiple_values_error(a.name); +#endif + } + if (!a.value) { +#if defined(NDEBUG) + argument_cast_error(); +#else + argument_cast_error(a.name, a.type); +#endif + } + m_kwargs[a.name] = a.value; + } + + void process(list &/*args_list*/, detail::kwargs_proxy kp) { + if (!kp) + return; + for (const auto &k : reinterpret_borrow(kp)) { + if (m_kwargs.contains(k.first)) { +#if defined(NDEBUG) + multiple_values_error(); +#else + multiple_values_error(str(k.first)); +#endif + } + m_kwargs[k.first] = k.second; + } + } + + [[noreturn]] static void multiple_values_error() { + throw type_error("Got multiple values for keyword argument " + "(compile in debug mode for details)"); + } + + [[noreturn]] static void multiple_values_error(std::string name) { + throw type_error("Got multiple values for keyword argument '" + name + "'"); + } + + [[noreturn]] static void argument_cast_error() { + throw cast_error("Unable to convert call argument to Python object " + "(compile in debug mode for details)"); + } + + [[noreturn]] static void argument_cast_error(std::string name, std::string type) { + throw cast_error("Unable to convert call argument '" + name + + "' of type '" + type + "' to Python object"); + } + +private: + tuple m_args; + dict m_kwargs; +}; + +/// Collect only positional arguments for a Python function call +template ::value>> +simple_collector collect_arguments(Args &&...args) { + return simple_collector(std::forward(args)...); +} + +/// Collect all arguments, including keywords and unpacking (only instantiated when needed) +template ::value>> +unpacking_collector collect_arguments(Args &&...args) { + // Following argument order rules for generalized unpacking according to PEP 448 + static_assert( + constexpr_last() < constexpr_first() + && constexpr_last() < constexpr_first(), + "Invalid function call: positional args must precede keywords and ** unpacking; " + "* unpacking must precede ** unpacking" + ); + return unpacking_collector(std::forward(args)...); +} + +template +template +object object_api::operator()(Args &&...args) const { + return detail::collect_arguments(std::forward(args)...).call(derived().ptr()); +} + +template +template +object object_api::call(Args &&...args) const { + return operator()(std::forward(args)...); +} + +NAMESPACE_END(detail) + +#define PYBIND11_MAKE_OPAQUE(Type) \ + namespace pybind11 { namespace detail { \ + template<> class type_caster : public type_caster_base { }; \ + }} + +NAMESPACE_END(pybind11) diff --git a/resources/pybind11/include/pybind11/chrono.h b/resources/pybind11/include/pybind11/chrono.h new file mode 100755 index 0000000..2b37f56 --- /dev/null +++ b/resources/pybind11/include/pybind11/chrono.h @@ -0,0 +1,160 @@ +/* + pybind11/chrono.h: Transparent conversion between std::chrono and python's datetime + + Copyright (c) 2016 Trent Houliston and + Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include +#include +#include +#include + +// Backport the PyDateTime_DELTA functions from Python3.3 if required +#ifndef PyDateTime_DELTA_GET_DAYS +#define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days) +#endif +#ifndef PyDateTime_DELTA_GET_SECONDS +#define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta*)o)->seconds) +#endif +#ifndef PyDateTime_DELTA_GET_MICROSECONDS +#define PyDateTime_DELTA_GET_MICROSECONDS(o) (((PyDateTime_Delta*)o)->microseconds) +#endif + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + +template class duration_caster { +public: + typedef typename type::rep rep; + typedef typename type::period period; + + typedef std::chrono::duration> days; + + bool load(handle src, bool) { + using namespace std::chrono; + + // Lazy initialise the PyDateTime import + if (!PyDateTimeAPI) { PyDateTime_IMPORT; } + + if (!src) return false; + // If invoked with datetime.delta object + if (PyDelta_Check(src.ptr())) { + value = type(duration_cast>( + days(PyDateTime_DELTA_GET_DAYS(src.ptr())) + + seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr())) + + microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr())))); + return true; + } + // If invoked with a float we assume it is seconds and convert + else if (PyFloat_Check(src.ptr())) { + value = type(duration_cast>(duration(PyFloat_AsDouble(src.ptr())))); + return true; + } + else return false; + } + + // If this is a duration just return it back + static const std::chrono::duration& get_duration(const std::chrono::duration &src) { + return src; + } + + // If this is a time_point get the time_since_epoch + template static std::chrono::duration get_duration(const std::chrono::time_point> &src) { + return src.time_since_epoch(); + } + + static handle cast(const type &src, return_value_policy /* policy */, handle /* parent */) { + using namespace std::chrono; + + // Use overloaded function to get our duration from our source + // Works out if it is a duration or time_point and get the duration + auto d = get_duration(src); + + // Lazy initialise the PyDateTime import + if (!PyDateTimeAPI) { PyDateTime_IMPORT; } + + // Declare these special duration types so the conversions happen with the correct primitive types (int) + using dd_t = duration>; + using ss_t = duration>; + using us_t = duration; + + return PyDelta_FromDSU(duration_cast(d).count(), + duration_cast(d % days(1)).count(), + duration_cast(d % seconds(1)).count()); + } + + PYBIND11_TYPE_CASTER(type, _("datetime.timedelta")); +}; + +// This is for casting times on the system clock into datetime.datetime instances +template class type_caster> { +public: + typedef std::chrono::time_point type; + bool load(handle src, bool) { + using namespace std::chrono; + + // Lazy initialise the PyDateTime import + if (!PyDateTimeAPI) { PyDateTime_IMPORT; } + + if (!src) return false; + if (PyDateTime_Check(src.ptr())) { + std::tm cal; + cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr()); + cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr()); + cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr()); + cal.tm_mday = PyDateTime_GET_DAY(src.ptr()); + cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1; + cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900; + cal.tm_isdst = -1; + + value = system_clock::from_time_t(std::mktime(&cal)) + microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr())); + return true; + } + else return false; + } + + static handle cast(const std::chrono::time_point &src, return_value_policy /* policy */, handle /* parent */) { + using namespace std::chrono; + + // Lazy initialise the PyDateTime import + if (!PyDateTimeAPI) { PyDateTime_IMPORT; } + + std::time_t tt = system_clock::to_time_t(src); + // this function uses static memory so it's best to copy it out asap just in case + // otherwise other code that is using localtime may break this (not just python code) + std::tm localtime = *std::localtime(&tt); + + // Declare these special duration types so the conversions happen with the correct primitive types (int) + using us_t = duration; + + return PyDateTime_FromDateAndTime(localtime.tm_year + 1900, + localtime.tm_mon + 1, + localtime.tm_mday, + localtime.tm_hour, + localtime.tm_min, + localtime.tm_sec, + (duration_cast(src.time_since_epoch() % seconds(1))).count()); + } + PYBIND11_TYPE_CASTER(type, _("datetime.datetime")); +}; + +// Other clocks that are not the system clock are not measured as datetime.datetime objects +// since they are not measured on calendar time. So instead we just make them timedeltas +// Or if they have passed us a time as a float we convert that +template class type_caster> +: public duration_caster> { +}; + +template class type_caster> +: public duration_caster> { +}; + +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/resources/pybind11/include/pybind11/common.h b/resources/pybind11/include/pybind11/common.h new file mode 100755 index 0000000..72e8e33 --- /dev/null +++ b/resources/pybind11/include/pybind11/common.h @@ -0,0 +1,560 @@ +/* + pybind11/common.h -- Basic macros + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#if !defined(NAMESPACE_BEGIN) +# define NAMESPACE_BEGIN(name) namespace name { +#endif +#if !defined(NAMESPACE_END) +# define NAMESPACE_END(name) } +#endif + +// Neither MSVC nor Intel support enough of C++14 yet (in particular, as of MSVC 2015 and ICC 17 +// beta, neither support extended constexpr, which we rely on in descr.h), so don't enable pybind +// CPP14 features for them. +#if !defined(_MSC_VER) && !defined(__INTEL_COMPILER) +# if __cplusplus >= 201402L +# define PYBIND11_CPP14 +# if __cplusplus > 201402L /* Temporary: should be updated to >= the final C++17 value once known */ +# define PYBIND11_CPP17 +# endif +# endif +#endif + +#if !defined(PYBIND11_EXPORT) +# if defined(WIN32) || defined(_WIN32) +# define PYBIND11_EXPORT __declspec(dllexport) +# else +# define PYBIND11_EXPORT __attribute__ ((visibility("default"))) +# endif +#endif + +#if defined(_MSC_VER) +# define PYBIND11_NOINLINE __declspec(noinline) +#else +# define PYBIND11_NOINLINE __attribute__ ((noinline)) +#endif + +#if defined(PYBIND11_CPP14) +# define PYBIND11_DEPRECATED(reason) [[deprecated(reason)]] +#elif defined(__clang__) +# define PYBIND11_DEPRECATED(reason) __attribute__((deprecated(reason))) +#elif defined(__GNUG__) +# define PYBIND11_DEPRECATED(reason) __attribute__((deprecated)) +#elif defined(_MSC_VER) +# define PYBIND11_DEPRECATED(reason) __declspec(deprecated) +#endif + +#define PYBIND11_VERSION_MAJOR 1 +#define PYBIND11_VERSION_MINOR 9 +#define PYBIND11_VERSION_PATCH dev0 + +/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode +#if defined(_MSC_VER) +# define HAVE_ROUND +# pragma warning(push) +# pragma warning(disable: 4510 4610 4512 4005) +# if _DEBUG +# define PYBIND11_DEBUG_MARKER +# undef _DEBUG +# endif +#endif + +#include +#include +#include + +#if defined(_WIN32) && (defined(min) || defined(max)) +# error Macro clash with min and max -- define NOMINMAX when compiling your program on Windows +#endif + +#if defined(isalnum) +# undef isalnum +# undef isalpha +# undef islower +# undef isspace +# undef isupper +# undef tolower +# undef toupper +#endif + +#if defined(_MSC_VER) +# if defined(PYBIND11_DEBUG_MARKER) +# define _DEBUG +# undef PYBIND11_DEBUG_MARKER +# endif +# pragma warning(pop) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions +#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr) +#define PYBIND11_BYTES_CHECK PyBytes_Check +#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString +#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize +#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize +#define PYBIND11_BYTES_AS_STRING PyBytes_AsString +#define PYBIND11_LONG_CHECK(o) PyLong_Check(o) +#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o) +#define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) PyLong_AsUnsignedLongLong(o) +#define PYBIND11_BYTES_NAME "bytes" +#define PYBIND11_STRING_NAME "str" +#define PYBIND11_SLICE_OBJECT PyObject +#define PYBIND11_FROM_STRING PyUnicode_FromString +#define PYBIND11_STR_TYPE ::pybind11::str +#define PYBIND11_OB_TYPE(ht_type) (ht_type).ob_base.ob_base.ob_type +#define PYBIND11_PLUGIN_IMPL(name) \ + extern "C" PYBIND11_EXPORT PyObject *PyInit_##name() +#else +#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_) +#define PYBIND11_BYTES_CHECK PyString_Check +#define PYBIND11_BYTES_FROM_STRING PyString_FromString +#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize +#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize +#define PYBIND11_BYTES_AS_STRING PyString_AsString +#define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o)) +#define PYBIND11_LONG_AS_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o)) +#define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) (PyInt_Check(o) ? (unsigned long long) PyLong_AsUnsignedLong(o) : PyLong_AsUnsignedLongLong(o)) +#define PYBIND11_BYTES_NAME "str" +#define PYBIND11_STRING_NAME "unicode" +#define PYBIND11_SLICE_OBJECT PySliceObject +#define PYBIND11_FROM_STRING PyString_FromString +#define PYBIND11_STR_TYPE ::pybind11::bytes +#define PYBIND11_OB_TYPE(ht_type) (ht_type).ob_type +#define PYBIND11_PLUGIN_IMPL(name) \ + extern "C" PYBIND11_EXPORT PyObject *init##name() +#endif + +#if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200 +extern "C" { + struct _Py_atomic_address { void *value; }; + PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current; +} +#endif + +#define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code +#define PYBIND11_STRINGIFY(x) #x +#define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x) +#define PYBIND11_INTERNALS_ID "__pybind11_" \ + PYBIND11_TOSTRING(PYBIND11_VERSION_MAJOR) "_" PYBIND11_TOSTRING(PYBIND11_VERSION_MINOR) "__" + +#define PYBIND11_PLUGIN(name) \ + static PyObject *pybind11_init(); \ + PYBIND11_PLUGIN_IMPL(name) { \ + int major, minor; \ + if (sscanf(Py_GetVersion(), "%i.%i", &major, &minor) != 2) { \ + PyErr_SetString(PyExc_ImportError, "Can't parse Python version."); \ + return nullptr; \ + } else if (major != PY_MAJOR_VERSION || minor != PY_MINOR_VERSION) { \ + PyErr_Format(PyExc_ImportError, \ + "Python version mismatch: module was compiled for " \ + "version %i.%i, while the interpreter is running " \ + "version %i.%i.", PY_MAJOR_VERSION, PY_MINOR_VERSION, \ + major, minor); \ + return nullptr; \ + } \ + try { \ + return pybind11_init(); \ + } catch (const std::exception &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } \ + } \ + PyObject *pybind11_init() + +NAMESPACE_BEGIN(pybind11) + +using ssize_t = Py_ssize_t; +using size_t = std::size_t; + +/// Approach used to cast a previously unknown C++ instance into a Python object +enum class return_value_policy : uint8_t { + /** This is the default return value policy, which falls back to the policy + return_value_policy::take_ownership when the return value is a pointer. + Otherwise, it uses return_value::move or return_value::copy for rvalue + and lvalue references, respectively. See below for a description of what + all of these different policies do. */ + automatic = 0, + + /** As above, but use policy return_value_policy::reference when the return + value is a pointer. This is the default conversion policy for function + arguments when calling Python functions manually from C++ code (i.e. via + handle::operator()). You probably won't need to use this. */ + automatic_reference, + + /** Reference an existing object (i.e. do not create a new copy) and take + ownership. Python will call the destructor and delete operator when the + object’s reference count reaches zero. Undefined behavior ensues when + the C++ side does the same.. */ + take_ownership, + + /** Create a new copy of the returned object, which will be owned by + Python. This policy is comparably safe because the lifetimes of the two + instances are decoupled. */ + copy, + + /** Use std::move to move the return value contents into a new instance + that will be owned by Python. This policy is comparably safe because the + lifetimes of the two instances (move source and destination) are + decoupled. */ + move, + + /** Reference an existing object, but do not take ownership. The C++ side + is responsible for managing the object’s lifetime and deallocating it + when it is no longer used. Warning: undefined behavior will ensue when + the C++ side deletes an object that is still referenced and used by + Python. */ + reference, + + /** This policy only applies to methods and properties. It references the + object without taking ownership similar to the above + return_value_policy::reference policy. In contrast to that policy, the + function or property’s implicit this argument (called the parent) is + considered to be the the owner of the return value (the child). + pybind11 then couples the lifetime of the parent to the child via a + reference relationship that ensures that the parent cannot be garbage + collected while Python is still using the child. More advanced + variations of this scheme are also possible using combinations of + return_value_policy::reference and the keep_alive call policy */ + reference_internal +}; + +/// Information record describing a Python buffer object +struct buffer_info { + void *ptr = nullptr; // Pointer to the underlying storage + size_t itemsize = 0; // Size of individual items in bytes + size_t size = 0; // Total number of entries + std::string format; // For homogeneous buffers, this should be set to format_descriptor::format() + size_t ndim = 0; // Number of dimensions + std::vector shape; // Shape of the tensor (1 entry per dimension) + std::vector strides; // Number of entries between adjacent entries (for each per dimension) + + buffer_info() { } + + buffer_info(void *ptr, size_t itemsize, const std::string &format, size_t ndim, + const std::vector &shape, const std::vector &strides) + : ptr(ptr), itemsize(itemsize), size(1), format(format), + ndim(ndim), shape(shape), strides(strides) { + for (size_t i = 0; i < ndim; ++i) + size *= shape[i]; + } + + buffer_info(void *ptr, size_t itemsize, const std::string &format, size_t size) + : buffer_info(ptr, itemsize, format, 1, std::vector { size }, + std::vector { itemsize }) { } + + explicit buffer_info(Py_buffer *view, bool ownview = true) + : ptr(view->buf), itemsize((size_t) view->itemsize), size(1), format(view->format), + ndim((size_t) view->ndim), shape((size_t) view->ndim), strides((size_t) view->ndim), view(view), ownview(ownview) { + for (size_t i = 0; i < (size_t) view->ndim; ++i) { + shape[i] = (size_t) view->shape[i]; + strides[i] = (size_t) view->strides[i]; + size *= shape[i]; + } + } + + buffer_info(const buffer_info &) = delete; + buffer_info& operator=(const buffer_info &) = delete; + + buffer_info(buffer_info &&other) { + (*this) = std::move(other); + } + + buffer_info& operator=(buffer_info &&rhs) { + ptr = rhs.ptr; + itemsize = rhs.itemsize; + size = rhs.size; + format = std::move(rhs.format); + ndim = rhs.ndim; + shape = std::move(rhs.shape); + strides = std::move(rhs.strides); + std::swap(view, rhs.view); + std::swap(ownview, rhs.ownview); + return *this; + } + + ~buffer_info() { + if (view && ownview) { PyBuffer_Release(view); delete view; } + } + +private: + Py_buffer *view = nullptr; + bool ownview = false; +}; + +NAMESPACE_BEGIN(detail) + +inline static constexpr int log2(size_t n, int k = 0) { return (n <= 1) ? k : log2(n >> 1, k + 1); } + +inline std::string error_string(); + +/// Core part of the 'instance' type which POD (needed to be able to use 'offsetof') +template struct instance_essentials { + PyObject_HEAD + type *value; + PyObject *weakrefs; + bool owned : 1; + bool holder_constructed : 1; +}; + +/// PyObject wrapper around generic types, includes a special holder type that is responsible for lifetime management +template > struct instance : instance_essentials { + holder_type holder; +}; + +struct overload_hash { + inline size_t operator()(const std::pair& v) const { + size_t value = std::hash()(v.first); + value ^= std::hash()(v.second) + 0x9e3779b9 + (value<<6) + (value>>2); + return value; + } +}; + +/// Internal data struture used to track registered instances and types +struct internals { + std::unordered_map registered_types_cpp; // std::type_index -> type_info + std::unordered_map registered_types_py; // PyTypeObject* -> type_info + std::unordered_multimap registered_instances; // void * -> PyObject* + std::unordered_set, overload_hash> inactive_overload_cache; + std::unordered_map> direct_conversions; + std::forward_list registered_exception_translators; + std::unordered_map shared_data; // Custom data to be shared across extensions +#if defined(WITH_THREAD) + decltype(PyThread_create_key()) tstate = 0; // Usually an int but a long on Cygwin64 with Python 3.x + PyInterpreterState *istate = nullptr; +#endif +}; + +/// Return a reference to the current 'internals' information +inline internals &get_internals(); + +/// Index sequence for convenient template metaprogramming involving tuples +#ifdef PYBIND11_CPP14 +using std::index_sequence; +using std::make_index_sequence; +#else +template struct index_sequence { }; +template struct make_index_sequence_impl : make_index_sequence_impl { }; +template struct make_index_sequence_impl <0, S...> { typedef index_sequence type; }; +template using make_index_sequence = typename make_index_sequence_impl::type; +#endif + +/// Strip the class from a method type +template struct remove_class { }; +template struct remove_class { typedef R type(A...); }; +template struct remove_class { typedef R type(A...); }; + +/// Helper template to strip away type modifiers +template struct intrinsic_type { typedef T type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template using intrinsic_t = typename intrinsic_type::type; + +/// Helper type to replace 'void' in some expressions +struct void_type { }; + +/// Helper template which holds a list of types +template struct type_list { }; + +/// from __cpp_future__ import (convenient aliases from C++14/17) +template using bool_constant = std::integral_constant; +template using negation = bool_constant; +template using enable_if_t = typename std::enable_if::type; +template using conditional_t = typename std::conditional::type; + +/// Compile-time integer sum +constexpr size_t constexpr_sum() { return 0; } +template +constexpr size_t constexpr_sum(T n, Ts... ns) { return size_t{n} + constexpr_sum(ns...); } + +// Counts the number of types in the template parameter pack matching the predicate +#if !defined(_MSC_VER) +template class Predicate, typename... Ts> +using count_t = std::integral_constant::value...)>; +#else +// MSVC workaround (2015 Update 3 has issues with some member type aliases and constexpr) +template class Predicate, typename... Ts> struct count_t; +template class Predicate> struct count_t : std::integral_constant {}; +template class Predicate, class T, class... Ts> +struct count_t : std::integral_constant::value + count_t::value> {}; +#endif + +/// Return true if all/any Ts satify Predicate +template class Predicate, typename... Ts> +using all_of_t = bool_constant<(count_t::value == sizeof...(Ts))>; +template class Predicate, typename... Ts> +using any_of_t = bool_constant<(count_t::value > 0)>; + +// Extracts the first type from the template parameter pack matching the predicate, or Default if none match. +template class Predicate, class Default, class... Ts> struct first_of; +template class Predicate, class Default> struct first_of { + using type = Default; +}; +template class Predicate, class Default, class T, class... Ts> +struct first_of { + using type = typename std::conditional< + Predicate::value, + T, + typename first_of::type + >::type; +}; +template class Predicate, class Default, class... T> using first_of_t = typename first_of::type; + +/// Defer the evaluation of type T until types Us are instantiated +template struct deferred_type { using type = T; }; +template using deferred_t = typename deferred_type::type; + +template class Base> +struct is_template_base_of_impl { + template static std::true_type check(Base *); + static std::false_type check(...); +}; + +/// Check if a template is the base of a type. For example: +/// `is_template_base_of` is true if `struct T : Base {}` where U can be anything +template class Base, typename T> +#if !defined(_MSC_VER) +using is_template_base_of = decltype(is_template_base_of_impl::check((T*)nullptr)); +#else // MSVC2015 has trouble with decltype in template aliases +struct is_template_base_of : decltype(is_template_base_of_impl::check((T*)nullptr)) { }; +#endif + +/// Check if T is std::shared_ptr where U can be anything +template struct is_shared_ptr : std::false_type { }; +template struct is_shared_ptr> : std::true_type { }; + +/// Ignore that a variable is unused in compiler warnings +inline void ignore_unused(const int *) { } + +NAMESPACE_END(detail) + +/// Returns a named pointer that is shared among all extension modules (using the same +/// pybind11 version) running in the current interpreter. Names starting with underscores +/// are reserved for internal usage. Returns `nullptr` if no matching entry was found. +inline PYBIND11_NOINLINE void* get_shared_data(const std::string& name) { + auto& internals = detail::get_internals(); + auto it = internals.shared_data.find(name); + return it != internals.shared_data.end() ? it->second : nullptr; +} + +/// Set the shared data that can be later recovered by `get_shared_data()`. +inline PYBIND11_NOINLINE void *set_shared_data(const std::string& name, void *data) { + detail::get_internals().shared_data[name] = data; + return data; +} + +/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if +/// such entry exists. Otherwise, a new object of default-constructible type `T` is +/// added to the shared data under the given name and a reference to it is returned. +template T& get_or_create_shared_data(const std::string& name) { + auto& internals = detail::get_internals(); + auto it = internals.shared_data.find(name); + T* ptr = (T*) (it != internals.shared_data.end() ? it->second : nullptr); + if (!ptr) { + ptr = new T(); + internals.shared_data[name] = ptr; + } + return *ptr; +} + +/// Fetch and hold an error which was already set in Python +class error_already_set : public std::runtime_error { +public: + error_already_set() : std::runtime_error(detail::error_string()) { + PyErr_Fetch(&type, &value, &trace); + } + + error_already_set(const error_already_set &) = delete; + + error_already_set(error_already_set &&e) + : std::runtime_error(e.what()), type(e.type), value(e.value), + trace(e.trace) { e.type = e.value = e.trace = nullptr; } + + inline ~error_already_set(); // implementation in pybind11.h + + error_already_set& operator=(const error_already_set &) = delete; + + /// Give the error back to Python + void restore() { PyErr_Restore(type, value, trace); type = value = trace = nullptr; } + +private: + PyObject *type, *value, *trace; +}; + +/// C++ bindings of builtin Python exceptions +class builtin_exception : public std::runtime_error { +public: + using std::runtime_error::runtime_error; + virtual void set_error() const = 0; /// Set the error using the Python C API +}; + +#define PYBIND11_RUNTIME_EXCEPTION(name, type) \ + class name : public builtin_exception { public: \ + using builtin_exception::builtin_exception; \ + name() : name("") { } \ + void set_error() const override { PyErr_SetString(type, what()); } \ + }; + +PYBIND11_RUNTIME_EXCEPTION(stop_iteration, PyExc_StopIteration) +PYBIND11_RUNTIME_EXCEPTION(index_error, PyExc_IndexError) +PYBIND11_RUNTIME_EXCEPTION(key_error, PyExc_KeyError) +PYBIND11_RUNTIME_EXCEPTION(value_error, PyExc_ValueError) +PYBIND11_RUNTIME_EXCEPTION(type_error, PyExc_TypeError) +PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybind11::cast or handle::call fail due to a type casting error +PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally + +[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); } +[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); } + +/// Format strings for basic number types +#define PYBIND11_DECL_FMT(t, v) template<> struct format_descriptor \ + { static constexpr const char* value = v; /* for backwards compatibility */ \ + static std::string format() { return value; } } + +template struct format_descriptor { }; + +template struct format_descriptor::value>> { + static constexpr const char c = "bBhHiIqQ"[detail::log2(sizeof(T))*2 + std::is_unsigned::value]; + static constexpr const char value[2] = { c, '\0' }; + static std::string format() { return std::string(1, c); } +}; + +template constexpr const char format_descriptor< + T, detail::enable_if_t::value>>::value[2]; + +/// RAII wrapper that temporarily clears any Python error state +struct error_scope { + PyObject *type, *value, *trace; + error_scope() { PyErr_Fetch(&type, &value, &trace); } + ~error_scope() { PyErr_Restore(type, value, trace); } +}; + +PYBIND11_DECL_FMT(float, "f"); +PYBIND11_DECL_FMT(double, "d"); +PYBIND11_DECL_FMT(bool, "?"); + +/// Dummy destructor wrapper that can be used to expose classes with a private destructor +struct nodelete { template void operator()(T*) { } }; + +NAMESPACE_END(pybind11) diff --git a/resources/pybind11/include/pybind11/complex.h b/resources/pybind11/include/pybind11/complex.h new file mode 100755 index 0000000..f767f35 --- /dev/null +++ b/resources/pybind11/include/pybind11/complex.h @@ -0,0 +1,47 @@ +/* + pybind11/complex.h: Complex number support + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include + +/// glibc defines I as a macro which breaks things, e.g., boost template names +#ifdef I +# undef I +#endif + +NAMESPACE_BEGIN(pybind11) + +PYBIND11_DECL_FMT(std::complex, "Zf"); +PYBIND11_DECL_FMT(std::complex, "Zd"); + +NAMESPACE_BEGIN(detail) +template class type_caster> { +public: + bool load(handle src, bool) { + if (!src) + return false; + Py_complex result = PyComplex_AsCComplex(src.ptr()); + if (result.real == -1.0 && PyErr_Occurred()) { + PyErr_Clear(); + return false; + } + value = std::complex((T) result.real, (T) result.imag); + return true; + } + + static handle cast(const std::complex &src, return_value_policy /* policy */, handle /* parent */) { + return PyComplex_FromDoubles((double) src.real(), (double) src.imag()); + } + + PYBIND11_TYPE_CASTER(std::complex, _("complex")); +}; +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/resources/pybind11/include/pybind11/descr.h b/resources/pybind11/include/pybind11/descr.h new file mode 100755 index 0000000..22e94ef --- /dev/null +++ b/resources/pybind11/include/pybind11/descr.h @@ -0,0 +1,177 @@ +/* + pybind11/descr.h: Helper type for concatenating type signatures + either at runtime (C++11) or compile time (C++14) + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "common.h" + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + +#if defined(PYBIND11_CPP14) /* Concatenate type signatures at compile time using C++14 */ + +template class descr { + template friend class descr; +public: + constexpr descr(char const (&text) [Size1+1], const std::type_info * const (&types)[Size2+1]) + : descr(text, types, + make_index_sequence(), + make_index_sequence()) { } + + constexpr const char *text() const { return m_text; } + constexpr const std::type_info * const * types() const { return m_types; } + + template + constexpr descr operator+(const descr &other) const { + return concat(other, + make_index_sequence(), + make_index_sequence(), + make_index_sequence(), + make_index_sequence()); + } + +protected: + template + constexpr descr( + char const (&text) [Size1+1], + const std::type_info * const (&types) [Size2+1], + index_sequence, index_sequence) + : m_text{text[Indices1]..., '\0'}, + m_types{types[Indices2]..., nullptr } {} + + template + constexpr descr + concat(const descr &other, + index_sequence, index_sequence, + index_sequence, index_sequence) const { + return descr( + { m_text[Indices1]..., other.m_text[OtherIndices1]..., '\0' }, + { m_types[Indices2]..., other.m_types[OtherIndices2]..., nullptr } + ); + } + +protected: + char m_text[Size1 + 1]; + const std::type_info * m_types[Size2 + 1]; +}; + +template constexpr descr _(char const(&text)[Size]) { + return descr(text, { nullptr }); +} + +template struct int_to_str : int_to_str { }; +template struct int_to_str<0, Digits...> { + static constexpr auto digits = descr({ ('0' + Digits)..., '\0' }, { nullptr }); +}; + +// Ternary description (like std::conditional) +template +constexpr enable_if_t> _(char const(&text1)[Size1], char const(&)[Size2]) { + return _(text1); +} +template +constexpr enable_if_t> _(char const(&)[Size1], char const(&text2)[Size2]) { + return _(text2); +} + +template auto constexpr _() -> decltype(int_to_str::digits) { + return int_to_str::digits; +} + +template constexpr descr<1, 1> _() { + return descr<1, 1>({ '%', '\0' }, { &typeid(Type), nullptr }); +} + +inline constexpr descr<0, 0> concat() { return _(""); } +template auto constexpr concat(descr descr) { return descr; } +template auto constexpr concat(descr descr, Args&&... args) { return descr + _(", ") + concat(args...); } +template auto constexpr type_descr(descr descr) { return _("{") + descr + _("}"); } + +#define PYBIND11_DESCR constexpr auto + +#else /* Simpler C++11 implementation based on run-time memory allocation and copying */ + +class descr { +public: + PYBIND11_NOINLINE descr(const char *text, const std::type_info * const * types) { + size_t nChars = len(text), nTypes = len(types); + m_text = new char[nChars]; + m_types = new const std::type_info *[nTypes]; + memcpy(m_text, text, nChars * sizeof(char)); + memcpy(m_types, types, nTypes * sizeof(const std::type_info *)); + } + + PYBIND11_NOINLINE descr friend operator+(descr &&d1, descr &&d2) { + descr r; + + size_t nChars1 = len(d1.m_text), nTypes1 = len(d1.m_types); + size_t nChars2 = len(d2.m_text), nTypes2 = len(d2.m_types); + + r.m_text = new char[nChars1 + nChars2 - 1]; + r.m_types = new const std::type_info *[nTypes1 + nTypes2 - 1]; + memcpy(r.m_text, d1.m_text, (nChars1-1) * sizeof(char)); + memcpy(r.m_text + nChars1 - 1, d2.m_text, nChars2 * sizeof(char)); + memcpy(r.m_types, d1.m_types, (nTypes1-1) * sizeof(std::type_info *)); + memcpy(r.m_types + nTypes1 - 1, d2.m_types, nTypes2 * sizeof(std::type_info *)); + + delete[] d1.m_text; delete[] d1.m_types; + delete[] d2.m_text; delete[] d2.m_types; + + return r; + } + + char *text() { return m_text; } + const std::type_info * * types() { return m_types; } + +protected: + PYBIND11_NOINLINE descr() { } + + template static size_t len(const T *ptr) { // return length including null termination + const T *it = ptr; + while (*it++ != (T) 0) + ; + return static_cast(it - ptr); + } + + const std::type_info **m_types = nullptr; + char *m_text = nullptr; +}; + +/* The 'PYBIND11_NOINLINE inline' combinations below are intentional to get the desired linkage while producing as little object code as possible */ + +PYBIND11_NOINLINE inline descr _(const char *text) { + const std::type_info *types[1] = { nullptr }; + return descr(text, types); +} + +template PYBIND11_NOINLINE enable_if_t _(const char *text1, const char *) { return _(text1); } +template PYBIND11_NOINLINE enable_if_t _(char const *, const char *text2) { return _(text2); } + +template PYBIND11_NOINLINE descr _() { + const std::type_info *types[2] = { &typeid(Type), nullptr }; + return descr("%", types); +} + +template PYBIND11_NOINLINE descr _() { + const std::type_info *types[1] = { nullptr }; + return descr(std::to_string(Size).c_str(), types); +} + +PYBIND11_NOINLINE inline descr concat() { return _(""); } +PYBIND11_NOINLINE inline descr concat(descr &&d) { return d; } +template PYBIND11_NOINLINE descr concat(descr &&d, Args&&... args) { return std::move(d) + _(", ") + concat(std::forward(args)...); } +PYBIND11_NOINLINE inline descr type_descr(descr&& d) { return _("{") + std::move(d) + _("}"); } + +#define PYBIND11_DESCR ::pybind11::detail::descr +#endif + +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/resources/pybind11/include/pybind11/eigen.h b/resources/pybind11/include/pybind11/eigen.h new file mode 100755 index 0000000..0a1208e --- /dev/null +++ b/resources/pybind11/include/pybind11/eigen.h @@ -0,0 +1,239 @@ +/* + pybind11/eigen.h: Transparent conversion for dense and sparse Eigen matrices + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "numpy.h" + +#if defined(__INTEL_COMPILER) +# pragma warning(disable: 1682) // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem) +#elif defined(__GNUG__) || defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +#include +#include + +#if defined(__GNUG__) || defined(__clang__) +# pragma GCC diagnostic pop +#endif + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + +template using is_eigen_dense = is_template_base_of; +template using is_eigen_sparse = is_template_base_of; +template using is_eigen_ref = is_template_base_of; + +// Test for objects inheriting from EigenBase that aren't captured by the above. This +// basically covers anything that can be assigned to a dense matrix but that don't have a typical +// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and +// SelfAdjointView fall into this category. +template using is_eigen_base = bool_constant< + is_template_base_of::value + && !is_eigen_dense::value && !is_eigen_sparse::value +>; + +template +struct type_caster::value && !is_eigen_ref::value>> { + typedef typename Type::Scalar Scalar; + static constexpr bool rowMajor = Type::Flags & Eigen::RowMajorBit; + static constexpr bool isVector = Type::IsVectorAtCompileTime; + + bool load(handle src, bool) { + auto buf = array_t::ensure(src); + if (!buf) + return false; + + if (buf.ndim() == 1) { + typedef Eigen::InnerStride<> Strides; + if (!isVector && + !(Type::RowsAtCompileTime == Eigen::Dynamic && + Type::ColsAtCompileTime == Eigen::Dynamic)) + return false; + + if (Type::SizeAtCompileTime != Eigen::Dynamic && + buf.shape(0) != (size_t) Type::SizeAtCompileTime) + return false; + + Strides::Index n_elts = (Strides::Index) buf.shape(0); + Strides::Index unity = 1; + + value = Eigen::Map( + buf.mutable_data(), + rowMajor ? unity : n_elts, + rowMajor ? n_elts : unity, + Strides(buf.strides(0) / sizeof(Scalar)) + ); + } else if (buf.ndim() == 2) { + typedef Eigen::Stride Strides; + + if ((Type::RowsAtCompileTime != Eigen::Dynamic && buf.shape(0) != (size_t) Type::RowsAtCompileTime) || + (Type::ColsAtCompileTime != Eigen::Dynamic && buf.shape(1) != (size_t) Type::ColsAtCompileTime)) + return false; + + value = Eigen::Map( + buf.mutable_data(), + typename Strides::Index(buf.shape(0)), + typename Strides::Index(buf.shape(1)), + Strides(buf.strides(rowMajor ? 0 : 1) / sizeof(Scalar), + buf.strides(rowMajor ? 1 : 0) / sizeof(Scalar)) + ); + } else { + return false; + } + return true; + } + + static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) { + if (isVector) { + return array( + { (size_t) src.size() }, // shape + { sizeof(Scalar) * static_cast(src.innerStride()) }, // strides + src.data() // data + ).release(); + } else { + return array( + { (size_t) src.rows(), // shape + (size_t) src.cols() }, + { sizeof(Scalar) * static_cast(src.rowStride()), // strides + sizeof(Scalar) * static_cast(src.colStride()) }, + src.data() // data + ).release(); + } + } + + PYBIND11_TYPE_CASTER(Type, _("numpy.ndarray[") + npy_format_descriptor::name() + + _("[") + rows() + _(", ") + cols() + _("]]")); + +protected: + template = 0> + static PYBIND11_DESCR rows() { return _("m"); } + template = 0> + static PYBIND11_DESCR rows() { return _(); } + template = 0> + static PYBIND11_DESCR cols() { return _("n"); } + template = 0> + static PYBIND11_DESCR cols() { return _(); } +}; + +// Eigen::Ref satisfies is_eigen_dense, but isn't constructable, so it needs a special +// type_caster to handle argument copying/forwarding. +template +struct type_caster> { +protected: + using Type = Eigen::Ref; + using Derived = typename std::remove_const::type; + using DerivedCaster = type_caster; + DerivedCaster derived_caster; + std::unique_ptr value; +public: + bool load(handle src, bool convert) { if (derived_caster.load(src, convert)) { value.reset(new Type(derived_caster.operator Derived&())); return true; } return false; } + static handle cast(const Type &src, return_value_policy policy, handle parent) { return DerivedCaster::cast(src, policy, parent); } + static handle cast(const Type *src, return_value_policy policy, handle parent) { return DerivedCaster::cast(*src, policy, parent); } + + static PYBIND11_DESCR name() { return DerivedCaster::name(); } + + operator Type*() { return value.get(); } + operator Type&() { if (!value) pybind11_fail("Eigen::Ref<...> value not loaded"); return *value; } + template using cast_op_type = pybind11::detail::cast_op_type<_T>; +}; + +// type_caster for special matrix types (e.g. DiagonalMatrix): load() is not supported, but we can +// cast them into the python domain by first copying to a regular Eigen::Matrix, then casting that. +template +struct type_caster::value && !is_eigen_ref::value>> { +protected: + using Matrix = Eigen::Matrix; + using MatrixCaster = type_caster; +public: + [[noreturn]] bool load(handle, bool) { pybind11_fail("Unable to load() into specialized EigenBase object"); } + static handle cast(const Type &src, return_value_policy policy, handle parent) { return MatrixCaster::cast(Matrix(src), policy, parent); } + static handle cast(const Type *src, return_value_policy policy, handle parent) { return MatrixCaster::cast(Matrix(*src), policy, parent); } + + static PYBIND11_DESCR name() { return MatrixCaster::name(); } + + [[noreturn]] operator Type*() { pybind11_fail("Loading not supported for specialized EigenBase object"); } + [[noreturn]] operator Type&() { pybind11_fail("Loading not supported for specialized EigenBase object"); } + template using cast_op_type = pybind11::detail::cast_op_type<_T>; +}; + +template +struct type_caster::value>> { + typedef typename Type::Scalar Scalar; + typedef typename std::remove_reference().outerIndexPtr())>::type StorageIndex; + typedef typename Type::Index Index; + static constexpr bool rowMajor = Type::Flags & Eigen::RowMajorBit; + + bool load(handle src, bool) { + if (!src) + return false; + + auto obj = reinterpret_borrow(src); + object sparse_module = module::import("scipy.sparse"); + object matrix_type = sparse_module.attr( + rowMajor ? "csr_matrix" : "csc_matrix"); + + if (obj.get_type() != matrix_type.ptr()) { + try { + obj = matrix_type(obj); + } catch (const error_already_set &) { + return false; + } + } + + auto values = array_t((object) obj.attr("data")); + auto innerIndices = array_t((object) obj.attr("indices")); + auto outerIndices = array_t((object) obj.attr("indptr")); + auto shape = pybind11::tuple((pybind11::object) obj.attr("shape")); + auto nnz = obj.attr("nnz").cast(); + + if (!values || !innerIndices || !outerIndices) + return false; + + value = Eigen::MappedSparseMatrix( + shape[0].cast(), shape[1].cast(), nnz, + outerIndices.mutable_data(), innerIndices.mutable_data(), values.mutable_data()); + + return true; + } + + static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) { + const_cast(src).makeCompressed(); + + object matrix_type = module::import("scipy.sparse").attr( + rowMajor ? "csr_matrix" : "csc_matrix"); + + array data((size_t) src.nonZeros(), src.valuePtr()); + array outerIndices((size_t) (rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr()); + array innerIndices((size_t) src.nonZeros(), src.innerIndexPtr()); + + return matrix_type( + std::make_tuple(data, innerIndices, outerIndices), + std::make_pair(src.rows(), src.cols()) + ).release(); + } + + PYBIND11_TYPE_CASTER(Type, _<(Type::Flags & Eigen::RowMajorBit) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[") + + npy_format_descriptor::name() + _("]")); +}; + +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif diff --git a/resources/pybind11/include/pybind11/eval.h b/resources/pybind11/include/pybind11/eval.h new file mode 100755 index 0000000..204427d --- /dev/null +++ b/resources/pybind11/include/pybind11/eval.h @@ -0,0 +1,105 @@ +/* + pybind11/exec.h: Support for evaluating Python expressions and statements + from strings and files + + Copyright (c) 2016 Klemens Morgenstern and + Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#pragma once + +#include "pybind11.h" + +NAMESPACE_BEGIN(pybind11) + +enum eval_mode { + /// Evaluate a string containing an isolated expression + eval_expr, + + /// Evaluate a string containing a single statement. Returns \c none + eval_single_statement, + + /// Evaluate a string containing a sequence of statement. Returns \c none + eval_statements +}; + +template +object eval(str expr, object global = object(), object local = object()) { + if (!global) { + global = reinterpret_borrow(PyEval_GetGlobals()); + if (!global) + global = dict(); + } + if (!local) + local = global; + + /* PyRun_String does not accept a PyObject / encoding specifier, + this seems to be the only alternative */ + std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr; + + int start; + switch (mode) { + case eval_expr: start = Py_eval_input; break; + case eval_single_statement: start = Py_single_input; break; + case eval_statements: start = Py_file_input; break; + default: pybind11_fail("invalid evaluation mode"); + } + + PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr()); + if (!result) + throw error_already_set(); + return reinterpret_steal(result); +} + +template +object eval_file(str fname, object global = object(), object local = object()) { + if (!global) { + global = reinterpret_borrow(PyEval_GetGlobals()); + if (!global) + global = dict(); + } + if (!local) + local = global; + + int start; + switch (mode) { + case eval_expr: start = Py_eval_input; break; + case eval_single_statement: start = Py_single_input; break; + case eval_statements: start = Py_file_input; break; + default: pybind11_fail("invalid evaluation mode"); + } + + int closeFile = 1; + std::string fname_str = (std::string) fname; +#if PY_VERSION_HEX >= 0x03040000 + FILE *f = _Py_fopen_obj(fname.ptr(), "r"); +#elif PY_VERSION_HEX >= 0x03000000 + FILE *f = _Py_fopen(fname.ptr(), "r"); +#else + /* No unicode support in open() :( */ + auto fobj = reinterpret_steal(PyFile_FromString( + const_cast(fname_str.c_str()), + const_cast("r"))); + FILE *f = nullptr; + if (fobj) + f = PyFile_AsFile(fobj.ptr()); + closeFile = 0; +#endif + if (!f) { + PyErr_Clear(); + pybind11_fail("File \"" + fname_str + "\" could not be opened!"); + } + + PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), + local.ptr(), closeFile); + if (!result) + throw error_already_set(); + return reinterpret_steal(result); +} + +NAMESPACE_END(pybind11) diff --git a/resources/pybind11/include/pybind11/functional.h b/resources/pybind11/include/pybind11/functional.h new file mode 100755 index 0000000..f1b0ebb --- /dev/null +++ b/resources/pybind11/include/pybind11/functional.h @@ -0,0 +1,79 @@ +/* + pybind11/functional.h: std::function<> support + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + +template struct type_caster> { + typedef std::function type; + typedef typename std::conditional::value, void_type, Return>::type retval_type; +public: + bool load(handle src_, bool) { + if (src_.is_none()) + return true; + + src_ = detail::get_function(src_); + if (!src_ || !PyCallable_Check(src_.ptr())) + return false; + + /* + When passing a C++ function as an argument to another C++ + function via Python, every function call would normally involve + a full C++ -> Python -> C++ roundtrip, which can be prohibitive. + Here, we try to at least detect the case where the function is + stateless (i.e. function pointer or lambda function without + captured variables), in which case the roundtrip can be avoided. + */ + if (PyCFunction_Check(src_.ptr())) { + auto c = reinterpret_borrow(PyCFunction_GetSelf(src_.ptr())); + auto rec = (function_record *) c; + using FunctionType = Return (*) (Args...); + + if (rec && rec->is_stateless && rec->data[1] == &typeid(FunctionType)) { + struct capture { FunctionType f; }; + value = ((capture *) &rec->data)->f; + return true; + } + } + + auto src = reinterpret_borrow(src_); + value = [src](Args... args) -> Return { + gil_scoped_acquire acq; + object retval(src(std::move(args)...)); + /* Visual studio 2015 parser issue: need parentheses around this expression */ + return (retval.template cast()); + }; + return true; + } + + template + static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) { + if (!f_) + return none().inc_ref(); + + auto result = f_.template target(); + if (result) + return cpp_function(*result, policy).release(); + else + return cpp_function(std::forward(f_), policy).release(); + } + + PYBIND11_TYPE_CASTER(type, _("Callable[[") + + argument_loader::arg_names() + _("], ") + + type_caster::name() + + _("]")); +}; + +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/resources/pybind11/include/pybind11/numpy.h b/resources/pybind11/include/pybind11/numpy.h new file mode 100755 index 0000000..e6f4efd --- /dev/null +++ b/resources/pybind11/include/pybind11/numpy.h @@ -0,0 +1,1169 @@ +/* + pybind11/numpy.h: Basic NumPy support, vectorize() wrapper + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include "complex.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +/* This will be true on all flat address space platforms and allows us to reduce the + whole npy_intp / size_t / Py_intptr_t business down to just size_t for all size + and dimension types (e.g. shape, strides, indexing), instead of inflicting this + upon the library user. */ +static_assert(sizeof(size_t) == sizeof(Py_intptr_t), "size_t != Py_intptr_t"); + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) +template struct npy_format_descriptor { }; +template struct is_pod_struct; + +struct PyArrayDescr_Proxy { + PyObject_HEAD + PyObject *typeobj; + char kind; + char type; + char byteorder; + char flags; + int type_num; + int elsize; + int alignment; + char *subarray; + PyObject *fields; + PyObject *names; +}; + +struct PyArray_Proxy { + PyObject_HEAD + char *data; + int nd; + ssize_t *dimensions; + ssize_t *strides; + PyObject *base; + PyObject *descr; + int flags; +}; + +struct PyVoidScalarObject_Proxy { + PyObject_VAR_HEAD + char *obval; + PyArrayDescr_Proxy *descr; + int flags; + PyObject *base; +}; + +struct numpy_type_info { + PyObject* dtype_ptr; + std::string format_str; +}; + +struct numpy_internals { + std::unordered_map registered_dtypes; + + numpy_type_info *get_type_info(const std::type_info& tinfo, bool throw_if_missing = true) { + auto it = registered_dtypes.find(std::type_index(tinfo)); + if (it != registered_dtypes.end()) + return &(it->second); + if (throw_if_missing) + pybind11_fail(std::string("NumPy type info missing for ") + tinfo.name()); + return nullptr; + } + + template numpy_type_info *get_type_info(bool throw_if_missing = true) { + return get_type_info(typeid(typename std::remove_cv::type), throw_if_missing); + } +}; + +inline PYBIND11_NOINLINE void load_numpy_internals(numpy_internals* &ptr) { + ptr = &get_or_create_shared_data("_numpy_internals"); +} + +inline numpy_internals& get_numpy_internals() { + static numpy_internals* ptr = nullptr; + if (!ptr) + load_numpy_internals(ptr); + return *ptr; +} + +struct npy_api { + enum constants { + NPY_C_CONTIGUOUS_ = 0x0001, + NPY_F_CONTIGUOUS_ = 0x0002, + NPY_ARRAY_OWNDATA_ = 0x0004, + NPY_ARRAY_FORCECAST_ = 0x0010, + NPY_ENSURE_ARRAY_ = 0x0040, + NPY_ARRAY_ALIGNED_ = 0x0100, + NPY_ARRAY_WRITEABLE_ = 0x0400, + NPY_BOOL_ = 0, + NPY_BYTE_, NPY_UBYTE_, + NPY_SHORT_, NPY_USHORT_, + NPY_INT_, NPY_UINT_, + NPY_LONG_, NPY_ULONG_, + NPY_LONGLONG_, NPY_ULONGLONG_, + NPY_FLOAT_, NPY_DOUBLE_, NPY_LONGDOUBLE_, + NPY_CFLOAT_, NPY_CDOUBLE_, NPY_CLONGDOUBLE_, + NPY_OBJECT_ = 17, + NPY_STRING_, NPY_UNICODE_, NPY_VOID_ + }; + + static npy_api& get() { + static npy_api api = lookup(); + return api; + } + + bool PyArray_Check_(PyObject *obj) const { + return (bool) PyObject_TypeCheck(obj, PyArray_Type_); + } + bool PyArrayDescr_Check_(PyObject *obj) const { + return (bool) PyObject_TypeCheck(obj, PyArrayDescr_Type_); + } + + PyObject *(*PyArray_DescrFromType_)(int); + PyObject *(*PyArray_NewFromDescr_) + (PyTypeObject *, PyObject *, int, Py_intptr_t *, + Py_intptr_t *, void *, int, PyObject *); + PyObject *(*PyArray_DescrNewFromType_)(int); + PyObject *(*PyArray_NewCopy_)(PyObject *, int); + PyTypeObject *PyArray_Type_; + PyTypeObject *PyVoidArrType_Type_; + PyTypeObject *PyArrayDescr_Type_; + PyObject *(*PyArray_DescrFromScalar_)(PyObject *); + PyObject *(*PyArray_FromAny_) (PyObject *, PyObject *, int, int, int, PyObject *); + int (*PyArray_DescrConverter_) (PyObject *, PyObject **); + bool (*PyArray_EquivTypes_) (PyObject *, PyObject *); + int (*PyArray_GetArrayParamsFromObject_)(PyObject *, PyObject *, char, PyObject **, int *, + Py_ssize_t *, PyObject **, PyObject *); + PyObject *(*PyArray_Squeeze_)(PyObject *); +private: + enum functions { + API_PyArray_Type = 2, + API_PyArrayDescr_Type = 3, + API_PyVoidArrType_Type = 39, + API_PyArray_DescrFromType = 45, + API_PyArray_DescrFromScalar = 57, + API_PyArray_FromAny = 69, + API_PyArray_NewCopy = 85, + API_PyArray_NewFromDescr = 94, + API_PyArray_DescrNewFromType = 9, + API_PyArray_DescrConverter = 174, + API_PyArray_EquivTypes = 182, + API_PyArray_GetArrayParamsFromObject = 278, + API_PyArray_Squeeze = 136 + }; + + static npy_api lookup() { + module m = module::import("numpy.core.multiarray"); + auto c = m.attr("_ARRAY_API"); +#if PY_MAJOR_VERSION >= 3 + void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL); +#else + void **api_ptr = (void **) PyCObject_AsVoidPtr(c.ptr()); +#endif + npy_api api; +#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func]; + DECL_NPY_API(PyArray_Type); + DECL_NPY_API(PyVoidArrType_Type); + DECL_NPY_API(PyArrayDescr_Type); + DECL_NPY_API(PyArray_DescrFromType); + DECL_NPY_API(PyArray_DescrFromScalar); + DECL_NPY_API(PyArray_FromAny); + DECL_NPY_API(PyArray_NewCopy); + DECL_NPY_API(PyArray_NewFromDescr); + DECL_NPY_API(PyArray_DescrNewFromType); + DECL_NPY_API(PyArray_DescrConverter); + DECL_NPY_API(PyArray_EquivTypes); + DECL_NPY_API(PyArray_GetArrayParamsFromObject); + DECL_NPY_API(PyArray_Squeeze); +#undef DECL_NPY_API + return api; + } +}; + +inline PyArray_Proxy* array_proxy(void* ptr) { + return reinterpret_cast(ptr); +} + +inline const PyArray_Proxy* array_proxy(const void* ptr) { + return reinterpret_cast(ptr); +} + +inline PyArrayDescr_Proxy* array_descriptor_proxy(PyObject* ptr) { + return reinterpret_cast(ptr); +} + +inline const PyArrayDescr_Proxy* array_descriptor_proxy(const PyObject* ptr) { + return reinterpret_cast(ptr); +} + +inline bool check_flags(const void* ptr, int flag) { + return (flag == (array_proxy(ptr)->flags & flag)); +} + +NAMESPACE_END(detail) + +class dtype : public object { +public: + PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_); + + explicit dtype(const buffer_info &info) { + dtype descr(_dtype_from_pep3118()(PYBIND11_STR_TYPE(info.format))); + // If info.itemsize == 0, use the value calculated from the format string + m_ptr = descr.strip_padding(info.itemsize ? info.itemsize : descr.itemsize()).release().ptr(); + } + + explicit dtype(const std::string &format) { + m_ptr = from_args(pybind11::str(format)).release().ptr(); + } + + dtype(const char *format) : dtype(std::string(format)) { } + + dtype(list names, list formats, list offsets, size_t itemsize) { + dict args; + args["names"] = names; + args["formats"] = formats; + args["offsets"] = offsets; + args["itemsize"] = pybind11::int_(itemsize); + m_ptr = from_args(args).release().ptr(); + } + + /// This is essentially the same as calling numpy.dtype(args) in Python. + static dtype from_args(object args) { + PyObject *ptr = nullptr; + if (!detail::npy_api::get().PyArray_DescrConverter_(args.release().ptr(), &ptr) || !ptr) + throw error_already_set(); + return reinterpret_steal(ptr); + } + + /// Return dtype associated with a C++ type. + template static dtype of() { + return detail::npy_format_descriptor::type>::dtype(); + } + + /// Size of the data type in bytes. + size_t itemsize() const { + return (size_t) detail::array_descriptor_proxy(m_ptr)->elsize; + } + + /// Returns true for structured data types. + bool has_fields() const { + return detail::array_descriptor_proxy(m_ptr)->names != nullptr; + } + + /// Single-character type code. + char kind() const { + return detail::array_descriptor_proxy(m_ptr)->kind; + } + +private: + static object _dtype_from_pep3118() { + static PyObject *obj = module::import("numpy.core._internal") + .attr("_dtype_from_pep3118").cast().release().ptr(); + return reinterpret_borrow(obj); + } + + dtype strip_padding(size_t itemsize) { + // Recursively strip all void fields with empty names that are generated for + // padding fields (as of NumPy v1.11). + if (!has_fields()) + return *this; + + struct field_descr { PYBIND11_STR_TYPE name; object format; pybind11::int_ offset; }; + std::vector field_descriptors; + + for (auto field : attr("fields").attr("items")()) { + auto spec = field.cast(); + auto name = spec[0].cast(); + auto format = spec[1].cast()[0].cast(); + auto offset = spec[1].cast()[1].cast(); + if (!len(name) && format.kind() == 'V') + continue; + field_descriptors.push_back({(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset}); + } + + std::sort(field_descriptors.begin(), field_descriptors.end(), + [](const field_descr& a, const field_descr& b) { + return a.offset.cast() < b.offset.cast(); + }); + + list names, formats, offsets; + for (auto& descr : field_descriptors) { + names.append(descr.name); + formats.append(descr.format); + offsets.append(descr.offset); + } + return dtype(names, formats, offsets, itemsize); + } +}; + +class array : public buffer { +public: + PYBIND11_OBJECT_CVT(array, buffer, detail::npy_api::get().PyArray_Check_, raw_array) + + enum { + c_style = detail::npy_api::NPY_C_CONTIGUOUS_, + f_style = detail::npy_api::NPY_F_CONTIGUOUS_, + forcecast = detail::npy_api::NPY_ARRAY_FORCECAST_ + }; + + array() : array(0, static_cast(nullptr)) {} + + array(const pybind11::dtype &dt, const std::vector &shape, + const std::vector &strides, const void *ptr = nullptr, + handle base = handle()) { + auto& api = detail::npy_api::get(); + auto ndim = shape.size(); + if (shape.size() != strides.size()) + pybind11_fail("NumPy: shape ndim doesn't match strides ndim"); + auto descr = dt; + + int flags = 0; + if (base && ptr) { + if (isinstance(base)) + /* Copy flags from base (except baseship bit) */ + flags = reinterpret_borrow(base).flags() & ~detail::npy_api::NPY_ARRAY_OWNDATA_; + else + /* Writable by default, easy to downgrade later on if needed */ + flags = detail::npy_api::NPY_ARRAY_WRITEABLE_; + } + + auto tmp = reinterpret_steal(api.PyArray_NewFromDescr_( + api.PyArray_Type_, descr.release().ptr(), (int) ndim, (Py_intptr_t *) shape.data(), + (Py_intptr_t *) strides.data(), const_cast(ptr), flags, nullptr)); + if (!tmp) + pybind11_fail("NumPy: unable to create array!"); + if (ptr) { + if (base) { + detail::array_proxy(tmp.ptr())->base = base.inc_ref().ptr(); + } else { + tmp = reinterpret_steal(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */)); + } + } + m_ptr = tmp.release().ptr(); + } + + array(const pybind11::dtype &dt, const std::vector &shape, + const void *ptr = nullptr, handle base = handle()) + : array(dt, shape, default_strides(shape, dt.itemsize()), ptr, base) { } + + array(const pybind11::dtype &dt, size_t count, const void *ptr = nullptr, + handle base = handle()) + : array(dt, std::vector{ count }, ptr, base) { } + + template array(const std::vector& shape, + const std::vector& strides, + const T* ptr, handle base = handle()) + : array(pybind11::dtype::of(), shape, strides, (void *) ptr, base) { } + + template + array(const std::vector &shape, const T *ptr, + handle base = handle()) + : array(shape, default_strides(shape, sizeof(T)), ptr, base) { } + + template + array(size_t count, const T *ptr, handle base = handle()) + : array(std::vector{ count }, ptr, base) { } + + explicit array(const buffer_info &info) + : array(pybind11::dtype(info), info.shape, info.strides, info.ptr) { } + + /// Array descriptor (dtype) + pybind11::dtype dtype() const { + return reinterpret_borrow(detail::array_proxy(m_ptr)->descr); + } + + /// Total number of elements + size_t size() const { + return std::accumulate(shape(), shape() + ndim(), (size_t) 1, std::multiplies()); + } + + /// Byte size of a single element + size_t itemsize() const { + return (size_t) detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize; + } + + /// Total number of bytes + size_t nbytes() const { + return size() * itemsize(); + } + + /// Number of dimensions + size_t ndim() const { + return (size_t) detail::array_proxy(m_ptr)->nd; + } + + /// Base object + object base() const { + return reinterpret_borrow(detail::array_proxy(m_ptr)->base); + } + + /// Dimensions of the array + const size_t* shape() const { + return reinterpret_cast(detail::array_proxy(m_ptr)->dimensions); + } + + /// Dimension along a given axis + size_t shape(size_t dim) const { + if (dim >= ndim()) + fail_dim_check(dim, "invalid axis"); + return shape()[dim]; + } + + /// Strides of the array + const size_t* strides() const { + return reinterpret_cast(detail::array_proxy(m_ptr)->strides); + } + + /// Stride along a given axis + size_t strides(size_t dim) const { + if (dim >= ndim()) + fail_dim_check(dim, "invalid axis"); + return strides()[dim]; + } + + /// Return the NumPy array flags + int flags() const { + return detail::array_proxy(m_ptr)->flags; + } + + /// If set, the array is writeable (otherwise the buffer is read-only) + bool writeable() const { + return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_WRITEABLE_); + } + + /// If set, the array owns the data (will be freed when the array is deleted) + bool owndata() const { + return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_OWNDATA_); + } + + /// Pointer to the contained data. If index is not provided, points to the + /// beginning of the buffer. May throw if the index would lead to out of bounds access. + template const void* data(Ix... index) const { + return static_cast(detail::array_proxy(m_ptr)->data + offset_at(index...)); + } + + /// Mutable pointer to the contained data. If index is not provided, points to the + /// beginning of the buffer. May throw if the index would lead to out of bounds access. + /// May throw if the array is not writeable. + template void* mutable_data(Ix... index) { + check_writeable(); + return static_cast(detail::array_proxy(m_ptr)->data + offset_at(index...)); + } + + /// Byte offset from beginning of the array to a given index (full or partial). + /// May throw if the index would lead to out of bounds access. + template size_t offset_at(Ix... index) const { + if (sizeof...(index) > ndim()) + fail_dim_check(sizeof...(index), "too many indices for an array"); + return byte_offset(size_t(index)...); + } + + size_t offset_at() const { return 0; } + + /// Item count from beginning of the array to a given index (full or partial). + /// May throw if the index would lead to out of bounds access. + template size_t index_at(Ix... index) const { + return offset_at(index...) / itemsize(); + } + + /// Return a new view with all of the dimensions of length 1 removed + array squeeze() { + auto& api = detail::npy_api::get(); + return reinterpret_steal(api.PyArray_Squeeze_(m_ptr)); + } + + /// Ensure that the argument is a NumPy array + /// In case of an error, nullptr is returned and the Python error is cleared. + static array ensure(handle h, int ExtraFlags = 0) { + auto result = reinterpret_steal(raw_array(h.ptr(), ExtraFlags)); + if (!result) + PyErr_Clear(); + return result; + } + +protected: + template friend struct detail::npy_format_descriptor; + + void fail_dim_check(size_t dim, const std::string& msg) const { + throw index_error(msg + ": " + std::to_string(dim) + + " (ndim = " + std::to_string(ndim()) + ")"); + } + + template size_t byte_offset(Ix... index) const { + check_dimensions(index...); + return byte_offset_unsafe(index...); + } + + template size_t byte_offset_unsafe(size_t i, Ix... index) const { + return i * strides()[dim] + byte_offset_unsafe(index...); + } + + template size_t byte_offset_unsafe() const { return 0; } + + void check_writeable() const { + if (!writeable()) + throw std::runtime_error("array is not writeable"); + } + + static std::vector default_strides(const std::vector& shape, size_t itemsize) { + auto ndim = shape.size(); + std::vector strides(ndim); + if (ndim) { + std::fill(strides.begin(), strides.end(), itemsize); + for (size_t i = 0; i < ndim - 1; i++) + for (size_t j = 0; j < ndim - 1 - i; j++) + strides[j] *= shape[ndim - 1 - i]; + } + return strides; + } + + template void check_dimensions(Ix... index) const { + check_dimensions_impl(size_t(0), shape(), size_t(index)...); + } + + void check_dimensions_impl(size_t, const size_t*) const { } + + template void check_dimensions_impl(size_t axis, const size_t* shape, size_t i, Ix... index) const { + if (i >= *shape) { + throw index_error(std::string("index ") + std::to_string(i) + + " is out of bounds for axis " + std::to_string(axis) + + " with size " + std::to_string(*shape)); + } + check_dimensions_impl(axis + 1, shape + 1, index...); + } + + /// Create array from any object -- always returns a new reference + static PyObject *raw_array(PyObject *ptr, int ExtraFlags = 0) { + if (ptr == nullptr) + return nullptr; + return detail::npy_api::get().PyArray_FromAny_( + ptr, nullptr, 0, 0, detail::npy_api::NPY_ENSURE_ARRAY_ | ExtraFlags, nullptr); + } +}; + +template class array_t : public array { +public: + array_t() : array(0, static_cast(nullptr)) {} + array_t(handle h, borrowed_t) : array(h, borrowed) { } + array_t(handle h, stolen_t) : array(h, stolen) { } + + PYBIND11_DEPRECATED("Use array_t::ensure() instead") + array_t(handle h, bool is_borrowed) : array(raw_array_t(h.ptr()), stolen) { + if (!m_ptr) PyErr_Clear(); + if (!is_borrowed) Py_XDECREF(h.ptr()); + } + + array_t(const object &o) : array(raw_array_t(o.ptr()), stolen) { + if (!m_ptr) throw error_already_set(); + } + + explicit array_t(const buffer_info& info) : array(info) { } + + array_t(const std::vector &shape, + const std::vector &strides, const T *ptr = nullptr, + handle base = handle()) + : array(shape, strides, ptr, base) { } + + explicit array_t(const std::vector &shape, const T *ptr = nullptr, + handle base = handle()) + : array(shape, ptr, base) { } + + explicit array_t(size_t count, const T *ptr = nullptr, handle base = handle()) + : array(count, ptr, base) { } + + constexpr size_t itemsize() const { + return sizeof(T); + } + + template size_t index_at(Ix... index) const { + return offset_at(index...) / itemsize(); + } + + template const T* data(Ix... index) const { + return static_cast(array::data(index...)); + } + + template T* mutable_data(Ix... index) { + return static_cast(array::mutable_data(index...)); + } + + // Reference to element at a given index + template const T& at(Ix... index) const { + if (sizeof...(index) != ndim()) + fail_dim_check(sizeof...(index), "index dimension mismatch"); + return *(static_cast(array::data()) + byte_offset(size_t(index)...) / itemsize()); + } + + // Mutable reference to element at a given index + template T& mutable_at(Ix... index) { + if (sizeof...(index) != ndim()) + fail_dim_check(sizeof...(index), "index dimension mismatch"); + return *(static_cast(array::mutable_data()) + byte_offset(size_t(index)...) / itemsize()); + } + + /// Ensure that the argument is a NumPy array of the correct dtype. + /// In case of an error, nullptr is returned and the Python error is cleared. + static array_t ensure(handle h) { + auto result = reinterpret_steal(raw_array_t(h.ptr())); + if (!result) + PyErr_Clear(); + return result; + } + + static bool _check(handle h) { + const auto &api = detail::npy_api::get(); + return api.PyArray_Check_(h.ptr()) + && api.PyArray_EquivTypes_(detail::array_proxy(h.ptr())->descr, dtype::of().ptr()); + } + +protected: + /// Create array from any object -- always returns a new reference + static PyObject *raw_array_t(PyObject *ptr) { + if (ptr == nullptr) + return nullptr; + return detail::npy_api::get().PyArray_FromAny_( + ptr, dtype::of().release().ptr(), 0, 0, + detail::npy_api::NPY_ENSURE_ARRAY_ | ExtraFlags, nullptr); + } +}; + +template +struct format_descriptor::value>> { + static std::string format() { + return detail::npy_format_descriptor::type>::format(); + } +}; + +template struct format_descriptor { + static std::string format() { return std::to_string(N) + "s"; } +}; +template struct format_descriptor> { + static std::string format() { return std::to_string(N) + "s"; } +}; + +template +struct format_descriptor::value>> { + static std::string format() { + return format_descriptor< + typename std::remove_cv::type>::type>::format(); + } +}; + +NAMESPACE_BEGIN(detail) +template +struct pyobject_caster> { + using type = array_t; + + bool load(handle src, bool /* convert */) { + value = type::ensure(src); + return static_cast(value); + } + + static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) { + return src.inc_ref(); + } + PYBIND11_TYPE_CASTER(type, handle_type_name::name()); +}; + +template struct is_std_array : std::false_type { }; +template struct is_std_array> : std::true_type { }; + +template +struct is_pod_struct { + enum { value = std::is_pod::value && // offsetof only works correctly for POD types + !std::is_reference::value && + !std::is_array::value && + !is_std_array::value && + !std::is_integral::value && + !std::is_enum::value && + !std::is_same::type, float>::value && + !std::is_same::type, double>::value && + !std::is_same::type, bool>::value && + !std::is_same::type, std::complex>::value && + !std::is_same::type, std::complex>::value }; +}; + +template struct npy_format_descriptor::value>> { +private: + constexpr static const int values[8] = { + npy_api::NPY_BYTE_, npy_api::NPY_UBYTE_, npy_api::NPY_SHORT_, npy_api::NPY_USHORT_, + npy_api::NPY_INT_, npy_api::NPY_UINT_, npy_api::NPY_LONGLONG_, npy_api::NPY_ULONGLONG_ }; +public: + enum { value = values[detail::log2(sizeof(T)) * 2 + (std::is_unsigned::value ? 1 : 0)] }; + static pybind11::dtype dtype() { + if (auto ptr = npy_api::get().PyArray_DescrFromType_(value)) + return reinterpret_borrow(ptr); + pybind11_fail("Unsupported buffer format!"); + } + template ::value, int> = 0> + static PYBIND11_DESCR name() { return _("int") + _(); } + template ::value, int> = 0> + static PYBIND11_DESCR name() { return _("uint") + _(); } +}; +template constexpr const int npy_format_descriptor< + T, enable_if_t::value>>::values[8]; + +#define DECL_FMT(Type, NumPyName, Name) template<> struct npy_format_descriptor { \ + enum { value = npy_api::NumPyName }; \ + static pybind11::dtype dtype() { \ + if (auto ptr = npy_api::get().PyArray_DescrFromType_(value)) \ + return reinterpret_borrow(ptr); \ + pybind11_fail("Unsupported buffer format!"); \ + } \ + static PYBIND11_DESCR name() { return _(Name); } } +DECL_FMT(float, NPY_FLOAT_, "float32"); +DECL_FMT(double, NPY_DOUBLE_, "float64"); +DECL_FMT(bool, NPY_BOOL_, "bool"); +DECL_FMT(std::complex, NPY_CFLOAT_, "complex64"); +DECL_FMT(std::complex, NPY_CDOUBLE_, "complex128"); +#undef DECL_FMT + +#define DECL_CHAR_FMT \ + static PYBIND11_DESCR name() { return _("S") + _(); } \ + static pybind11::dtype dtype() { return pybind11::dtype(std::string("S") + std::to_string(N)); } +template struct npy_format_descriptor { DECL_CHAR_FMT }; +template struct npy_format_descriptor> { DECL_CHAR_FMT }; +#undef DECL_CHAR_FMT + +template struct npy_format_descriptor::value>> { +private: + using base_descr = npy_format_descriptor::type>; +public: + static PYBIND11_DESCR name() { return base_descr::name(); } + static pybind11::dtype dtype() { return base_descr::dtype(); } +}; + +struct field_descriptor { + const char *name; + size_t offset; + size_t size; + size_t alignment; + std::string format; + dtype descr; +}; + +inline PYBIND11_NOINLINE void register_structured_dtype( + const std::initializer_list& fields, + const std::type_info& tinfo, size_t itemsize, + bool (*direct_converter)(PyObject *, void *&)) { + + auto& numpy_internals = get_numpy_internals(); + if (numpy_internals.get_type_info(tinfo, false)) + pybind11_fail("NumPy: dtype is already registered"); + + list names, formats, offsets; + for (auto field : fields) { + if (!field.descr) + pybind11_fail(std::string("NumPy: unsupported field dtype: `") + + field.name + "` @ " + tinfo.name()); + names.append(PYBIND11_STR_TYPE(field.name)); + formats.append(field.descr); + offsets.append(pybind11::int_(field.offset)); + } + auto dtype_ptr = pybind11::dtype(names, formats, offsets, itemsize).release().ptr(); + + // There is an existing bug in NumPy (as of v1.11): trailing bytes are + // not encoded explicitly into the format string. This will supposedly + // get fixed in v1.12; for further details, see these: + // - https://github.com/numpy/numpy/issues/7797 + // - https://github.com/numpy/numpy/pull/7798 + // Because of this, we won't use numpy's logic to generate buffer format + // strings and will just do it ourselves. + std::vector ordered_fields(fields); + std::sort(ordered_fields.begin(), ordered_fields.end(), + [](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; }); + size_t offset = 0; + std::ostringstream oss; + oss << "T{"; + for (auto& field : ordered_fields) { + if (field.offset > offset) + oss << (field.offset - offset) << 'x'; + // mark unaligned fields with '=' + if (field.offset % field.alignment) + oss << '='; + oss << field.format << ':' << field.name << ':'; + offset = field.offset + field.size; + } + if (itemsize > offset) + oss << (itemsize - offset) << 'x'; + oss << '}'; + auto format_str = oss.str(); + + // Sanity check: verify that NumPy properly parses our buffer format string + auto& api = npy_api::get(); + auto arr = array(buffer_info(nullptr, itemsize, format_str, 1)); + if (!api.PyArray_EquivTypes_(dtype_ptr, arr.dtype().ptr())) + pybind11_fail("NumPy: invalid buffer descriptor!"); + + auto tindex = std::type_index(tinfo); + numpy_internals.registered_dtypes[tindex] = { dtype_ptr, format_str }; + get_internals().direct_conversions[tindex].push_back(direct_converter); +} + +template +struct npy_format_descriptor::value>> { + static PYBIND11_DESCR name() { return _("struct"); } + + static pybind11::dtype dtype() { + return reinterpret_borrow(dtype_ptr()); + } + + static std::string format() { + static auto format_str = get_numpy_internals().get_type_info(true)->format_str; + return format_str; + } + + static void register_dtype(const std::initializer_list& fields) { + register_structured_dtype(fields, typeid(typename std::remove_cv::type), + sizeof(T), &direct_converter); + } + +private: + static PyObject* dtype_ptr() { + static PyObject* ptr = get_numpy_internals().get_type_info(true)->dtype_ptr; + return ptr; + } + + static bool direct_converter(PyObject *obj, void*& value) { + auto& api = npy_api::get(); + if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_)) + return false; + if (auto descr = reinterpret_steal(api.PyArray_DescrFromScalar_(obj))) { + if (api.PyArray_EquivTypes_(dtype_ptr(), descr.ptr())) { + value = ((PyVoidScalarObject_Proxy *) obj)->obval; + return true; + } + } + return false; + } +}; + +#define PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, Name) \ + ::pybind11::detail::field_descriptor { \ + Name, offsetof(T, Field), sizeof(decltype(std::declval().Field)), \ + alignof(decltype(std::declval().Field)), \ + ::pybind11::format_descriptor().Field)>::format(), \ + ::pybind11::detail::npy_format_descriptor().Field)>::dtype() \ + } + +// Extract name, offset and format descriptor for a struct field +#define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #Field) + +// The main idea of this macro is borrowed from https://github.com/swansontec/map-macro +// (C) William Swanson, Paul Fultz +#define PYBIND11_EVAL0(...) __VA_ARGS__ +#define PYBIND11_EVAL1(...) PYBIND11_EVAL0 (PYBIND11_EVAL0 (PYBIND11_EVAL0 (__VA_ARGS__))) +#define PYBIND11_EVAL2(...) PYBIND11_EVAL1 (PYBIND11_EVAL1 (PYBIND11_EVAL1 (__VA_ARGS__))) +#define PYBIND11_EVAL3(...) PYBIND11_EVAL2 (PYBIND11_EVAL2 (PYBIND11_EVAL2 (__VA_ARGS__))) +#define PYBIND11_EVAL4(...) PYBIND11_EVAL3 (PYBIND11_EVAL3 (PYBIND11_EVAL3 (__VA_ARGS__))) +#define PYBIND11_EVAL(...) PYBIND11_EVAL4 (PYBIND11_EVAL4 (PYBIND11_EVAL4 (__VA_ARGS__))) +#define PYBIND11_MAP_END(...) +#define PYBIND11_MAP_OUT +#define PYBIND11_MAP_COMMA , +#define PYBIND11_MAP_GET_END() 0, PYBIND11_MAP_END +#define PYBIND11_MAP_NEXT0(test, next, ...) next PYBIND11_MAP_OUT +#define PYBIND11_MAP_NEXT1(test, next) PYBIND11_MAP_NEXT0 (test, next, 0) +#define PYBIND11_MAP_NEXT(test, next) PYBIND11_MAP_NEXT1 (PYBIND11_MAP_GET_END test, next) +#ifdef _MSC_VER // MSVC is not as eager to expand macros, hence this workaround +#define PYBIND11_MAP_LIST_NEXT1(test, next) \ + PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)) +#else +#define PYBIND11_MAP_LIST_NEXT1(test, next) \ + PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0) +#endif +#define PYBIND11_MAP_LIST_NEXT(test, next) \ + PYBIND11_MAP_LIST_NEXT1 (PYBIND11_MAP_GET_END test, next) +#define PYBIND11_MAP_LIST0(f, t, x, peek, ...) \ + f(t, x) PYBIND11_MAP_LIST_NEXT (peek, PYBIND11_MAP_LIST1) (f, t, peek, __VA_ARGS__) +#define PYBIND11_MAP_LIST1(f, t, x, peek, ...) \ + f(t, x) PYBIND11_MAP_LIST_NEXT (peek, PYBIND11_MAP_LIST0) (f, t, peek, __VA_ARGS__) +// PYBIND11_MAP_LIST(f, t, a1, a2, ...) expands to f(t, a1), f(t, a2), ... +#define PYBIND11_MAP_LIST(f, t, ...) \ + PYBIND11_EVAL (PYBIND11_MAP_LIST1 (f, t, __VA_ARGS__, (), 0)) + +#define PYBIND11_NUMPY_DTYPE(Type, ...) \ + ::pybind11::detail::npy_format_descriptor::register_dtype \ + ({PYBIND11_MAP_LIST (PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)}) + +#ifdef _MSC_VER +#define PYBIND11_MAP2_LIST_NEXT1(test, next) \ + PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)) +#else +#define PYBIND11_MAP2_LIST_NEXT1(test, next) \ + PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0) +#endif +#define PYBIND11_MAP2_LIST_NEXT(test, next) \ + PYBIND11_MAP2_LIST_NEXT1 (PYBIND11_MAP_GET_END test, next) +#define PYBIND11_MAP2_LIST0(f, t, x1, x2, peek, ...) \ + f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT (peek, PYBIND11_MAP2_LIST1) (f, t, peek, __VA_ARGS__) +#define PYBIND11_MAP2_LIST1(f, t, x1, x2, peek, ...) \ + f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT (peek, PYBIND11_MAP2_LIST0) (f, t, peek, __VA_ARGS__) +// PYBIND11_MAP2_LIST(f, t, a1, a2, ...) expands to f(t, a1, a2), f(t, a3, a4), ... +#define PYBIND11_MAP2_LIST(f, t, ...) \ + PYBIND11_EVAL (PYBIND11_MAP2_LIST1 (f, t, __VA_ARGS__, (), 0)) + +#define PYBIND11_NUMPY_DTYPE_EX(Type, ...) \ + ::pybind11::detail::npy_format_descriptor::register_dtype \ + ({PYBIND11_MAP2_LIST (PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)}) + +template +using array_iterator = typename std::add_pointer::type; + +template +array_iterator array_begin(const buffer_info& buffer) { + return array_iterator(reinterpret_cast(buffer.ptr)); +} + +template +array_iterator array_end(const buffer_info& buffer) { + return array_iterator(reinterpret_cast(buffer.ptr) + buffer.size); +} + +class common_iterator { +public: + using container_type = std::vector; + using value_type = container_type::value_type; + using size_type = container_type::size_type; + + common_iterator() : p_ptr(0), m_strides() {} + + common_iterator(void* ptr, const container_type& strides, const std::vector& shape) + : p_ptr(reinterpret_cast(ptr)), m_strides(strides.size()) { + m_strides.back() = static_cast(strides.back()); + for (size_type i = m_strides.size() - 1; i != 0; --i) { + size_type j = i - 1; + value_type s = static_cast(shape[i]); + m_strides[j] = strides[j] + m_strides[i] - strides[i] * s; + } + } + + void increment(size_type dim) { + p_ptr += m_strides[dim]; + } + + void* data() const { + return p_ptr; + } + +private: + char* p_ptr; + container_type m_strides; +}; + +template class multi_array_iterator { +public: + using container_type = std::vector; + + multi_array_iterator(const std::array &buffers, + const std::vector &shape) + : m_shape(shape.size()), m_index(shape.size(), 0), + m_common_iterator() { + + // Manual copy to avoid conversion warning if using std::copy + for (size_t i = 0; i < shape.size(); ++i) + m_shape[i] = static_cast(shape[i]); + + container_type strides(shape.size()); + for (size_t i = 0; i < N; ++i) + init_common_iterator(buffers[i], shape, m_common_iterator[i], strides); + } + + multi_array_iterator& operator++() { + for (size_t j = m_index.size(); j != 0; --j) { + size_t i = j - 1; + if (++m_index[i] != m_shape[i]) { + increment_common_iterator(i); + break; + } else { + m_index[i] = 0; + } + } + return *this; + } + + template const T& data() const { + return *reinterpret_cast(m_common_iterator[K].data()); + } + +private: + + using common_iter = common_iterator; + + void init_common_iterator(const buffer_info &buffer, + const std::vector &shape, + common_iter &iterator, container_type &strides) { + auto buffer_shape_iter = buffer.shape.rbegin(); + auto buffer_strides_iter = buffer.strides.rbegin(); + auto shape_iter = shape.rbegin(); + auto strides_iter = strides.rbegin(); + + while (buffer_shape_iter != buffer.shape.rend()) { + if (*shape_iter == *buffer_shape_iter) + *strides_iter = static_cast(*buffer_strides_iter); + else + *strides_iter = 0; + + ++buffer_shape_iter; + ++buffer_strides_iter; + ++shape_iter; + ++strides_iter; + } + + std::fill(strides_iter, strides.rend(), 0); + iterator = common_iter(buffer.ptr, strides, shape); + } + + void increment_common_iterator(size_t dim) { + for (auto &iter : m_common_iterator) + iter.increment(dim); + } + + container_type m_shape; + container_type m_index; + std::array m_common_iterator; +}; + +template +bool broadcast(const std::array& buffers, size_t& ndim, std::vector& shape) { + ndim = std::accumulate(buffers.begin(), buffers.end(), size_t(0), [](size_t res, const buffer_info& buf) { + return std::max(res, buf.ndim); + }); + + shape = std::vector(ndim, 1); + bool trivial_broadcast = true; + for (size_t i = 0; i < N; ++i) { + auto res_iter = shape.rbegin(); + bool i_trivial_broadcast = (buffers[i].size == 1) || (buffers[i].ndim == ndim); + for (auto shape_iter = buffers[i].shape.rbegin(); + shape_iter != buffers[i].shape.rend(); ++shape_iter, ++res_iter) { + + if (*res_iter == 1) + *res_iter = *shape_iter; + else if ((*shape_iter != 1) && (*res_iter != *shape_iter)) + pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!"); + + i_trivial_broadcast = i_trivial_broadcast && (*res_iter == *shape_iter); + } + trivial_broadcast = trivial_broadcast && i_trivial_broadcast; + } + return trivial_broadcast; +} + +template +struct vectorize_helper { + typename std::remove_reference::type f; + + template + explicit vectorize_helper(T&&f) : f(std::forward(f)) { } + + object operator()(array_t... args) { + return run(args..., make_index_sequence()); + } + + template object run(array_t&... args, index_sequence index) { + /* Request buffers from all parameters */ + const size_t N = sizeof...(Args); + + std::array buffers {{ args.request()... }}; + + /* Determine dimensions parameters of output array */ + size_t ndim = 0; + std::vector shape(0); + bool trivial_broadcast = broadcast(buffers, ndim, shape); + + size_t size = 1; + std::vector strides(ndim); + if (ndim > 0) { + strides[ndim-1] = sizeof(Return); + for (size_t i = ndim - 1; i > 0; --i) { + strides[i - 1] = strides[i] * shape[i]; + size *= shape[i]; + } + size *= shape[0]; + } + + if (size == 1) + return cast(f(*((Args *) buffers[Index].ptr)...)); + + array_t result(shape, strides); + auto buf = result.request(); + auto output = (Return *) buf.ptr; + + if (trivial_broadcast) { + /* Call the function */ + for (size_t i = 0; i < size; ++i) { + output[i] = f((buffers[Index].size == 1 + ? *((Args *) buffers[Index].ptr) + : ((Args *) buffers[Index].ptr)[i])...); + } + } else { + apply_broadcast(buffers, buf, index); + } + + return result; + } + + template + void apply_broadcast(const std::array &buffers, + buffer_info &output, index_sequence) { + using input_iterator = multi_array_iterator; + using output_iterator = array_iterator; + + input_iterator input_iter(buffers, output.shape); + output_iterator output_end = array_end(output); + + for (output_iterator iter = array_begin(output); + iter != output_end; ++iter, ++input_iter) { + *iter = f((input_iter.template data())...); + } + } +}; + +template struct handle_type_name> { + static PYBIND11_DESCR name() { return _("numpy.ndarray[") + type_caster::name() + _("]"); } +}; + +NAMESPACE_END(detail) + +template +detail::vectorize_helper vectorize(const Func &f, Return (*) (Args ...)) { + return detail::vectorize_helper(f); +} + +template +detail::vectorize_helper vectorize(Return (*f) (Args ...)) { + return vectorize(f, f); +} + +template +auto vectorize(Func &&f) -> decltype( + vectorize(std::forward(f), (typename detail::remove_class::type::operator())>::type *) nullptr)) { + return vectorize(std::forward(f), (typename detail::remove_class::type::operator())>::type *) nullptr); +} + +NAMESPACE_END(pybind11) + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif diff --git a/resources/pybind11/include/pybind11/operators.h b/resources/pybind11/include/pybind11/operators.h new file mode 100755 index 0000000..2e78c01 --- /dev/null +++ b/resources/pybind11/include/pybind11/operators.h @@ -0,0 +1,154 @@ +/* + pybind11/operator.h: Metatemplates for operator overloading + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" + +#if defined(__clang__) && !defined(__INTEL_COMPILER) +# pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type())) +#endif + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + +/// Enumeration with all supported operator types +enum op_id : int { + op_add, op_sub, op_mul, op_div, op_mod, op_divmod, op_pow, op_lshift, + op_rshift, op_and, op_xor, op_or, op_neg, op_pos, op_abs, op_invert, + op_int, op_long, op_float, op_str, op_cmp, op_gt, op_ge, op_lt, op_le, + op_eq, op_ne, op_iadd, op_isub, op_imul, op_idiv, op_imod, op_ilshift, + op_irshift, op_iand, op_ixor, op_ior, op_complex, op_bool, op_nonzero, + op_repr, op_truediv +}; + +enum op_type : int { + op_l, /* base type on left */ + op_r, /* base type on right */ + op_u /* unary operator */ +}; + +struct self_t { }; +static const self_t self = self_t(); + +/// Type for an unused type slot +struct undefined_t { }; + +/// Don't warn about an unused variable +inline self_t __self() { return self; } + +/// base template of operator implementations +template struct op_impl { }; + +/// Operator implementation generator +template struct op_ { + template void execute(Class &cl, const Extra&... extra) const { + typedef typename Class::type Base; + typedef typename std::conditional::value, Base, L>::type L_type; + typedef typename std::conditional::value, Base, R>::type R_type; + typedef op_impl op; + cl.def(op::name(), &op::execute, is_operator(), extra...); + } + template void execute_cast(Class &cl, const Extra&... extra) const { + typedef typename Class::type Base; + typedef typename std::conditional::value, Base, L>::type L_type; + typedef typename std::conditional::value, Base, R>::type R_type; + typedef op_impl op; + cl.def(op::name(), &op::execute_cast, is_operator(), extra...); + } +}; + +#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \ +template struct op_impl { \ + static char const* name() { return "__" #id "__"; } \ + static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \ + static B execute_cast(const L &l, const R &r) { return B(expr); } \ +}; \ +template struct op_impl { \ + static char const* name() { return "__" #rid "__"; } \ + static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \ + static B execute_cast(const R &r, const L &l) { return B(expr); } \ +}; \ +inline op_ op(const self_t &, const self_t &) { \ + return op_(); \ +} \ +template op_ op(const self_t &, const T &) { \ + return op_(); \ +} \ +template op_ op(const T &, const self_t &) { \ + return op_(); \ +} + +#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \ +template struct op_impl { \ + static char const* name() { return "__" #id "__"; } \ + static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \ + static B execute_cast(L &l, const R &r) { return B(expr); } \ +}; \ +template op_ op(const self_t &, const T &) { \ + return op_(); \ +} + +#define PYBIND11_UNARY_OPERATOR(id, op, expr) \ +template struct op_impl { \ + static char const* name() { return "__" #id "__"; } \ + static auto execute(const L &l) -> decltype(expr) { return expr; } \ + static B execute_cast(const L &l) { return B(expr); } \ +}; \ +inline op_ op(const self_t &) { \ + return op_(); \ +} + +PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r) +PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r) +PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l * r) +#if PY_MAJOR_VERSION >= 3 +PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r) +#else +PYBIND11_BINARY_OPERATOR(div, rdiv, operator/, l / r) +#endif +PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r) +PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r) +PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r) +PYBIND11_BINARY_OPERATOR(and, rand, operator&, l & r) +PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r) +PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r) +PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r) +PYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r) +PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r) +PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r) +PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r) +PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r) +//PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r)) +PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r) +PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r) +PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r) +PYBIND11_INPLACE_OPERATOR(idiv, operator/=, l /= r) +PYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r) +PYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r) +PYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r) +PYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r) +PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r) +PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r) +PYBIND11_UNARY_OPERATOR(neg, operator-, -l) +PYBIND11_UNARY_OPERATOR(pos, operator+, +l) +PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l)) +PYBIND11_UNARY_OPERATOR(invert, operator~, (~l)) +PYBIND11_UNARY_OPERATOR(bool, operator!, !!l) +PYBIND11_UNARY_OPERATOR(int, int_, (int) l) +PYBIND11_UNARY_OPERATOR(float, float_, (double) l) + +#undef PYBIND11_BINARY_OPERATOR +#undef PYBIND11_INPLACE_OPERATOR +#undef PYBIND11_UNARY_OPERATOR +NAMESPACE_END(detail) + +using detail::self; + +NAMESPACE_END(pybind11) diff --git a/resources/pybind11/include/pybind11/options.h b/resources/pybind11/include/pybind11/options.h new file mode 100755 index 0000000..3105551 --- /dev/null +++ b/resources/pybind11/include/pybind11/options.h @@ -0,0 +1,65 @@ +/* + pybind11/options.h: global settings that are configurable at runtime. + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "common.h" + +NAMESPACE_BEGIN(pybind11) + +class options { +public: + + // Default RAII constructor, which leaves settings as they currently are. + options() : previous_state(global_state()) {} + + // Class is non-copyable. + options(const options&) = delete; + options& operator=(const options&) = delete; + + // Destructor, which restores settings that were in effect before. + ~options() { + global_state() = previous_state; + } + + // Setter methods (affect the global state): + + options& disable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = false; return *this; } + + options& enable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = true; return *this; } + + options& disable_function_signatures() & { global_state().show_function_signatures = false; return *this; } + + options& enable_function_signatures() & { global_state().show_function_signatures = true; return *this; } + + // Getter methods (return the global state): + + static bool show_user_defined_docstrings() { return global_state().show_user_defined_docstrings; } + + static bool show_function_signatures() { return global_state().show_function_signatures; } + + // This type is not meant to be allocated on the heap. + void* operator new(size_t) = delete; + +private: + + struct state { + bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings. + bool show_function_signatures = true; //< Include auto-generated function signatures in docstrings. + }; + + static state &global_state() { + static state instance; + return instance; + } + + state previous_state; +}; + +NAMESPACE_END(pybind11) diff --git a/resources/pybind11/include/pybind11/pybind11.h b/resources/pybind11/include/pybind11/pybind11.h new file mode 100755 index 0000000..1db9efb --- /dev/null +++ b/resources/pybind11/include/pybind11/pybind11.h @@ -0,0 +1,1735 @@ +/* + pybind11/pybind11.h: Main header file of the C++11 python + binding generator library + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4100) // warning C4100: Unreferenced formal parameter +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +# pragma warning(disable: 4512) // warning C4512: Assignment operator was implicitly defined as deleted +# pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning) +# pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name +# pragma warning(disable: 4702) // warning C4702: unreachable code +# pragma warning(disable: 4522) // warning C4522: multiple assignment operators specified +#elif defined(__INTEL_COMPILER) +# pragma warning(push) +# pragma warning(disable: 186) // pointless comparison of unsigned integer with zero +# pragma warning(disable: 1334) // the "template" keyword used for syntactic disambiguation may only be used within a template +# pragma warning(disable: 2196) // warning #2196: routine is both "inline" and "noinline" +#elif defined(__GNUG__) && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-but-set-parameter" +# pragma GCC diagnostic ignored "-Wunused-but-set-variable" +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +# pragma GCC diagnostic ignored "-Wstrict-aliasing" +# pragma GCC diagnostic ignored "-Wattributes" +#endif + +#include "attr.h" +#include "options.h" + +NAMESPACE_BEGIN(pybind11) + +/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object +class cpp_function : public function { +public: + cpp_function() { } + + /// Construct a cpp_function from a vanilla function pointer + template + cpp_function(Return (*f)(Args...), const Extra&... extra) { + initialize(f, f, extra...); + } + + /// Construct a cpp_function from a lambda function (possibly with internal state) + template cpp_function(Func &&f, const Extra&... extra) { + initialize(std::forward(f), + (typename detail::remove_class::type::operator())>::type *) nullptr, extra...); + } + + /// Construct a cpp_function from a class method (non-const) + template + cpp_function(Return (Class::*f)(Arg...), const Extra&... extra) { + initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); }, + (Return (*) (Class *, Arg...)) nullptr, extra...); + } + + /// Construct a cpp_function from a class method (const) + template + cpp_function(Return (Class::*f)(Arg...) const, const Extra&... extra) { + initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); }, + (Return (*)(const Class *, Arg ...)) nullptr, extra...); + } + + /// Return the function name + object name() const { return attr("__name__"); } + +protected: + /// Space optimization: don't inline this frequently instantiated fragment + PYBIND11_NOINLINE detail::function_record *make_function_record() { + return new detail::function_record(); + } + + /// Special internal constructor for functors, lambda functions, etc. + template + void initialize(Func &&f, Return (*)(Args...), const Extra&... extra) { + static_assert(detail::expected_num_args(sizeof...(Args)), + "The number of named arguments does not match the function signature"); + + struct capture { typename std::remove_reference::type f; }; + + /* Store the function including any extra state it might have (e.g. a lambda capture object) */ + auto rec = make_function_record(); + + /* Store the capture object directly in the function record if there is enough space */ + if (sizeof(capture) <= sizeof(rec->data)) { + /* Without these pragmas, GCC warns that there might not be + enough space to use the placement new operator. However, the + 'if' statement above ensures that this is the case. */ +#if defined(__GNUG__) && !defined(__clang__) && __GNUC__ >= 6 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wplacement-new" +#endif + new ((capture *) &rec->data) capture { std::forward(f) }; +#if defined(__GNUG__) && !defined(__clang__) && __GNUC__ >= 6 +# pragma GCC diagnostic pop +#endif + if (!std::is_trivially_destructible::value) + rec->free_data = [](detail::function_record *r) { ((capture *) &r->data)->~capture(); }; + } else { + rec->data[0] = new capture { std::forward(f) }; + rec->free_data = [](detail::function_record *r) { delete ((capture *) r->data[0]); }; + } + + /* Type casters for the function arguments and return value */ + using cast_in = detail::argument_loader; + using cast_out = detail::make_caster< + detail::conditional_t::value, detail::void_type, Return> + >; + + /* Dispatch code which converts function arguments and performs the actual function call */ + rec->impl = [](detail::function_record *rec, handle args, handle kwargs, handle parent) -> handle { + cast_in args_converter; + + /* Try to cast the function arguments into the C++ domain */ + if (!args_converter.load_args(args, kwargs, true)) + return PYBIND11_TRY_NEXT_OVERLOAD; + + /* Invoke call policy pre-call hook */ + detail::process_attributes::precall(args); + + /* Get a pointer to the capture object */ + capture *cap = (capture *) (sizeof(capture) <= sizeof(rec->data) + ? &rec->data : rec->data[0]); + + /* Override policy for rvalues -- always move */ + constexpr auto is_rvalue = !std::is_pointer::value + && !std::is_lvalue_reference::value; + const auto policy = is_rvalue ? return_value_policy::move : rec->policy; + + /* Perform the function call */ + handle result = cast_out::cast(args_converter.template call(cap->f), + policy, parent); + + /* Invoke call policy post-call hook */ + detail::process_attributes::postcall(args, result); + + return result; + }; + + /* Process any user-provided function attributes */ + detail::process_attributes::init(extra..., rec); + + /* Generate a readable signature describing the function's arguments and return value types */ + using detail::descr; using detail::_; + PYBIND11_DESCR signature = _("(") + cast_in::arg_names() + _(") -> ") + cast_out::name(); + + /* Register the function with Python from generic (non-templated) code */ + initialize_generic(rec, signature.text(), signature.types(), sizeof...(Args)); + + if (cast_in::has_args) rec->has_args = true; + if (cast_in::has_kwargs) rec->has_kwargs = true; + + /* Stash some additional information used by an important optimization in 'functional.h' */ + using FunctionType = Return (*)(Args...); + constexpr bool is_function_ptr = + std::is_convertible::value && + sizeof(capture) == sizeof(void *); + if (is_function_ptr) { + rec->is_stateless = true; + rec->data[1] = (void *) &typeid(FunctionType); + } + } + + /// Register a function call with Python (generic non-templated code goes here) + void initialize_generic(detail::function_record *rec, const char *text, + const std::type_info *const *types, size_t args) { + + /* Create copies of all referenced C-style strings */ + rec->name = strdup(rec->name ? rec->name : ""); + if (rec->doc) rec->doc = strdup(rec->doc); + for (auto &a: rec->args) { + if (a.name) + a.name = strdup(a.name); + if (a.descr) + a.descr = strdup(a.descr); + else if (a.value) + a.descr = strdup(a.value.attr("__repr__")().cast().c_str()); + } + + /* Generate a proper function signature */ + std::string signature; + size_t type_depth = 0, char_index = 0, type_index = 0, arg_index = 0; + while (true) { + char c = text[char_index++]; + if (c == '\0') + break; + + if (c == '{') { + // Write arg name for everything except *args, **kwargs and return type. + if (type_depth == 0 && text[char_index] != '*' && arg_index < args) { + if (!rec->args.empty()) { + signature += rec->args[arg_index].name; + } else if (arg_index == 0 && rec->is_method) { + signature += "self"; + } else { + signature += "arg" + std::to_string(arg_index - (rec->is_method ? 1 : 0)); + } + signature += ": "; + } + ++type_depth; + } else if (c == '}') { + --type_depth; + if (type_depth == 0) { + if (arg_index < rec->args.size() && rec->args[arg_index].descr) { + signature += "="; + signature += rec->args[arg_index].descr; + } + arg_index++; + } + } else if (c == '%') { + const std::type_info *t = types[type_index++]; + if (!t) + pybind11_fail("Internal error while parsing type signature (1)"); + if (auto tinfo = detail::get_type_info(*t)) { + signature += tinfo->type->tp_name; + } else { + std::string tname(t->name()); + detail::clean_type_id(tname); + signature += tname; + } + } else { + signature += c; + } + } + if (type_depth != 0 || types[type_index] != nullptr) + pybind11_fail("Internal error while parsing type signature (2)"); + + #if !defined(PYBIND11_CPP14) + delete[] types; + delete[] text; + #endif + +#if PY_MAJOR_VERSION < 3 + if (strcmp(rec->name, "__next__") == 0) { + std::free(rec->name); + rec->name = strdup("next"); + } else if (strcmp(rec->name, "__bool__") == 0) { + std::free(rec->name); + rec->name = strdup("__nonzero__"); + } +#endif + rec->signature = strdup(signature.c_str()); + rec->args.shrink_to_fit(); + rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__"); + rec->nargs = (uint16_t) args; + +#if PY_MAJOR_VERSION < 3 + if (rec->sibling && PyMethod_Check(rec->sibling.ptr())) + rec->sibling = PyMethod_GET_FUNCTION(rec->sibling.ptr()); +#endif + + detail::function_record *chain = nullptr, *chain_start = rec; + if (rec->sibling) { + if (PyCFunction_Check(rec->sibling.ptr())) { + auto rec_capsule = reinterpret_borrow(PyCFunction_GetSelf(rec->sibling.ptr())); + chain = (detail::function_record *) rec_capsule; + /* Never append a method to an overload chain of a parent class; + instead, hide the parent's overloads in this case */ + if (chain->scope != rec->scope) + chain = nullptr; + } + // Don't trigger for things like the default __init__, which are wrapper_descriptors that we are intentionally replacing + else if (!rec->sibling.is_none() && rec->name[0] != '_') + pybind11_fail("Cannot overload existing non-function object \"" + std::string(rec->name) + + "\" with a function of the same name"); + } + + if (!chain) { + /* No existing overload was found, create a new function object */ + rec->def = new PyMethodDef(); + memset(rec->def, 0, sizeof(PyMethodDef)); + rec->def->ml_name = rec->name; + rec->def->ml_meth = reinterpret_cast(*dispatcher); + rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS; + + capsule rec_capsule(rec, [](PyObject *o) { + destruct((detail::function_record *) PyCapsule_GetPointer(o, nullptr)); + }); + + object scope_module; + if (rec->scope) { + if (hasattr(rec->scope, "__module__")) { + scope_module = rec->scope.attr("__module__"); + } else if (hasattr(rec->scope, "__name__")) { + scope_module = rec->scope.attr("__name__"); + } + } + + m_ptr = PyCFunction_NewEx(rec->def, rec_capsule.ptr(), scope_module.ptr()); + if (!m_ptr) + pybind11_fail("cpp_function::cpp_function(): Could not allocate function object"); + } else { + /* Append at the end of the overload chain */ + m_ptr = rec->sibling.ptr(); + inc_ref(); + chain_start = chain; + while (chain->next) + chain = chain->next; + chain->next = rec; + } + + std::string signatures; + int index = 0; + /* Create a nice pydoc rec including all signatures and + docstrings of the functions in the overload chain */ + if (chain && options::show_function_signatures()) { + // First a generic signature + signatures += rec->name; + signatures += "(*args, **kwargs)\n"; + signatures += "Overloaded function.\n\n"; + } + // Then specific overload signatures + for (auto it = chain_start; it != nullptr; it = it->next) { + if (options::show_function_signatures()) { + if (chain) + signatures += std::to_string(++index) + ". "; + signatures += rec->name; + signatures += it->signature; + signatures += "\n"; + } + if (it->doc && strlen(it->doc) > 0 && options::show_user_defined_docstrings()) { + if (options::show_function_signatures()) signatures += "\n"; + signatures += it->doc; + if (options::show_function_signatures()) signatures += "\n"; + } + if (it->next) + signatures += "\n"; + } + + /* Install docstring */ + PyCFunctionObject *func = (PyCFunctionObject *) m_ptr; + if (func->m_ml->ml_doc) + std::free((char *) func->m_ml->ml_doc); + func->m_ml->ml_doc = strdup(signatures.c_str()); + + if (rec->is_method) { + m_ptr = PYBIND11_INSTANCE_METHOD_NEW(m_ptr, rec->scope.ptr()); + if (!m_ptr) + pybind11_fail("cpp_function::cpp_function(): Could not allocate instance method object"); + Py_DECREF(func); + } + } + + /// When a cpp_function is GCed, release any memory allocated by pybind11 + static void destruct(detail::function_record *rec) { + while (rec) { + detail::function_record *next = rec->next; + if (rec->free_data) + rec->free_data(rec); + std::free((char *) rec->name); + std::free((char *) rec->doc); + std::free((char *) rec->signature); + for (auto &arg: rec->args) { + std::free((char *) arg.name); + std::free((char *) arg.descr); + arg.value.dec_ref(); + } + if (rec->def) { + std::free((char *) rec->def->ml_doc); + delete rec->def; + } + delete rec; + rec = next; + } + } + + /// Main dispatch logic for calls to functions bound using pybind11 + static PyObject *dispatcher(PyObject *self, PyObject *args, PyObject *kwargs) { + /* Iterator over the list of potentially admissible overloads */ + detail::function_record *overloads = (detail::function_record *) PyCapsule_GetPointer(self, nullptr), + *it = overloads; + + /* Need to know how many arguments + keyword arguments there are to pick the right overload */ + size_t nargs = (size_t) PyTuple_GET_SIZE(args), + nkwargs = kwargs ? (size_t) PyDict_Size(kwargs) : 0; + + handle parent = nargs > 0 ? PyTuple_GET_ITEM(args, 0) : nullptr, + result = PYBIND11_TRY_NEXT_OVERLOAD; + try { + for (; it != nullptr; it = it->next) { + auto args_ = reinterpret_borrow(args); + size_t kwargs_consumed = 0; + + /* For each overload: + 1. If the required list of arguments is longer than the + actually provided amount, create a copy of the argument + list and fill in any available keyword/default arguments. + 2. Ensure that all keyword arguments were "consumed" + 3. Call the function call dispatcher (function_record::impl) + */ + size_t nargs_ = nargs; + if (nargs < it->args.size()) { + nargs_ = it->args.size(); + args_ = tuple(nargs_); + for (size_t i = 0; i < nargs; ++i) { + handle item = PyTuple_GET_ITEM(args, i); + PyTuple_SET_ITEM(args_.ptr(), i, item.inc_ref().ptr()); + } + + int arg_ctr = 0; + for (auto const &it2 : it->args) { + int index = arg_ctr++; + if (PyTuple_GET_ITEM(args_.ptr(), index)) + continue; + + handle value; + if (kwargs) + value = PyDict_GetItemString(kwargs, it2.name); + + if (value) + kwargs_consumed++; + else if (it2.value) + value = it2.value; + + if (value) { + PyTuple_SET_ITEM(args_.ptr(), index, value.inc_ref().ptr()); + } else { + kwargs_consumed = (size_t) -1; /* definite failure */ + break; + } + } + } + + try { + if ((kwargs_consumed == nkwargs || it->has_kwargs) && + (nargs_ == it->nargs || it->has_args)) + result = it->impl(it, args_, kwargs, parent); + } catch (reference_cast_error &) { + result = PYBIND11_TRY_NEXT_OVERLOAD; + } + + if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) + break; + } + } catch (error_already_set &e) { + e.restore(); + return nullptr; + } catch (...) { + /* When an exception is caught, give each registered exception + translator a chance to translate it to a Python exception + in reverse order of registration. + + A translator may choose to do one of the following: + + - catch the exception and call PyErr_SetString or PyErr_SetObject + to set a standard (or custom) Python exception, or + - do nothing and let the exception fall through to the next translator, or + - delegate translation to the next translator by throwing a new type of exception. */ + + auto last_exception = std::current_exception(); + auto ®istered_exception_translators = pybind11::detail::get_internals().registered_exception_translators; + for (auto& translator : registered_exception_translators) { + try { + translator(last_exception); + } catch (...) { + last_exception = std::current_exception(); + continue; + } + return nullptr; + } + PyErr_SetString(PyExc_SystemError, "Exception escaped from default exception translator!"); + return nullptr; + } + + if (result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) { + if (overloads->is_operator) + return handle(Py_NotImplemented).inc_ref().ptr(); + + std::string msg = std::string(overloads->name) + "(): incompatible " + + std::string(overloads->is_constructor ? "constructor" : "function") + + " arguments. The following argument types are supported:\n"; + + int ctr = 0; + for (detail::function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) { + msg += " "+ std::to_string(++ctr) + ". "; + + bool wrote_sig = false; + if (overloads->is_constructor) { + // For a constructor, rewrite `(self: Object, arg0, ...) -> NoneType` as `Object(arg0, ...)` + std::string sig = it2->signature; + size_t start = sig.find('(') + 7; // skip "(self: " + if (start < sig.size()) { + // End at the , for the next argument + size_t end = sig.find(", "), next = end + 2; + size_t ret = sig.rfind(" -> "); + // Or the ), if there is no comma: + if (end >= sig.size()) next = end = sig.find(')'); + if (start < end && next < sig.size()) { + msg.append(sig, start, end - start); + msg += '('; + msg.append(sig, next, ret - next); + wrote_sig = true; + } + } + } + if (!wrote_sig) msg += it2->signature; + + msg += "\n"; + } + msg += "\nInvoked with: "; + auto args_ = reinterpret_borrow(args); + for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) { + msg += pybind11::repr(args_[ti]); + if ((ti + 1) != args_.size() ) + msg += ", "; + } + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return nullptr; + } else if (!result) { + std::string msg = "Unable to convert function return value to a " + "Python type! The signature was\n\t"; + msg += it->signature; + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return nullptr; + } else { + if (overloads->is_constructor) { + /* When a constructor ran successfully, the corresponding + holder type (e.g. std::unique_ptr) must still be initialized. */ + PyObject *inst = PyTuple_GET_ITEM(args, 0); + auto tinfo = detail::get_type_info(Py_TYPE(inst)); + tinfo->init_holder(inst, nullptr); + } + return result.ptr(); + } + } +}; + +/// Wrapper for Python extension modules +class module : public object { +public: + PYBIND11_OBJECT_DEFAULT(module, object, PyModule_Check) + + explicit module(const char *name, const char *doc = nullptr) { + if (!options::show_user_defined_docstrings()) doc = nullptr; +#if PY_MAJOR_VERSION >= 3 + PyModuleDef *def = new PyModuleDef(); + memset(def, 0, sizeof(PyModuleDef)); + def->m_name = name; + def->m_doc = doc; + 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) + pybind11_fail("Internal error in module::module()"); + inc_ref(); + } + + template + module &def(const char *name_, Func &&f, const Extra& ... extra) { + cpp_function func(std::forward(f), name(name_), scope(*this), + sibling(getattr(*this, name_, none())), extra...); + // NB: allow overwriting here because cpp_function sets up a chain with the intention of + // overwriting (and has already checked internally that it isn't overwriting non-functions). + add_object(name_, func, true /* overwrite */); + return *this; + } + + module def_submodule(const char *name, const char *doc = nullptr) { + std::string full_name = std::string(PyModule_GetName(m_ptr)) + + std::string(".") + std::string(name); + auto result = reinterpret_borrow(PyImport_AddModule(full_name.c_str())); + if (doc && options::show_user_defined_docstrings()) + result.attr("__doc__") = pybind11::str(doc); + attr(name) = result; + return result; + } + + static module import(const char *name) { + PyObject *obj = PyImport_ImportModule(name); + if (!obj) + throw error_already_set(); + return reinterpret_steal(obj); + } + + // Adds an object to the module using the given name. Throws if an object with the given name + // already exists. + // + // overwrite should almost always be false: attempting to overwrite objects that pybind11 has + // established will, in most cases, break things. + PYBIND11_NOINLINE void add_object(const char *name, object &obj, bool overwrite = false) { + if (!overwrite && hasattr(*this, name)) + pybind11_fail("Error during initialization: multiple incompatible definitions with name \"" + + std::string(name) + "\""); + + obj.inc_ref(); // PyModule_AddObject() steals a reference + PyModule_AddObject(ptr(), name, obj.ptr()); + } +}; + +NAMESPACE_BEGIN(detail) +extern "C" inline PyObject *get_dict(PyObject *op, void *) { + PyObject *&dict = *_PyObject_GetDictPtr(op); + if (!dict) { + dict = PyDict_New(); + } + Py_XINCREF(dict); + return dict; +} + +extern "C" inline int set_dict(PyObject *op, PyObject *new_dict, void *) { + if (!PyDict_Check(new_dict)) { + PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'", + Py_TYPE(new_dict)->tp_name); + return -1; + } + PyObject *&dict = *_PyObject_GetDictPtr(op); + Py_INCREF(new_dict); + Py_CLEAR(dict); + dict = new_dict; + return 0; +} + +static PyGetSetDef generic_getset[] = { + {const_cast("__dict__"), get_dict, set_dict, nullptr, nullptr}, + {nullptr, nullptr, nullptr, nullptr, nullptr} +}; + +/// Generic support for creating new Python heap types +class generic_type : public object { + template friend class class_; +public: + PYBIND11_OBJECT_DEFAULT(generic_type, object, PyType_Check) +protected: + void initialize(type_record *rec) { + auto &internals = get_internals(); + auto tindex = std::type_index(*(rec->type)); + + if (get_type_info(*(rec->type))) + pybind11_fail("generic_type: type \"" + std::string(rec->name) + + "\" is already registered!"); + + auto name = reinterpret_steal(PYBIND11_FROM_STRING(rec->name)); + object scope_module; + if (rec->scope) { + if (hasattr(rec->scope, rec->name)) + pybind11_fail("generic_type: cannot initialize type \"" + std::string(rec->name) + + "\": an object with that name is already defined"); + + if (hasattr(rec->scope, "__module__")) { + scope_module = rec->scope.attr("__module__"); + } else if (hasattr(rec->scope, "__name__")) { + scope_module = rec->scope.attr("__name__"); + } + } + +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + /* Qualified names for Python >= 3.3 */ + object scope_qualname; + if (rec->scope && hasattr(rec->scope, "__qualname__")) + scope_qualname = rec->scope.attr("__qualname__"); + object ht_qualname; + if (scope_qualname) { + ht_qualname = reinterpret_steal(PyUnicode_FromFormat( + "%U.%U", scope_qualname.ptr(), name.ptr())); + } else { + ht_qualname = name; + } +#endif + + size_t num_bases = rec->bases.size(); + auto bases = tuple(rec->bases); + + std::string full_name = (scope_module ? ((std::string) pybind11::str(scope_module) + "." + rec->name) + : std::string(rec->name)); + + char *tp_doc = nullptr; + if (rec->doc && options::show_user_defined_docstrings()) { + /* Allocate memory for docstring (using PyObject_MALLOC, since + Python will free this later on) */ + size_t size = strlen(rec->doc) + 1; + tp_doc = (char *) PyObject_MALLOC(size); + memcpy((void *) tp_doc, rec->doc, size); + } + + /* Danger zone: from now (and until PyType_Ready), make sure to + issue no Python C API calls which could potentially invoke the + garbage collector (the GC will call type_traverse(), which will in + turn find the newly constructed type in an invalid state) */ + + auto type_holder = reinterpret_steal(PyType_Type.tp_alloc(&PyType_Type, 0)); + auto type = (PyHeapTypeObject*) type_holder.ptr(); + + if (!type_holder || !name) + pybind11_fail(std::string(rec->name) + ": Unable to create type object!"); + + /* Register supplemental type information in C++ dict */ + detail::type_info *tinfo = new detail::type_info(); + tinfo->type = (PyTypeObject *) type; + tinfo->type_size = rec->type_size; + tinfo->init_holder = rec->init_holder; + tinfo->direct_conversions = &internals.direct_conversions[tindex]; + internals.registered_types_cpp[tindex] = tinfo; + internals.registered_types_py[type] = tinfo; + + /* Basic type attributes */ + type->ht_type.tp_name = strdup(full_name.c_str()); + type->ht_type.tp_basicsize = (ssize_t) rec->instance_size; + + if (num_bases > 0) { + type->ht_type.tp_base = (PyTypeObject *) ((object) bases[0]).inc_ref().ptr(); + type->ht_type.tp_bases = bases.release().ptr(); + rec->multiple_inheritance |= num_bases > 1; + } + + type->ht_name = name.release().ptr(); + +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + type->ht_qualname = ht_qualname.release().ptr(); +#endif + + /* Supported protocols */ + 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; + + /* Supported elementary operations */ + type->ht_type.tp_init = (initproc) init; + type->ht_type.tp_new = (newfunc) new_instance; + type->ht_type.tp_dealloc = rec->dealloc; + + /* Support weak references (needed for the keep_alive feature) */ + type->ht_type.tp_weaklistoffset = offsetof(instance_essentials, weakrefs); + + /* Flags */ + type->ht_type.tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; +#if PY_MAJOR_VERSION < 3 + type->ht_type.tp_flags |= Py_TPFLAGS_CHECKTYPES; +#endif + type->ht_type.tp_flags &= ~Py_TPFLAGS_HAVE_GC; + + /* Support dynamic attributes */ + if (rec->dynamic_attr) { + type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_GC; + type->ht_type.tp_dictoffset = type->ht_type.tp_basicsize; // place the dict at the end + type->ht_type.tp_basicsize += sizeof(PyObject *); // and allocate enough space for it + type->ht_type.tp_getset = generic_getset; + type->ht_type.tp_traverse = traverse; + type->ht_type.tp_clear = clear; + } + + type->ht_type.tp_doc = tp_doc; + + if (PyType_Ready(&type->ht_type) < 0) + pybind11_fail(std::string(rec->name) + ": PyType_Ready failed (" + + detail::error_string() + ")!"); + + m_ptr = type_holder.ptr(); + + if (scope_module) // Needed by pydoc + attr("__module__") = scope_module; + + /* Register type with the parent scope */ + if (rec->scope) + rec->scope.attr(handle(type->ht_name)) = *this; + + if (rec->multiple_inheritance) + mark_parents_nonsimple(&type->ht_type); + + type_holder.release(); + } + + /// Helper function which tags all parents of a type using mult. inheritance + void mark_parents_nonsimple(PyTypeObject *value) { + auto t = reinterpret_borrow(value->tp_bases); + for (handle h : t) { + auto tinfo2 = get_type_info((PyTypeObject *) h.ptr()); + if (tinfo2) + tinfo2->simple_type = false; + mark_parents_nonsimple((PyTypeObject *) h.ptr()); + } + } + + /// Allocate a metaclass on demand (for static properties) + handle metaclass() { + auto &ht_type = ((PyHeapTypeObject *) m_ptr)->ht_type; + auto &ob_type = PYBIND11_OB_TYPE(ht_type); + + if (ob_type == &PyType_Type) { + std::string name_ = std::string(ht_type.tp_name) + "__Meta"; +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + auto ht_qualname = reinterpret_steal(PyUnicode_FromFormat("%U__Meta", attr("__qualname__").ptr())); +#endif + auto name = reinterpret_steal(PYBIND11_FROM_STRING(name_.c_str())); + auto type_holder = reinterpret_steal(PyType_Type.tp_alloc(&PyType_Type, 0)); + if (!type_holder || !name) + pybind11_fail("generic_type::metaclass(): unable to create type object!"); + + auto type = (PyHeapTypeObject*) type_holder.ptr(); + type->ht_name = name.release().ptr(); + +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + /* Qualified names for Python >= 3.3 */ + type->ht_qualname = ht_qualname.release().ptr(); +#endif + type->ht_type.tp_name = strdup(name_.c_str()); + type->ht_type.tp_base = ob_type; + type->ht_type.tp_flags |= (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE) & + ~Py_TPFLAGS_HAVE_GC; + + if (PyType_Ready(&type->ht_type) < 0) + pybind11_fail("generic_type::metaclass(): PyType_Ready failed!"); + + ob_type = (PyTypeObject *) type_holder.release().ptr(); + } + return handle((PyObject *) ob_type); + } + + static int init(void *self, PyObject *, PyObject *) { + std::string msg = std::string(Py_TYPE(self)->tp_name) + ": No constructor defined!"; + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return -1; + } + + static PyObject *new_instance(PyTypeObject *type, PyObject *, PyObject *) { + instance *self = (instance *) PyType_GenericAlloc((PyTypeObject *) type, 0); + auto tinfo = detail::get_type_info(type); + self->value = ::operator new(tinfo->type_size); + self->owned = true; + self->holder_constructed = false; + detail::get_internals().registered_instances.emplace(self->value, (PyObject *) self); + return (PyObject *) self; + } + + static void dealloc(instance *self) { + if (self->value) { + auto instance_type = Py_TYPE(self); + auto ®istered_instances = detail::get_internals().registered_instances; + auto range = registered_instances.equal_range(self->value); + bool found = false; + for (auto it = range.first; it != range.second; ++it) { + if (instance_type == Py_TYPE(it->second)) { + registered_instances.erase(it); + found = true; + break; + } + } + if (!found) + pybind11_fail("generic_type::dealloc(): Tried to deallocate unregistered instance!"); + + if (self->weakrefs) + PyObject_ClearWeakRefs((PyObject *) self); + + PyObject **dict_ptr = _PyObject_GetDictPtr((PyObject *) self); + if (dict_ptr) { + Py_CLEAR(*dict_ptr); + } + } + Py_TYPE(self)->tp_free((PyObject*) self); + } + + static int traverse(PyObject *op, visitproc visit, void *arg) { + PyObject *&dict = *_PyObject_GetDictPtr(op); + Py_VISIT(dict); + return 0; + } + + static int clear(PyObject *op) { + PyObject *&dict = *_PyObject_GetDictPtr(op); + Py_CLEAR(dict); + return 0; + } + + void install_buffer_funcs( + buffer_info *(*get_buffer)(PyObject *, void *), + 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 tinfo = detail::get_type_info(&type->ht_type); + tinfo->get_buffer = get_buffer; + tinfo->get_buffer_data = get_buffer_data; + } + + static int getbuffer(PyObject *obj, Py_buffer *view, int flags) { + auto tinfo = detail::get_type_info(Py_TYPE(obj)); + if (view == nullptr || obj == nullptr || !tinfo || !tinfo->get_buffer) { + PyErr_SetString(PyExc_BufferError, "generic_type::getbuffer(): Internal error"); + return -1; + } + memset(view, 0, sizeof(Py_buffer)); + buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data); + view->obj = obj; + view->ndim = 1; + view->internal = info; + view->buf = info->ptr; + view->itemsize = (ssize_t) info->itemsize; + view->len = view->itemsize; + for (auto s : info->shape) + view->len *= s; + if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) + view->format = const_cast(info->format.c_str()); + if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) { + view->ndim = (int) info->ndim; + view->strides = (ssize_t *) &info->strides[0]; + view->shape = (ssize_t *) &info->shape[0]; + } + Py_INCREF(view->obj); + return 0; + } + + static void releasebuffer(PyObject *, Py_buffer *view) { delete (buffer_info *) view->internal; } +}; + +NAMESPACE_END(detail) + +template +class class_ : public detail::generic_type { + template using is_holder = detail::is_holder_type; + template using is_subtype = detail::bool_constant::value && !std::is_same::value>; + template using is_base = detail::bool_constant::value && !std::is_same::value>; + template using is_valid_class_option = + detail::bool_constant< + is_holder::value || + is_subtype::value || + is_base::value + >; + +public: + using type = type_; + using type_alias = detail::first_of_t; + constexpr static bool has_alias = !std::is_void::value; + using holder_type = detail::first_of_t, options...>; + using instance_type = detail::instance; + + static_assert(detail::all_of_t::value, + "Unknown/invalid class_ template parameters provided"); + + PYBIND11_OBJECT(class_, generic_type, PyType_Check) + + template + class_(handle scope, const char *name, const Extra &... extra) { + detail::type_record record; + record.scope = scope; + record.name = name; + record.type = &typeid(type); + record.type_size = sizeof(detail::conditional_t); + record.instance_size = sizeof(instance_type); + record.init_holder = init_holder; + record.dealloc = dealloc; + + /* Register base classes specified via template arguments to class_, if any */ + bool unused[] = { (add_base(record), false)..., false }; + (void) unused; + + /* Process optional arguments, if any */ + detail::process_attributes::init(extra..., &record); + + detail::generic_type::initialize(&record); + + if (has_alias) { + auto &instances = pybind11::detail::get_internals().registered_types_cpp; + instances[std::type_index(typeid(type_alias))] = instances[std::type_index(typeid(type))]; + } + } + + template ::value, int> = 0> + static void add_base(detail::type_record &rec) { + rec.add_base(&typeid(Base), [](void *src) -> void * { + return static_cast(reinterpret_cast(src)); + }); + } + + template ::value, int> = 0> + static void add_base(detail::type_record &) { } + + template + class_ &def(const char *name_, Func&& f, const Extra&... extra) { + cpp_function cf(std::forward(f), name(name_), is_method(*this), + sibling(getattr(*this, name_, none())), extra...); + attr(cf.name()) = cf; + return *this; + } + + template class_ & + def_static(const char *name_, Func f, const Extra&... extra) { + cpp_function cf(std::forward(f), name(name_), scope(*this), + sibling(getattr(*this, name_, none())), extra...); + attr(cf.name()) = cf; + return *this; + } + + template + class_ &def(const detail::op_ &op, const Extra&... extra) { + op.execute(*this, extra...); + return *this; + } + + template + class_ & def_cast(const detail::op_ &op, const Extra&... extra) { + op.execute_cast(*this, extra...); + return *this; + } + + template + class_ &def(const detail::init &init, const Extra&... extra) { + init.execute(*this, extra...); + return *this; + } + + template + class_ &def(const detail::init_alias &init, const Extra&... extra) { + init.execute(*this, extra...); + return *this; + } + + template class_& def_buffer(Func &&func) { + struct capture { Func func; }; + capture *ptr = new capture { std::forward(func) }; + install_buffer_funcs([](PyObject *obj, void *ptr) -> buffer_info* { + detail::type_caster caster; + if (!caster.load(obj, false)) + return nullptr; + return new buffer_info(((capture *) ptr)->func(caster)); + }, ptr); + return *this; + } + + template + class_ &def_readwrite(const char *name, D C::*pm, const Extra&... extra) { + cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; }, is_method(*this)), + fset([pm](C &c, const D &value) { c.*pm = value; }, is_method(*this)); + def_property(name, fget, fset, return_value_policy::reference_internal, extra...); + return *this; + } + + template + class_ &def_readonly(const char *name, const D C::*pm, const Extra& ...extra) { + cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; }, is_method(*this)); + def_property_readonly(name, fget, return_value_policy::reference_internal, extra...); + return *this; + } + + template + class_ &def_readwrite_static(const char *name, D *pm, const Extra& ...extra) { + cpp_function fget([pm](object) -> const D &{ return *pm; }, scope(*this)), + fset([pm](object, const D &value) { *pm = value; }, scope(*this)); + def_property_static(name, fget, fset, return_value_policy::reference, extra...); + return *this; + } + + template + class_ &def_readonly_static(const char *name, const D *pm, const Extra& ...extra) { + cpp_function fget([pm](object) -> const D &{ return *pm; }, scope(*this)); + def_property_readonly_static(name, fget, return_value_policy::reference, extra...); + return *this; + } + + /// Uses return_value_policy::reference_internal by default + template + class_ &def_property_readonly(const char *name, const Getter &fget, const Extra& ...extra) { + return def_property_readonly(name, cpp_function(fget), return_value_policy::reference_internal, extra...); + } + + /// Uses cpp_function's return_value_policy by default + template + class_ &def_property_readonly(const char *name, const cpp_function &fget, const Extra& ...extra) { + return def_property(name, fget, cpp_function(), extra...); + } + + /// Uses return_value_policy::reference by default + template + class_ &def_property_readonly_static(const char *name, const Getter &fget, const Extra& ...extra) { + return def_property_readonly_static(name, cpp_function(fget), return_value_policy::reference, extra...); + } + + /// Uses cpp_function's return_value_policy by default + template + class_ &def_property_readonly_static(const char *name, const cpp_function &fget, const Extra& ...extra) { + return def_property_static(name, fget, cpp_function(), extra...); + } + + /// Uses return_value_policy::reference_internal by default + template + class_ &def_property(const char *name, const Getter &fget, const cpp_function &fset, const Extra& ...extra) { + return def_property(name, cpp_function(fget), fset, return_value_policy::reference_internal, extra...); + } + + /// Uses cpp_function's return_value_policy by default + template + class_ &def_property(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) { + return def_property_static(name, fget, fset, is_method(*this), extra...); + } + + /// Uses return_value_policy::reference by default + template + class_ &def_property_static(const char *name, const Getter &fget, const cpp_function &fset, const Extra& ...extra) { + return def_property_static(name, cpp_function(fget), fset, return_value_policy::reference, extra...); + } + + /// Uses cpp_function's return_value_policy by default + template + class_ &def_property_static(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) { + auto rec_fget = get_function_record(fget), rec_fset = get_function_record(fset); + char *doc_prev = rec_fget->doc; /* 'extra' field may include a property-specific documentation string */ + detail::process_attributes::init(extra..., rec_fget); + if (rec_fget->doc && rec_fget->doc != doc_prev) { + free(doc_prev); + rec_fget->doc = strdup(rec_fget->doc); + } + if (rec_fset) { + doc_prev = rec_fset->doc; + detail::process_attributes::init(extra..., rec_fset); + if (rec_fset->doc && rec_fset->doc != doc_prev) { + free(doc_prev); + rec_fset->doc = strdup(rec_fset->doc); + } + } + pybind11::str doc_obj = pybind11::str((rec_fget->doc && pybind11::options::show_user_defined_docstrings()) ? rec_fget->doc : ""); + const auto property = reinterpret_steal( + PyObject_CallFunctionObjArgs((PyObject *) &PyProperty_Type, fget.ptr() ? fget.ptr() : Py_None, + fset.ptr() ? fset.ptr() : Py_None, Py_None, doc_obj.ptr(), nullptr)); + if (rec_fget->is_method && rec_fget->scope) + attr(name) = property; + else + metaclass().attr(name) = property; + return *this; + } + +private: + /// Initialize holder object, variant 1: object derives from enable_shared_from_this + template + static void init_holder_helper(instance_type *inst, const holder_type * /* unused */, const std::enable_shared_from_this * /* dummy */) { + try { + new (&inst->holder) holder_type(std::static_pointer_cast(inst->value->shared_from_this())); + inst->holder_constructed = true; + } catch (const std::bad_weak_ptr &) { + if (inst->owned) { + new (&inst->holder) holder_type(inst->value); + inst->holder_constructed = true; + } + } + } + + /// Initialize holder object, variant 2: try to construct from existing holder object, if possible + template ::value, int> = 0> + static void init_holder_helper(instance_type *inst, const holder_type *holder_ptr, const void * /* dummy */) { + if (holder_ptr) { + new (&inst->holder) holder_type(*holder_ptr); + inst->holder_constructed = true; + } else if (inst->owned) { + new (&inst->holder) holder_type(inst->value); + inst->holder_constructed = true; + } + } + + /// Initialize holder object, variant 3: holder is not copy constructible (e.g. unique_ptr), always initialize from raw pointer + template ::value, int> = 0> + static void init_holder_helper(instance_type *inst, const holder_type * /* unused */, const void * /* dummy */) { + if (inst->owned) { + new (&inst->holder) holder_type(inst->value); + inst->holder_constructed = true; + } + } + + /// Initialize holder object of an instance, possibly given a pointer to an existing holder + static void init_holder(PyObject *inst_, const void *holder_ptr) { + auto inst = (instance_type *) inst_; + init_holder_helper(inst, (const holder_type *) holder_ptr, inst->value); + } + + static void dealloc(PyObject *inst_) { + instance_type *inst = (instance_type *) inst_; + if (inst->holder_constructed) + inst->holder.~holder_type(); + else if (inst->owned) + ::operator delete(inst->value); + + generic_type::dealloc((detail::instance *) inst); + } + + static detail::function_record *get_function_record(handle h) { + h = detail::get_function(h); + return h ? (detail::function_record *) reinterpret_borrow(PyCFunction_GetSelf(h.ptr())) + : nullptr; + } +}; + +/// Binds C++ enumerations and enumeration classes to Python +template class enum_ : public class_ { +public: + using class_::def; + using Scalar = typename std::underlying_type::type; + template using arithmetic_tag = std::is_same; + + template + enum_(const handle &scope, const char *name, const Extra&... extra) + : class_(scope, name, extra...), m_parent(scope) { + + constexpr bool is_arithmetic = + !std::is_same, + void>::value; + + auto entries = new std::unordered_map(); + def("__repr__", [name, entries](Type value) -> std::string { + auto it = entries->find((Scalar) value); + return std::string(name) + "." + + ((it == entries->end()) ? std::string("???") + : std::string(it->second)); + }); + def("__init__", [](Type& value, Scalar i) { value = (Type)i; }); + def("__init__", [](Type& value, Scalar i) { new (&value) Type((Type) i); }); + def("__int__", [](Type value) { return (Scalar) value; }); + def("__eq__", [](const Type &value, Type *value2) { return value2 && value == *value2; }); + def("__ne__", [](const Type &value, Type *value2) { return !value2 || value != *value2; }); + if (is_arithmetic) { + def("__lt__", [](const Type &value, Type *value2) { return value2 && value < *value2; }); + def("__gt__", [](const Type &value, Type *value2) { return value2 && value > *value2; }); + def("__le__", [](const Type &value, Type *value2) { return value2 && value <= *value2; }); + def("__ge__", [](const Type &value, Type *value2) { return value2 && value >= *value2; }); + } + if (std::is_convertible::value) { + // Don't provide comparison with the underlying type if the enum isn't convertible, + // i.e. if Type is a scoped enum, mirroring the C++ behaviour. (NB: we explicitly + // convert Type to Scalar below anyway because this needs to compile). + def("__eq__", [](const Type &value, Scalar value2) { return (Scalar) value == value2; }); + def("__ne__", [](const Type &value, Scalar value2) { return (Scalar) value != value2; }); + if (is_arithmetic) { + def("__lt__", [](const Type &value, Scalar value2) { return (Scalar) value < value2; }); + def("__gt__", [](const Type &value, Scalar value2) { return (Scalar) value > value2; }); + def("__le__", [](const Type &value, Scalar value2) { return (Scalar) value <= value2; }); + def("__ge__", [](const Type &value, Scalar value2) { return (Scalar) value >= value2; }); + def("__invert__", [](const Type &value) { return ~((Scalar) value); }); + def("__and__", [](const Type &value, Scalar value2) { return (Scalar) value & value2; }); + def("__or__", [](const Type &value, Scalar value2) { return (Scalar) value | value2; }); + def("__xor__", [](const Type &value, Scalar value2) { return (Scalar) value ^ value2; }); + def("__rand__", [](const Type &value, Scalar value2) { return (Scalar) value & value2; }); + def("__ror__", [](const Type &value, Scalar value2) { return (Scalar) value | value2; }); + def("__rxor__", [](const Type &value, Scalar value2) { return (Scalar) value ^ value2; }); + def("__and__", [](const Type &value, const Type &value2) { return (Scalar) value & (Scalar) value2; }); + def("__or__", [](const Type &value, const Type &value2) { return (Scalar) value | (Scalar) value2; }); + def("__xor__", [](const Type &value, const Type &value2) { return (Scalar) value ^ (Scalar) value2; }); + } + } + def("__hash__", [](const Type &value) { return (Scalar) value; }); + // Pickling and unpickling -- needed for use with the 'multiprocessing' module + def("__getstate__", [](const Type &value) { return pybind11::make_tuple((Scalar) value); }); + def("__setstate__", [](Type &p, tuple t) { new (&p) Type((Type) t[0].cast()); }); + m_entries = entries; + } + + /// Export enumeration entries into the parent scope + enum_ &export_values() { + PyObject *dict = ((PyTypeObject *) this->m_ptr)->tp_dict; + PyObject *key, *value; + ssize_t pos = 0; + while (PyDict_Next(dict, &pos, &key, &value)) + if (PyObject_IsInstance(value, this->m_ptr)) + m_parent.attr(key) = value; + return *this; + } + + /// Add an enumeration entry + enum_& value(char const* name, Type value) { + this->attr(name) = pybind11::cast(value, return_value_policy::copy); + (*m_entries)[(Scalar) value] = name; + return *this; + } +private: + std::unordered_map *m_entries; + handle m_parent; +}; + +NAMESPACE_BEGIN(detail) +template struct init { + template = 0> + static void execute(Class &cl, const Extra&... extra) { + using Base = typename Class::type; + /// Function which calls a specific C++ in-place constructor + cl.def("__init__", [](Base *self_, Args... args) { new (self_) Base(args...); }, extra...); + } + + template ::value, int> = 0> + static void execute(Class &cl, const Extra&... extra) { + using Base = typename Class::type; + using Alias = typename Class::type_alias; + handle cl_type = cl; + cl.def("__init__", [cl_type](handle self_, Args... args) { + if (self_.get_type() == cl_type) + new (self_.cast()) Base(args...); + else + new (self_.cast()) Alias(args...); + }, extra...); + } + + template ::value, int> = 0> + static void execute(Class &cl, const Extra&... extra) { + init_alias::execute(cl, extra...); + } +}; +template struct init_alias { + template ::value, int> = 0> + static void execute(Class &cl, const Extra&... extra) { + using Alias = typename Class::type_alias; + cl.def("__init__", [](Alias *self_, Args... args) { new (self_) Alias(args...); }, extra...); + } +}; + + +inline void keep_alive_impl(handle nurse, handle patient) { + /* Clever approach based on weak references taken from Boost.Python */ + if (!nurse || !patient) + pybind11_fail("Could not activate keep_alive!"); + + if (patient.is_none() || nurse.is_none()) + return; /* Nothing to keep alive or nothing to be kept alive by */ + + cpp_function disable_lifesupport( + [patient](handle weakref) { patient.dec_ref(); weakref.dec_ref(); }); + + weakref wr(nurse, disable_lifesupport); + + patient.inc_ref(); /* reference patient and leak the weak reference */ + (void) wr.release(); +} + +PYBIND11_NOINLINE inline void keep_alive_impl(int Nurse, int Patient, handle args, handle ret) { + handle nurse (Nurse > 0 ? PyTuple_GetItem(args.ptr(), Nurse - 1) : ret.ptr()); + handle patient(Patient > 0 ? PyTuple_GetItem(args.ptr(), Patient - 1) : ret.ptr()); + + keep_alive_impl(nurse, patient); +} + +template +struct iterator_state { + Iterator it; + Sentinel end; + bool first; +}; + +NAMESPACE_END(detail) + +template detail::init init() { return detail::init(); } +template detail::init_alias init_alias() { return detail::init_alias(); } + +template ()), + typename... Extra> +iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) { + typedef detail::iterator_state state; + + if (!detail::get_type_info(typeid(state), false)) { + class_(handle(), "iterator") + .def("__iter__", [](state &s) -> state& { return s; }) + .def("__next__", [](state &s) -> ValueType { + if (!s.first) + ++s.it; + else + s.first = false; + if (s.it == s.end) + throw stop_iteration(); + return *s.it; + }, std::forward(extra)..., Policy); + } + + return (iterator) cast(state { first, last, true }); +} + +template ()).first), + typename... Extra> +iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) { + typedef detail::iterator_state state; + + if (!detail::get_type_info(typeid(state), false)) { + class_(handle(), "iterator") + .def("__iter__", [](state &s) -> state& { return s; }) + .def("__next__", [](state &s) -> KeyType { + if (!s.first) + ++s.it; + else + s.first = false; + if (s.it == s.end) + throw stop_iteration(); + return (*s.it).first; + }, std::forward(extra)..., Policy); + } + + return (iterator) cast(state { first, last, true }); +} + +template iterator make_iterator(Type &value, Extra&&... extra) { + return make_iterator(std::begin(value), std::end(value), extra...); +} + +template iterator make_key_iterator(Type &value, Extra&&... extra) { + return make_key_iterator(std::begin(value), std::end(value), extra...); +} + +template void implicitly_convertible() { + auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * { + if (!detail::type_caster().load(obj, false)) + return nullptr; + tuple args(1); + args[0] = obj; + PyObject *result = PyObject_Call((PyObject *) type, args.ptr(), nullptr); + if (result == nullptr) + PyErr_Clear(); + return result; + }; + + if (auto tinfo = detail::get_type_info(typeid(OutputType))) + tinfo->implicit_conversions.push_back(implicit_caster); + else + pybind11_fail("implicitly_convertible: Unable to find type " + type_id()); +} + +template +void register_exception_translator(ExceptionTranslator&& translator) { + detail::get_internals().registered_exception_translators.push_front( + std::forward(translator)); +} + +/* Wrapper to generate a new Python exception type. + * + * This should only be used with PyErr_SetString for now. + * It is not (yet) possible to use as a py::base. + * Template type argument is reserved for future use. + */ +template +class exception : public object { +public: + exception(handle scope, const char *name, PyObject *base = PyExc_Exception) { + std::string full_name = scope.attr("__name__").cast() + + std::string(".") + name; + m_ptr = PyErr_NewException((char *) full_name.c_str(), base, NULL); + if (hasattr(scope, name)) + pybind11_fail("Error during initialization: multiple incompatible " + "definitions with name \"" + std::string(name) + "\""); + scope.attr(name) = *this; + } + + // Sets the current python exception to this exception object with the given message + void operator()(const char *message) { + PyErr_SetString(m_ptr, message); + } +}; + +/** Registers a Python exception in `m` of the given `name` and installs an exception translator to + * translate the C++ exception to the created Python exception using the exceptions what() method. + * This is intended for simple exception translations; for more complex translation, register the + * exception object and translator directly. + */ +template +exception ®ister_exception(handle scope, + const char *name, + PyObject *base = PyExc_Exception) { + static exception ex(scope, name, base); + register_exception_translator([](std::exception_ptr p) { + if (!p) return; + try { + std::rethrow_exception(p); + } catch (const CppException &e) { + ex(e.what()); + } + }); + return ex; +} + +NAMESPACE_BEGIN(detail) +PYBIND11_NOINLINE inline void print(tuple args, dict kwargs) { + auto strings = tuple(args.size()); + for (size_t i = 0; i < args.size(); ++i) { + strings[i] = str(args[i]); + } + auto sep = kwargs.contains("sep") ? kwargs["sep"] : cast(" "); + auto line = sep.attr("join")(strings); + + object file; + if (kwargs.contains("file")) { + file = kwargs["file"].cast(); + } else { + try { + file = module::import("sys").attr("stdout"); + } catch (const error_already_set &) { + /* If print() is called from code that is executed as + part of garbage collection during interpreter shutdown, + importing 'sys' can fail. Give up rather than crashing the + interpreter in this case. */ + return; + } + } + + auto write = file.attr("write"); + write(line); + write(kwargs.contains("end") ? kwargs["end"] : cast("\n")); + + if (kwargs.contains("flush") && kwargs["flush"].cast()) + file.attr("flush")(); +} +NAMESPACE_END(detail) + +template +void print(Args &&...args) { + auto c = detail::collect_arguments(std::forward(args)...); + detail::print(c.args(), c.kwargs()); +} + +#if defined(WITH_THREAD) + +/* The functions below essentially reproduce the PyGILState_* API using a RAII + * pattern, but there are a few important differences: + * + * 1. When acquiring the GIL from an non-main thread during the finalization + * phase, the GILState API blindly terminates the calling thread, which + * is often not what is wanted. This API does not do this. + * + * 2. The gil_scoped_release function can optionally cut the relationship + * of a PyThreadState and its associated thread, which allows moving it to + * another thread (this is a fairly rare/advanced use case). + * + * 3. The reference count of an acquired thread state can be controlled. This + * can be handy to prevent cases where callbacks issued from an external + * thread would otherwise constantly construct and destroy thread state data + * structures. + * + * See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an + * example which uses features 2 and 3 to migrate the Python thread of + * execution to another thread (to run the event loop on the original thread, + * in this case). + */ + +class gil_scoped_acquire { +public: + PYBIND11_NOINLINE gil_scoped_acquire() { + auto const &internals = detail::get_internals(); + tstate = (PyThreadState *) PyThread_get_key_value(internals.tstate); + + if (!tstate) { + tstate = PyThreadState_New(internals.istate); + #if !defined(NDEBUG) + if (!tstate) + pybind11_fail("scoped_acquire: could not create thread state!"); + #endif + tstate->gilstate_counter = 0; + #if PY_MAJOR_VERSION < 3 + PyThread_delete_key_value(internals.tstate); + #endif + PyThread_set_key_value(internals.tstate, tstate); + } else { + release = detail::get_thread_state_unchecked() != tstate; + } + + if (release) { + /* Work around an annoying assertion in PyThreadState_Swap */ + #if defined(Py_DEBUG) + PyInterpreterState *interp = tstate->interp; + tstate->interp = nullptr; + #endif + PyEval_AcquireThread(tstate); + #if defined(Py_DEBUG) + tstate->interp = interp; + #endif + } + + inc_ref(); + } + + void inc_ref() { + ++tstate->gilstate_counter; + } + + PYBIND11_NOINLINE void dec_ref() { + --tstate->gilstate_counter; + #if !defined(NDEBUG) + if (detail::get_thread_state_unchecked() != tstate) + pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!"); + if (tstate->gilstate_counter < 0) + pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!"); + #endif + if (tstate->gilstate_counter == 0) { + #if !defined(NDEBUG) + if (!release) + pybind11_fail("scoped_acquire::dec_ref(): internal error!"); + #endif + PyThreadState_Clear(tstate); + PyThreadState_DeleteCurrent(); + PyThread_delete_key_value(detail::get_internals().tstate); + release = false; + } + } + + PYBIND11_NOINLINE ~gil_scoped_acquire() { + dec_ref(); + if (release) + PyEval_SaveThread(); + } +private: + PyThreadState *tstate = nullptr; + bool release = true; +}; + +class gil_scoped_release { +public: + explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) { + tstate = PyEval_SaveThread(); + if (disassoc) { + auto key = detail::get_internals().tstate; + #if PY_MAJOR_VERSION < 3 + PyThread_delete_key_value(key); + #else + PyThread_set_key_value(key, nullptr); + #endif + } + } + ~gil_scoped_release() { + if (!tstate) + return; + PyEval_RestoreThread(tstate); + if (disassoc) { + auto key = detail::get_internals().tstate; + #if PY_MAJOR_VERSION < 3 + PyThread_delete_key_value(key); + #endif + PyThread_set_key_value(key, tstate); + } + } +private: + PyThreadState *tstate; + bool disassoc; +}; +#else +class gil_scoped_acquire { }; +class gil_scoped_release { }; +#endif + +error_already_set::~error_already_set() { + if (value) { + gil_scoped_acquire gil; + PyErr_Restore(type, value, trace); + PyErr_Clear(); + } +} + +inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) { + handle py_object = detail::get_object_handle(this_ptr, this_type); + if (!py_object) + return function(); + handle type = py_object.get_type(); + auto key = std::make_pair(type.ptr(), name); + + /* Cache functions that aren't overloaded in Python to avoid + many costly Python dictionary lookups below */ + auto &cache = detail::get_internals().inactive_overload_cache; + if (cache.find(key) != cache.end()) + return function(); + + function overload = getattr(py_object, name, function()); + if (overload.is_cpp_function()) { + cache.insert(key); + return function(); + } + + /* Don't call dispatch code if invoked from overridden function */ + PyFrameObject *frame = PyThreadState_Get()->frame; + if (frame && (std::string) str(frame->f_code->co_name) == name && + frame->f_code->co_argcount > 0) { + PyFrame_FastToLocals(frame); + PyObject *self_caller = PyDict_GetItem( + frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0)); + if (self_caller == py_object.ptr()) + return function(); + } + return overload; +} + +template function get_overload(const T *this_ptr, const char *name) { + auto tinfo = detail::get_type_info(typeid(T)); + return tinfo ? get_type_overload(this_ptr, tinfo, name) : function(); +} + +#define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...) { \ + pybind11::gil_scoped_acquire gil; \ + pybind11::function overload = pybind11::get_overload(static_cast(this), name); \ + if (overload) { \ + auto o = overload(__VA_ARGS__); \ + if (pybind11::detail::cast_is_temporary_value_reference::value) { \ + static pybind11::detail::overload_caster_t caster; \ + return pybind11::detail::cast_ref(std::move(o), caster); \ + } \ + else return pybind11::detail::cast_safe(std::move(o)); \ + } \ + } + +#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \ + PYBIND11_OVERLOAD_INT(ret_type, cname, name, __VA_ARGS__) \ + return cname::fn(__VA_ARGS__) + +#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \ + PYBIND11_OVERLOAD_INT(ret_type, cname, name, __VA_ARGS__) \ + pybind11::pybind11_fail("Tried to call pure virtual function \"" #cname "::" name "\""); + +#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \ + PYBIND11_OVERLOAD_NAME(ret_type, cname, #fn, fn, __VA_ARGS__) + +#define PYBIND11_OVERLOAD_PURE(ret_type, cname, fn, ...) \ + PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, #fn, fn, __VA_ARGS__) + +NAMESPACE_END(pybind11) + +#if defined(_MSC_VER) +# pragma warning(pop) +#elif defined(__INTEL_COMPILER) +/* Leave ignored warnings on */ +#elif defined(__GNUG__) && !defined(__clang__) +# pragma GCC diagnostic pop +#endif diff --git a/resources/pybind11/include/pybind11/pytypes.h b/resources/pybind11/include/pybind11/pytypes.h new file mode 100755 index 0000000..d078d58 --- /dev/null +++ b/resources/pybind11/include/pybind11/pytypes.h @@ -0,0 +1,899 @@ +/* + pybind11/typeid.h: Convenience wrapper classes for basic Python types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "common.h" +#include +#include + +NAMESPACE_BEGIN(pybind11) + +/* A few forward declarations */ +class handle; class object; +class str; class iterator; +struct arg; struct arg_v; + +NAMESPACE_BEGIN(detail) +class args_proxy; +inline bool isinstance_generic(handle obj, const std::type_info &tp); + +// Accessor forward declarations +template class accessor; +namespace accessor_policies { + struct obj_attr; + struct str_attr; + struct generic_item; + struct sequence_item; + struct list_item; + struct tuple_item; +} +using obj_attr_accessor = accessor; +using str_attr_accessor = accessor; +using item_accessor = accessor; +using sequence_accessor = accessor; +using list_accessor = accessor; +using tuple_accessor = accessor; + +/// Tag and check to identify a class which implements the Python object API +class pyobject_tag { }; +template using is_pyobject = std::is_base_of; + +/// Mixin which adds common functions to handle, object and various accessors. +/// The only requirement for `Derived` is to implement `PyObject *Derived::ptr() const`. +template +class object_api : public pyobject_tag { + const Derived &derived() const { return static_cast(*this); } + +public: + iterator begin() const; + iterator end() const; + item_accessor operator[](handle key) const; + item_accessor operator[](const char *key) const; + obj_attr_accessor attr(handle key) const; + str_attr_accessor attr(const char *key) const; + args_proxy operator*() const; + template bool contains(T &&key) const; + + template + object operator()(Args &&...args) const; + template + PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)") + object call(Args&&... args) const; + + bool is_none() const { return derived().ptr() == Py_None; } + PYBIND11_DEPRECATED("Instead of obj.str(), use py::str(obj)") + pybind11::str str() const; + + int ref_count() const { return static_cast(Py_REFCNT(derived().ptr())); } + handle get_type() const; +}; + +NAMESPACE_END(detail) + +/// Holds a reference to a Python object (no reference counting) +class handle : public detail::object_api { +public: + handle() = default; + handle(PyObject *ptr) : m_ptr(ptr) { } + + PyObject *ptr() const { return m_ptr; } + PyObject *&ptr() { return m_ptr; } + const handle& inc_ref() const { Py_XINCREF(m_ptr); return *this; } + const handle& dec_ref() const { Py_XDECREF(m_ptr); return *this; } + + template T cast() const; + explicit operator bool() const { return m_ptr != nullptr; } + bool operator==(const handle &h) const { return m_ptr == h.m_ptr; } + bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; } + PYBIND11_DEPRECATED("Use handle::operator bool() instead") + bool check() const { return m_ptr != nullptr; } +protected: + PyObject *m_ptr = nullptr; +}; + +/// Holds a reference to a Python object (with reference counting) +class object : public handle { +public: + object() = default; + PYBIND11_DEPRECATED("Use reinterpret_borrow() or reinterpret_steal()") + object(handle h, bool is_borrowed) : handle(h) { if (is_borrowed) inc_ref(); } + object(const object &o) : handle(o) { inc_ref(); } + object(object &&other) noexcept { m_ptr = other.m_ptr; other.m_ptr = nullptr; } + ~object() { dec_ref(); } + + handle release() { + PyObject *tmp = m_ptr; + m_ptr = nullptr; + return handle(tmp); + } + + object& operator=(const object &other) { + other.inc_ref(); + dec_ref(); + m_ptr = other.m_ptr; + return *this; + } + + object& operator=(object &&other) noexcept { + if (this != &other) { + handle temp(m_ptr); + m_ptr = other.m_ptr; + other.m_ptr = nullptr; + temp.dec_ref(); + } + return *this; + } + + // Calling cast() on an object lvalue just copies (via handle::cast) + template T cast() const &; + // Calling on an object rvalue does a move, if needed and/or possible + template T cast() &&; + +protected: + // Tags for choosing constructors from raw PyObject * + struct borrowed_t { }; static constexpr borrowed_t borrowed{}; + struct stolen_t { }; static constexpr stolen_t stolen{}; + + template friend T reinterpret_borrow(handle); + template friend T reinterpret_steal(handle); + +public: + // Only accessible from derived classes and the reinterpret_* functions + object(handle h, borrowed_t) : handle(h) { inc_ref(); } + object(handle h, stolen_t) : handle(h) { } +}; + +/** The following functions don't do any kind of conversion, they simply declare + that a PyObject is a certain type and borrow or steal the reference. */ +template T reinterpret_borrow(handle h) { return {h, object::borrowed}; } +template T reinterpret_steal(handle h) { return {h, object::stolen}; } + +/// Check if `obj` is an instance of type `T` +template ::value, int> = 0> +bool isinstance(handle obj) { return T::_check(obj); } + +template ::value, int> = 0> +bool isinstance(handle obj) { return detail::isinstance_generic(obj, typeid(T)); } + +template <> inline bool isinstance(handle obj) = delete; +template <> inline bool isinstance(handle obj) { return obj.ptr() != nullptr; } + +inline bool hasattr(handle obj, handle name) { + return PyObject_HasAttr(obj.ptr(), name.ptr()) == 1; +} + +inline bool hasattr(handle obj, const char *name) { + return PyObject_HasAttrString(obj.ptr(), name) == 1; +} + +inline object getattr(handle obj, handle name) { + PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr()); + if (!result) { throw error_already_set(); } + return reinterpret_steal(result); +} + +inline object getattr(handle obj, const char *name) { + PyObject *result = PyObject_GetAttrString(obj.ptr(), name); + if (!result) { throw error_already_set(); } + return reinterpret_steal(result); +} + +inline object getattr(handle obj, handle name, handle default_) { + if (PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr())) { + return reinterpret_steal(result); + } else { + PyErr_Clear(); + return reinterpret_borrow(default_); + } +} + +inline object getattr(handle obj, const char *name, handle default_) { + if (PyObject *result = PyObject_GetAttrString(obj.ptr(), name)) { + return reinterpret_steal(result); + } else { + PyErr_Clear(); + return reinterpret_borrow(default_); + } +} + +inline void setattr(handle obj, handle name, handle value) { + if (PyObject_SetAttr(obj.ptr(), name.ptr(), value.ptr()) != 0) { throw error_already_set(); } +} + +inline void setattr(handle obj, const char *name, handle value) { + if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) { throw error_already_set(); } +} + +NAMESPACE_BEGIN(detail) +inline handle get_function(handle value) { + if (value) { +#if PY_MAJOR_VERSION >= 3 + if (PyInstanceMethod_Check(value.ptr())) + value = PyInstanceMethod_GET_FUNCTION(value.ptr()); +#endif + if (PyMethod_Check(value.ptr())) + value = PyMethod_GET_FUNCTION(value.ptr()); + } + return value; +} + +template +class accessor : public object_api> { + using key_type = typename Policy::key_type; + +public: + accessor(handle obj, key_type key) : obj(obj), key(std::move(key)) { } + + void operator=(const accessor &a) && { std::move(*this).operator=(handle(a)); } + void operator=(const accessor &a) & { operator=(handle(a)); } + void operator=(const object &o) && { std::move(*this).operator=(handle(o)); } + void operator=(const object &o) & { operator=(handle(o)); } + void operator=(handle value) && { Policy::set(obj, key, value); } + void operator=(handle value) & { get_cache() = reinterpret_borrow(value); } + + template + PYBIND11_DEPRECATED("Use of obj.attr(...) as bool is deprecated in favor of pybind11::hasattr(obj, ...)") + explicit operator enable_if_t::value || + std::is_same::value, bool>() const { + return hasattr(obj, key); + } + template + PYBIND11_DEPRECATED("Use of obj[key] as bool is deprecated in favor of obj.contains(key)") + explicit operator enable_if_t::value, bool>() const { + return obj.contains(key); + } + + operator object() const { return get_cache(); } + PyObject *ptr() const { return get_cache().ptr(); } + template T cast() const { return get_cache().template cast(); } + +private: + object &get_cache() const { + if (!cache) { cache = Policy::get(obj, key); } + return cache; + } + +private: + handle obj; + key_type key; + mutable object cache; +}; + +NAMESPACE_BEGIN(accessor_policies) +struct obj_attr { + using key_type = object; + static object get(handle obj, handle key) { return getattr(obj, key); } + static void set(handle obj, handle key, handle val) { setattr(obj, key, val); } +}; + +struct str_attr { + using key_type = const char *; + static object get(handle obj, const char *key) { return getattr(obj, key); } + static void set(handle obj, const char *key, handle val) { setattr(obj, key, val); } +}; + +struct generic_item { + using key_type = object; + + static object get(handle obj, handle key) { + PyObject *result = PyObject_GetItem(obj.ptr(), key.ptr()); + if (!result) { throw error_already_set(); } + return reinterpret_steal(result); + } + + static void set(handle obj, handle key, handle val) { + if (PyObject_SetItem(obj.ptr(), key.ptr(), val.ptr()) != 0) { throw error_already_set(); } + } +}; + +struct sequence_item { + using key_type = size_t; + + static object get(handle obj, size_t index) { + PyObject *result = PySequence_GetItem(obj.ptr(), static_cast(index)); + if (!result) { throw error_already_set(); } + return reinterpret_borrow(result); + } + + static void set(handle obj, size_t index, handle val) { + // PySequence_SetItem does not steal a reference to 'val' + if (PySequence_SetItem(obj.ptr(), static_cast(index), val.ptr()) != 0) { + throw error_already_set(); + } + } +}; + +struct list_item { + using key_type = size_t; + + static object get(handle obj, size_t index) { + PyObject *result = PyList_GetItem(obj.ptr(), static_cast(index)); + if (!result) { throw error_already_set(); } + return reinterpret_borrow(result); + } + + static void set(handle obj, size_t index, handle val) { + // PyList_SetItem steals a reference to 'val' + if (PyList_SetItem(obj.ptr(), static_cast(index), val.inc_ref().ptr()) != 0) { + throw error_already_set(); + } + } +}; + +struct tuple_item { + using key_type = size_t; + + static object get(handle obj, size_t index) { + PyObject *result = PyTuple_GetItem(obj.ptr(), static_cast(index)); + if (!result) { throw error_already_set(); } + return reinterpret_borrow(result); + } + + static void set(handle obj, size_t index, handle val) { + // PyTuple_SetItem steals a reference to 'val' + if (PyTuple_SetItem(obj.ptr(), static_cast(index), val.inc_ref().ptr()) != 0) { + throw error_already_set(); + } + } +}; +NAMESPACE_END(accessor_policies) + +struct dict_iterator { +public: + explicit dict_iterator(handle dict = handle(), ssize_t pos = -1) : dict(dict), pos(pos) { } + dict_iterator& operator++() { + if (!PyDict_Next(dict.ptr(), &pos, &key.ptr(), &value.ptr())) + pos = -1; + return *this; + } + std::pair operator*() const { + return std::make_pair(key, value); + } + bool operator==(const dict_iterator &it) const { return it.pos == pos; } + bool operator!=(const dict_iterator &it) const { return it.pos != pos; } +private: + handle dict, key, value; + ssize_t pos = 0; +}; + +inline bool PyIterable_Check(PyObject *obj) { + PyObject *iter = PyObject_GetIter(obj); + if (iter) { + Py_DECREF(iter); + return true; + } else { + PyErr_Clear(); + return false; + } +} + +inline bool PyNone_Check(PyObject *o) { return o == Py_None; } + +inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); } + +class kwargs_proxy : public handle { +public: + explicit kwargs_proxy(handle h) : handle(h) { } +}; + +class args_proxy : public handle { +public: + explicit args_proxy(handle h) : handle(h) { } + kwargs_proxy operator*() const { return kwargs_proxy(*this); } +}; + +/// Python argument categories (using PEP 448 terms) +template using is_keyword = std::is_base_of; +template using is_s_unpacking = std::is_same; // * unpacking +template using is_ds_unpacking = std::is_same; // ** unpacking +template using is_positional = bool_constant< + !is_keyword::value && !is_s_unpacking::value && !is_ds_unpacking::value +>; +template using is_keyword_or_ds = bool_constant< + is_keyword::value || is_ds_unpacking::value +>; + +// Call argument collector forward declarations +template +class simple_collector; +template +class unpacking_collector; + +NAMESPACE_END(detail) + +// TODO: After the deprecated constructors are removed, this macro can be simplified by +// inheriting ctors: `using Parent::Parent`. It's not an option right now because +// the `using` statement triggers the parent deprecation warning even if the ctor +// isn't even used. +#define PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ + public: \ + PYBIND11_DEPRECATED("Use reinterpret_borrow<"#Name">() or reinterpret_steal<"#Name">()") \ + Name(handle h, bool is_borrowed) : Parent(is_borrowed ? Parent(h, borrowed) : Parent(h, stolen)) { } \ + Name(handle h, borrowed_t) : Parent(h, borrowed) { } \ + Name(handle h, stolen_t) : Parent(h, stolen) { } \ + PYBIND11_DEPRECATED("Use py::isinstance(obj) instead") \ + bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); } \ + static bool _check(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); } + +#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \ + PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ + /* This is deliberately not 'explicit' to allow implicit conversion from object: */ \ + Name(const object &o) : Parent(ConvertFun(o.ptr()), stolen) { if (!m_ptr) throw error_already_set(); } + +#define PYBIND11_OBJECT(Name, Parent, CheckFun) \ + PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ + /* This is deliberately not 'explicit' to allow implicit conversion from object: */ \ + Name(const object &o) : Parent(o) { } \ + Name(object &&o) : Parent(std::move(o)) { } + +#define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun) \ + PYBIND11_OBJECT(Name, Parent, CheckFun) \ + Name() : Parent() { } + +class iterator : public object { +public: + /** Caveat: copying an iterator does not (and cannot) clone the internal + state of the Python iterable */ + PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check) + + iterator& operator++() { + if (m_ptr) + advance(); + return *this; + } + + /** Caveat: this postincrement operator does not (and cannot) clone the + internal state of the Python iterable. It should only be used to + retrieve the current iterate using operator*() */ + iterator operator++(int) { + iterator rv(*this); + rv.value = value; + if (m_ptr) + advance(); + return rv; + } + + bool operator==(const iterator &it) const { return *it == **this; } + bool operator!=(const iterator &it) const { return *it != **this; } + + handle operator*() const { + if (!ready && m_ptr) { + auto& self = const_cast(*this); + self.advance(); + self.ready = true; + } + return value; + } + +private: + void advance() { value = reinterpret_steal(PyIter_Next(m_ptr)); } + +private: + object value = {}; + bool ready = false; +}; + +class iterable : public object { +public: + PYBIND11_OBJECT_DEFAULT(iterable, object, detail::PyIterable_Check) +}; + +class bytes; + +class str : public object { +public: + PYBIND11_OBJECT_CVT(str, object, detail::PyUnicode_Check_Permissive, raw_str) + + str(const char *c, size_t n) + : object(PyUnicode_FromStringAndSize(c, (ssize_t) n), stolen) { + if (!m_ptr) pybind11_fail("Could not allocate string object!"); + } + + // 'explicit' is explicitly omitted from the following constructors to allow implicit conversion to py::str from C++ string-like objects + str(const char *c = "") + : object(PyUnicode_FromString(c), stolen) { + if (!m_ptr) pybind11_fail("Could not allocate string object!"); + } + + str(const std::string &s) : str(s.data(), s.size()) { } + + explicit str(const bytes &b); + + explicit str(handle h) : object(raw_str(h.ptr()), stolen) { } + + operator std::string() const { + object temp = *this; + if (PyUnicode_Check(m_ptr)) { + temp = reinterpret_steal(PyUnicode_AsUTF8String(m_ptr)); + if (!temp) + pybind11_fail("Unable to extract string contents! (encoding issue)"); + } + char *buffer; + ssize_t length; + if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) + pybind11_fail("Unable to extract string contents! (invalid type)"); + return std::string(buffer, (size_t) length); + } + + template + str format(Args &&...args) const { + return attr("format")(std::forward(args)...); + } + +private: + /// Return string representation -- always returns a new reference, even if already a str + static PyObject *raw_str(PyObject *op) { + PyObject *str_value = PyObject_Str(op); +#if PY_MAJOR_VERSION < 3 + if (!str_value) throw error_already_set(); + PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr); + Py_XDECREF(str_value); str_value = unicode; +#endif + return str_value; + } +}; + +inline namespace literals { +/// String literal version of str +inline str operator"" _s(const char *s, size_t size) { return {s, size}; } +} + +class bytes : public object { +public: + PYBIND11_OBJECT(bytes, object, PYBIND11_BYTES_CHECK) + + // Allow implicit conversion: + bytes(const char *c = "") + : object(PYBIND11_BYTES_FROM_STRING(c), stolen) { + if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); + } + + bytes(const char *c, size_t n) + : object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(c, (ssize_t) n), stolen) { + if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); + } + + // Allow implicit conversion: + bytes(const std::string &s) : bytes(s.data(), s.size()) { } + + explicit bytes(const pybind11::str &s); + + operator std::string() const { + char *buffer; + ssize_t length; + if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) + pybind11_fail("Unable to extract bytes contents!"); + return std::string(buffer, (size_t) length); + } +}; + +inline bytes::bytes(const pybind11::str &s) { + object temp = s; + if (PyUnicode_Check(s.ptr())) { + temp = reinterpret_steal(PyUnicode_AsUTF8String(s.ptr())); + if (!temp) + pybind11_fail("Unable to extract string contents! (encoding issue)"); + } + char *buffer; + ssize_t length; + if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) + pybind11_fail("Unable to extract string contents! (invalid type)"); + auto obj = reinterpret_steal(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length)); + if (!obj) + pybind11_fail("Could not allocate bytes object!"); + m_ptr = obj.release().ptr(); +} + +inline str::str(const bytes& b) { + char *buffer; + ssize_t length; + if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length)) + pybind11_fail("Unable to extract bytes contents!"); + auto obj = reinterpret_steal(PyUnicode_FromStringAndSize(buffer, (ssize_t) length)); + if (!obj) + pybind11_fail("Could not allocate string object!"); + m_ptr = obj.release().ptr(); +} + +class none : public object { +public: + PYBIND11_OBJECT(none, object, detail::PyNone_Check) + none() : object(Py_None, borrowed) { } +}; + +class bool_ : public object { +public: + PYBIND11_OBJECT_CVT(bool_, object, PyBool_Check, raw_bool) + bool_() : object(Py_False, borrowed) { } + // Allow implicit conversion from and to `bool`: + bool_(bool value) : object(value ? Py_True : Py_False, borrowed) { } + operator bool() const { return m_ptr && PyLong_AsLong(m_ptr) != 0; } + +private: + /// Return the truth value of an object -- always returns a new reference + static PyObject *raw_bool(PyObject *op) { + const auto value = PyObject_IsTrue(op); + if (value == -1) return nullptr; + return handle(value ? Py_True : Py_False).inc_ref().ptr(); + } +}; + +class int_ : public object { +public: + PYBIND11_OBJECT_CVT(int_, object, PYBIND11_LONG_CHECK, PyNumber_Long) + int_() : object(PyLong_FromLong(0), stolen) { } + // Allow implicit conversion from C++ integral types: + template ::value, int> = 0> + int_(T value) { + if (sizeof(T) <= sizeof(long)) { + if (std::is_signed::value) + m_ptr = PyLong_FromLong((long) value); + else + m_ptr = PyLong_FromUnsignedLong((unsigned long) value); + } else { + if (std::is_signed::value) + m_ptr = PyLong_FromLongLong((long long) value); + else + m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value); + } + if (!m_ptr) pybind11_fail("Could not allocate int object!"); + } + + template ::value, int> = 0> + operator T() const { + if (sizeof(T) <= sizeof(long)) { + if (std::is_signed::value) + return (T) PyLong_AsLong(m_ptr); + else + return (T) PyLong_AsUnsignedLong(m_ptr); + } else { + if (std::is_signed::value) + return (T) PYBIND11_LONG_AS_LONGLONG(m_ptr); + else + return (T) PYBIND11_LONG_AS_UNSIGNED_LONGLONG(m_ptr); + } + } +}; + +class float_ : public object { +public: + PYBIND11_OBJECT_CVT(float_, object, PyFloat_Check, PyNumber_Float) + // Allow implicit conversion from float/double: + float_(float value) : object(PyFloat_FromDouble((double) value), stolen) { + if (!m_ptr) pybind11_fail("Could not allocate float object!"); + } + float_(double value = .0) : object(PyFloat_FromDouble((double) value), stolen) { + if (!m_ptr) pybind11_fail("Could not allocate float object!"); + } + operator float() const { return (float) PyFloat_AsDouble(m_ptr); } + operator double() const { return (double) PyFloat_AsDouble(m_ptr); } +}; + +class weakref : public object { +public: + PYBIND11_OBJECT_DEFAULT(weakref, object, PyWeakref_Check) + explicit weakref(handle obj, handle callback = {}) + : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen) { + if (!m_ptr) pybind11_fail("Could not allocate weak reference!"); + } +}; + +class slice : public object { +public: + PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check) + slice(ssize_t start_, ssize_t stop_, ssize_t step_) { + int_ start(start_), stop(stop_), step(step_); + m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr()); + if (!m_ptr) pybind11_fail("Could not allocate slice object!"); + } + bool compute(size_t length, size_t *start, size_t *stop, size_t *step, + size_t *slicelength) const { + return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr, + (ssize_t) length, (ssize_t *) start, + (ssize_t *) stop, (ssize_t *) step, + (ssize_t *) slicelength) == 0; + } +}; + +class capsule : public object { +public: + PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact) + PYBIND11_DEPRECATED("Use reinterpret_borrow() or reinterpret_steal()") + capsule(PyObject *ptr, bool is_borrowed) : object(is_borrowed ? object(ptr, borrowed) : object(ptr, stolen)) { } + explicit capsule(const void *value, void (*destruct)(PyObject *) = nullptr) + : object(PyCapsule_New(const_cast(value), nullptr, destruct), stolen) { + if (!m_ptr) pybind11_fail("Could not allocate capsule object!"); + } + template operator T *() const { + T * result = static_cast(PyCapsule_GetPointer(m_ptr, nullptr)); + if (!result) pybind11_fail("Unable to extract capsule contents!"); + return result; + } +}; + +class tuple : public object { +public: + PYBIND11_OBJECT_CVT(tuple, object, PyTuple_Check, PySequence_Tuple) + explicit tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), stolen) { + if (!m_ptr) pybind11_fail("Could not allocate tuple object!"); + } + size_t size() const { return (size_t) PyTuple_Size(m_ptr); } + detail::tuple_accessor operator[](size_t index) const { return {*this, index}; } +}; + +class dict : public object { +public: + PYBIND11_OBJECT_CVT(dict, object, PyDict_Check, raw_dict) + dict() : object(PyDict_New(), stolen) { + if (!m_ptr) pybind11_fail("Could not allocate dict object!"); + } + template ::value>, + // MSVC workaround: it can't compile an out-of-line definition, so defer the collector + typename collector = detail::deferred_t, Args...>> + explicit dict(Args &&...args) : dict(collector(std::forward(args)...).kwargs()) { } + + size_t size() const { return (size_t) PyDict_Size(m_ptr); } + detail::dict_iterator begin() const { return (++detail::dict_iterator(*this, 0)); } + detail::dict_iterator end() const { return detail::dict_iterator(); } + void clear() const { PyDict_Clear(ptr()); } + bool contains(handle key) const { return PyDict_Contains(ptr(), key.ptr()) == 1; } + bool contains(const char *key) const { return PyDict_Contains(ptr(), pybind11::str(key).ptr()) == 1; } + +private: + /// Call the `dict` Python type -- always returns a new reference + static PyObject *raw_dict(PyObject *op) { + if (PyDict_Check(op)) + return handle(op).inc_ref().ptr(); + return PyObject_CallFunctionObjArgs((PyObject *) &PyDict_Type, op, nullptr); + } +}; + +class sequence : public object { +public: + PYBIND11_OBJECT(sequence, object, PySequence_Check) + size_t size() const { return (size_t) PySequence_Size(m_ptr); } + detail::sequence_accessor operator[](size_t index) const { return {*this, index}; } +}; + +class list : public object { +public: + PYBIND11_OBJECT_CVT(list, object, PyList_Check, PySequence_List) + explicit list(size_t size = 0) : object(PyList_New((ssize_t) size), stolen) { + if (!m_ptr) pybind11_fail("Could not allocate list object!"); + } + size_t size() const { return (size_t) PyList_Size(m_ptr); } + detail::list_accessor operator[](size_t index) const { return {*this, index}; } + void append(handle h) const { PyList_Append(m_ptr, h.ptr()); } +}; + +class args : public tuple { PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check) }; +class kwargs : public dict { PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check) }; + +class set : public object { +public: + PYBIND11_OBJECT_CVT(set, object, PySet_Check, PySet_New) + set() : object(PySet_New(nullptr), stolen) { + if (!m_ptr) pybind11_fail("Could not allocate set object!"); + } + size_t size() const { return (size_t) PySet_Size(m_ptr); } + bool add(const object &object) const { return PySet_Add(m_ptr, object.ptr()) == 0; } + void clear() const { PySet_Clear(m_ptr); } +}; + +class function : public object { +public: + PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check) + bool is_cpp_function() const { + handle fun = detail::get_function(m_ptr); + return fun && PyCFunction_Check(fun.ptr()); + } +}; + +class buffer : public object { +public: + PYBIND11_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer) + + buffer_info request(bool writable = false) { + int flags = PyBUF_STRIDES | PyBUF_FORMAT; + if (writable) flags |= PyBUF_WRITABLE; + Py_buffer *view = new Py_buffer(); + if (PyObject_GetBuffer(m_ptr, view, flags) != 0) + throw error_already_set(); + return buffer_info(view); + } +}; + +class memoryview : public object { +public: + explicit memoryview(const buffer_info& info) { + static Py_buffer buf { }; + // Py_buffer uses signed sizes, strides and shape!.. + static std::vector py_strides { }; + static std::vector py_shape { }; + buf.buf = info.ptr; + buf.itemsize = (Py_ssize_t) info.itemsize; + buf.format = const_cast(info.format.c_str()); + buf.ndim = (int) info.ndim; + buf.len = (Py_ssize_t) info.size; + py_strides.clear(); + py_shape.clear(); + for (size_t i = 0; i < info.ndim; ++i) { + py_strides.push_back((Py_ssize_t) info.strides[i]); + py_shape.push_back((Py_ssize_t) info.shape[i]); + } + buf.strides = py_strides.data(); + buf.shape = py_shape.data(); + buf.suboffsets = nullptr; + buf.readonly = false; + buf.internal = nullptr; + + m_ptr = PyMemoryView_FromBuffer(&buf); + if (!m_ptr) + pybind11_fail("Unable to create memoryview from buffer descriptor"); + } + + PYBIND11_OBJECT_CVT(memoryview, object, PyMemoryView_Check, PyMemoryView_FromObject) +}; + +inline size_t len(handle h) { + ssize_t result = PyObject_Length(h.ptr()); + if (result < 0) + pybind11_fail("Unable to compute length of object"); + return (size_t) result; +} + +inline str repr(handle h) { + PyObject *str_value = PyObject_Repr(h.ptr()); + if (!str_value) throw error_already_set(); +#if PY_MAJOR_VERSION < 3 + PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr); + Py_XDECREF(str_value); str_value = unicode; + if (!str_value) throw error_already_set(); +#endif + return reinterpret_steal(str_value); +} + +NAMESPACE_BEGIN(detail) +template iterator object_api::begin() const { + return reinterpret_steal(PyObject_GetIter(derived().ptr())); +} +template iterator object_api::end() const { + return {}; +} +template item_accessor object_api::operator[](handle key) const { + return {derived(), reinterpret_borrow(key)}; +} +template item_accessor object_api::operator[](const char *key) const { + return {derived(), pybind11::str(key)}; +} +template obj_attr_accessor object_api::attr(handle key) const { + return {derived(), reinterpret_borrow(key)}; +} +template str_attr_accessor object_api::attr(const char *key) const { + return {derived(), key}; +} +template args_proxy object_api::operator*() const { + return args_proxy(derived().ptr()); +} +template template bool object_api::contains(T &&key) const { + return attr("__contains__")(std::forward(key)).template cast(); +} + +template +pybind11::str object_api::str() const { return pybind11::str(derived()); } + +template +handle object_api::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); } + +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/resources/pybind11/include/pybind11/stl.h b/resources/pybind11/include/pybind11/stl.h new file mode 100755 index 0000000..766a8f2 --- /dev/null +++ b/resources/pybind11/include/pybind11/stl.h @@ -0,0 +1,256 @@ +/* + pybind11/stl.h: Transparent conversion for STL data types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +#ifdef __has_include +// std::optional (but including it in c++14 mode isn't allowed) +# if defined(PYBIND11_CPP17) && __has_include() +# include +# define PYBIND11_HAS_OPTIONAL 1 +# endif +// std::experimental::optional (but not allowed in c++11 mode) +# if defined(PYBIND11_CPP14) && __has_include() +# include +# if __cpp_lib_experimental_optional // just in case +# define PYBIND11_HAS_EXP_OPTIONAL 1 +# endif +# endif +#endif + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + +template struct set_caster { + using type = Type; + using key_conv = make_caster; + + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + auto s = reinterpret_borrow(src); + value.clear(); + key_conv conv; + for (auto entry : s) { + if (!conv.load(entry, convert)) + return false; + value.insert(cast_op(conv)); + } + return true; + } + + static handle cast(const type &src, return_value_policy policy, handle parent) { + pybind11::set s; + for (auto const &value: src) { + auto value_ = reinterpret_steal(key_conv::cast(value, policy, parent)); + if (!value_ || !s.add(value_)) + return handle(); + } + return s.release(); + } + + PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name() + _("]")); +}; + +template struct map_caster { + using type = Type; + using key_conv = make_caster; + using value_conv = make_caster; + + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + auto d = reinterpret_borrow(src); + key_conv kconv; + value_conv vconv; + value.clear(); + for (auto it : d) { + if (!kconv.load(it.first.ptr(), convert) || + !vconv.load(it.second.ptr(), convert)) + return false; + value.emplace(cast_op(kconv), cast_op(vconv)); + } + return true; + } + + static handle cast(const type &src, return_value_policy policy, handle parent) { + dict d; + for (auto const &kv: src) { + auto key = reinterpret_steal(key_conv::cast(kv.first, policy, parent)); + auto value = reinterpret_steal(value_conv::cast(kv.second, policy, parent)); + if (!key || !value) + return handle(); + d[key] = value; + } + return d.release(); + } + + PYBIND11_TYPE_CASTER(type, _("Dict[") + key_conv::name() + _(", ") + value_conv::name() + _("]")); +}; + +template struct list_caster { + using type = Type; + using value_conv = make_caster; + + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + auto s = reinterpret_borrow(src); + value_conv conv; + value.clear(); + reserve_maybe(s, &value); + for (auto it : s) { + if (!conv.load(it, convert)) + return false; + value.push_back(cast_op(conv)); + } + return true; + } + + template ().reserve(0)), void>::value, int> = 0> + void reserve_maybe(sequence s, Type *) { value.reserve(s.size()); } + void reserve_maybe(sequence, void *) { } + + static handle cast(const Type &src, return_value_policy policy, handle parent) { + list l(src.size()); + size_t index = 0; + for (auto const &value: src) { + auto value_ = reinterpret_steal(value_conv::cast(value, policy, parent)); + if (!value_) + return handle(); + PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference + } + return l.release(); + } + + PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name() + _("]")); +}; + +template struct type_caster> + : list_caster, Type> { }; + +template struct type_caster> + : list_caster, Type> { }; + +template struct type_caster> { + using array_type = std::array; + using value_conv = make_caster; + + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + auto l = reinterpret_borrow(src); + if (l.size() != Size) + return false; + value_conv conv; + size_t ctr = 0; + for (auto it : l) { + if (!conv.load(it, convert)) + return false; + value[ctr++] = cast_op(conv); + } + return true; + } + + static handle cast(const array_type &src, return_value_policy policy, handle parent) { + list l(Size); + size_t index = 0; + for (auto const &value: src) { + auto value_ = reinterpret_steal(value_conv::cast(value, policy, parent)); + if (!value_) + return handle(); + PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference + } + return l.release(); + } + PYBIND11_TYPE_CASTER(array_type, _("List[") + value_conv::name() + _("[") + _() + _("]]")); +}; + +template struct type_caster> + : set_caster, Key> { }; + +template struct type_caster> + : set_caster, Key> { }; + +template struct type_caster> + : map_caster, Key, Value> { }; + +template struct type_caster> + : map_caster, Key, Value> { }; + +// This type caster is intended to be used for std::optional and std::experimental::optional +template struct optional_caster { + using value_conv = make_caster; + + static handle cast(const T& src, return_value_policy policy, handle parent) { + if (!src) + return none().inc_ref(); + return value_conv::cast(*src, policy, parent); + } + + bool load(handle src, bool convert) { + if (!src) { + return false; + } else if (src.is_none()) { + value = {}; // nullopt + return true; + } + value_conv inner_caster; + if (!inner_caster.load(src, convert)) + return false; + + value.emplace(cast_op(inner_caster)); + return true; + } + + PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name() + _("]")); +}; + +#if PYBIND11_HAS_OPTIONAL +template struct type_caster> + : public optional_caster> {}; + +template<> struct type_caster + : public void_caster {}; +#endif + +#if PYBIND11_HAS_EXP_OPTIONAL +template struct type_caster> + : public optional_caster> {}; + +template<> struct type_caster + : public void_caster {}; +#endif + +NAMESPACE_END(detail) + +inline std::ostream &operator<<(std::ostream &os, const handle &obj) { + os << (std::string) str(obj); + return os; +} + +NAMESPACE_END(pybind11) + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif diff --git a/resources/pybind11/include/pybind11/stl_bind.h b/resources/pybind11/include/pybind11/stl_bind.h new file mode 100755 index 0000000..ef9950e --- /dev/null +++ b/resources/pybind11/include/pybind11/stl_bind.h @@ -0,0 +1,541 @@ +/* + pybind11/std_bind.h: Binding generators for STL data types + + Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "common.h" +#include "operators.h" + +#include +#include + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) + +/* SFINAE helper class used by 'is_comparable */ +template struct container_traits { + template static std::true_type test_comparable(decltype(std::declval() == std::declval())*); + template static std::false_type test_comparable(...); + template static std::true_type test_value(typename T2::value_type *); + template static std::false_type test_value(...); + template static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *); + template static std::false_type test_pair(...); + + static constexpr const bool is_comparable = std::is_same(nullptr))>::value; + static constexpr const bool is_pair = std::is_same(nullptr, nullptr))>::value; + static constexpr const bool is_vector = std::is_same(nullptr))>::value; + static constexpr const bool is_element = !is_pair && !is_vector; +}; + +/* Default: is_comparable -> std::false_type */ +template +struct is_comparable : std::false_type { }; + +/* For non-map data structures, check whether operator== can be instantiated */ +template +struct is_comparable< + T, enable_if_t::is_element && + container_traits::is_comparable>> + : std::true_type { }; + +/* For a vector/map data structure, recursively check the value type (which is std::pair for maps) */ +template +struct is_comparable::is_vector>> { + static constexpr const bool value = + is_comparable::value; +}; + +/* For pairs, recursively check the two data types */ +template +struct is_comparable::is_pair>> { + static constexpr const bool value = + is_comparable::value && + is_comparable::value; +}; + +/* Fallback functions */ +template void vector_if_copy_constructible(const Args &...) { } +template void vector_if_equal_operator(const Args &...) { } +template void vector_if_insertion_operator(const Args &...) { } +template void vector_modifiers(const Args &...) { } + +template +void vector_if_copy_constructible(enable_if_t< + std::is_copy_constructible::value && + std::is_copy_constructible::value, Class_> &cl) { + + cl.def(pybind11::init(), "Copy constructor"); +} + +template +void vector_if_equal_operator(enable_if_t::value, Class_> &cl) { + using T = typename Vector::value_type; + + cl.def(self == self); + cl.def(self != self); + + cl.def("count", + [](const Vector &v, const T &x) { + return std::count(v.begin(), v.end(), x); + }, + arg("x"), + "Return the number of times ``x`` appears in the list" + ); + + cl.def("remove", [](Vector &v, const T &x) { + auto p = std::find(v.begin(), v.end(), x); + if (p != v.end()) + v.erase(p); + else + throw pybind11::value_error(); + }, + arg("x"), + "Remove the first item from the list whose value is x. " + "It is an error if there is no such item." + ); + + cl.def("__contains__", + [](const Vector &v, const T &x) { + return std::find(v.begin(), v.end(), x) != v.end(); + }, + arg("x"), + "Return true the container contains ``x``" + ); +} + +// Vector modifiers -- requires a copyable vector_type: +// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it seems +// silly to allow deletion but not insertion, so include them here too.) +template +void vector_modifiers(enable_if_t::value, Class_> &cl) { + using T = typename Vector::value_type; + using SizeType = typename Vector::size_type; + using DiffType = typename Vector::difference_type; + + cl.def("append", + [](Vector &v, const T &value) { v.push_back(value); }, + arg("x"), + "Add an item to the end of the list"); + + cl.def("__init__", [](Vector &v, iterable it) { + new (&v) Vector(); + try { + v.reserve(len(it)); + for (handle h : it) + v.push_back(h.cast()); + } catch (...) { + v.~Vector(); + throw; + } + }); + + cl.def("extend", + [](Vector &v, const Vector &src) { + v.reserve(v.size() + src.size()); + v.insert(v.end(), src.begin(), src.end()); + }, + arg("L"), + "Extend the list by appending all the items in the given list" + ); + + cl.def("insert", + [](Vector &v, SizeType i, const T &x) { + v.insert(v.begin() + (DiffType) i, x); + }, + arg("i") , arg("x"), + "Insert an item at a given position." + ); + + cl.def("pop", + [](Vector &v) { + if (v.empty()) + throw pybind11::index_error(); + T t = v.back(); + v.pop_back(); + return t; + }, + "Remove and return the last item" + ); + + cl.def("pop", + [](Vector &v, SizeType i) { + if (i >= v.size()) + throw pybind11::index_error(); + T t = v[i]; + v.erase(v.begin() + (DiffType) i); + return t; + }, + arg("i"), + "Remove and return the item at index ``i``" + ); + + cl.def("__setitem__", + [](Vector &v, SizeType i, const T &t) { + if (i >= v.size()) + throw pybind11::index_error(); + v[i] = t; + } + ); + + /// Slicing protocol + cl.def("__getitem__", + [](const Vector &v, slice slice) -> Vector * { + size_t start, stop, step, slicelength; + + if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) + throw pybind11::error_already_set(); + + Vector *seq = new Vector(); + seq->reserve((size_t) slicelength); + + for (size_t i=0; ipush_back(v[start]); + start += step; + } + return seq; + }, + arg("s"), + "Retrieve list elements using a slice object" + ); + + cl.def("__setitem__", + [](Vector &v, slice slice, const Vector &value) { + size_t start, stop, step, slicelength; + if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) + throw pybind11::error_already_set(); + + if (slicelength != value.size()) + throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); + + for (size_t i=0; i= v.size()) + throw pybind11::index_error(); + v.erase(v.begin() + DiffType(i)); + }, + "Delete the list elements at index ``i``" + ); + + cl.def("__delitem__", + [](Vector &v, slice slice) { + size_t start, stop, step, slicelength; + + if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) + throw pybind11::error_already_set(); + + if (step == 1 && false) { + v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength)); + } else { + for (size_t i = 0; i < slicelength; ++i) { + v.erase(v.begin() + DiffType(start)); + start += step - 1; + } + } + }, + "Delete list elements using a slice object" + ); + +} + +// If the type has an operator[] that doesn't return a reference (most notably std::vector), +// we have to access by copying; otherwise we return by reference. +template using vector_needs_copy = bool_constant< + !std::is_same()[typename Vector::size_type()]), typename Vector::value_type &>::value>; + +// The usual case: access and iterate by reference +template +void vector_accessor(enable_if_t::value, Class_> &cl) { + using T = typename Vector::value_type; + using SizeType = typename Vector::size_type; + using ItType = typename Vector::iterator; + + cl.def("__getitem__", + [](Vector &v, SizeType i) -> T & { + if (i >= v.size()) + throw pybind11::index_error(); + return v[i]; + }, + return_value_policy::reference_internal // ref + keepalive + ); + + cl.def("__iter__", + [](Vector &v) { + return pybind11::make_iterator< + return_value_policy::reference_internal, ItType, ItType, T&>( + v.begin(), v.end()); + }, + keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + ); +} + +// The case for special objects, like std::vector, that have to be returned-by-copy: +template +void vector_accessor(enable_if_t::value, Class_> &cl) { + using T = typename Vector::value_type; + using SizeType = typename Vector::size_type; + using ItType = typename Vector::iterator; + cl.def("__getitem__", + [](const Vector &v, SizeType i) -> T { + if (i >= v.size()) + throw pybind11::index_error(); + return v[i]; + } + ); + + cl.def("__iter__", + [](Vector &v) { + return pybind11::make_iterator< + return_value_policy::copy, ItType, ItType, T>( + v.begin(), v.end()); + }, + keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + ); +} + +template auto vector_if_insertion_operator(Class_ &cl, std::string const &name) + -> decltype(std::declval() << std::declval(), void()) { + using size_type = typename Vector::size_type; + + cl.def("__repr__", + [name](Vector &v) { + std::ostringstream s; + s << name << '['; + for (size_type i=0; i < v.size(); ++i) { + s << v[i]; + if (i != v.size() - 1) + s << ", "; + } + s << ']'; + return s.str(); + }, + "Return the canonical string representation of this list." + ); +} + +NAMESPACE_END(detail) + +// +// std::vector +// +template , typename... Args> +pybind11::class_ bind_vector(pybind11::module &m, std::string const &name, Args&&... args) { + using Class_ = pybind11::class_; + + Class_ cl(m, name.c_str(), std::forward(args)...); + + cl.def(pybind11::init<>()); + + // Register copy constructor (if possible) + detail::vector_if_copy_constructible(cl); + + // Register comparison-related operators and functions (if possible) + detail::vector_if_equal_operator(cl); + + // Register stream insertion operator (if possible) + detail::vector_if_insertion_operator(cl, name); + + // Modifiers require copyable vector value type + detail::vector_modifiers(cl); + + // Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive + detail::vector_accessor(cl); + + cl.def("__bool__", + [](const Vector &v) -> bool { + return !v.empty(); + }, + "Check whether the list is nonempty" + ); + + cl.def("__len__", &Vector::size); + + + + +#if 0 + // C++ style functions deprecated, leaving it here as an example + cl.def(pybind11::init()); + + cl.def("resize", + (void (Vector::*) (size_type count)) & Vector::resize, + "changes the number of elements stored"); + + cl.def("erase", + [](Vector &v, SizeType i) { + if (i >= v.size()) + throw pybind11::index_error(); + v.erase(v.begin() + i); + }, "erases element at index ``i``"); + + cl.def("empty", &Vector::empty, "checks whether the container is empty"); + cl.def("size", &Vector::size, "returns the number of elements"); + cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end"); + cl.def("pop_back", &Vector::pop_back, "removes the last element"); + + cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements"); + cl.def("reserve", &Vector::reserve, "reserves storage"); + cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage"); + cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory"); + + cl.def("clear", &Vector::clear, "clears the contents"); + cl.def("swap", &Vector::swap, "swaps the contents"); + + cl.def("front", [](Vector &v) { + if (v.size()) return v.front(); + else throw pybind11::index_error(); + }, "access the first element"); + + cl.def("back", [](Vector &v) { + if (v.size()) return v.back(); + else throw pybind11::index_error(); + }, "access the last element "); + +#endif + + return cl; +} + + + +// +// std::map, std::unordered_map +// + +NAMESPACE_BEGIN(detail) + +/* Fallback functions */ +template void map_if_insertion_operator(const Args &...) { } +template void map_assignment(const Args &...) { } + +// Map assignment when copy-assignable: just copy the value +template +void map_assignment(enable_if_t::value, Class_> &cl) { + using KeyType = typename Map::key_type; + using MappedType = typename Map::mapped_type; + + cl.def("__setitem__", + [](Map &m, const KeyType &k, const MappedType &v) { + auto it = m.find(k); + if (it != m.end()) it->second = v; + else m.emplace(k, v); + } + ); +} + +// Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting +template +void map_assignment(enable_if_t< + !std::is_copy_assignable::value && + std::is_copy_constructible::value, + Class_> &cl) { + using KeyType = typename Map::key_type; + using MappedType = typename Map::mapped_type; + + cl.def("__setitem__", + [](Map &m, const KeyType &k, const MappedType &v) { + // We can't use m[k] = v; because value type might not be default constructable + auto r = m.emplace(k, v); + if (!r.second) { + // value type is not copy assignable so the only way to insert it is to erase it first... + m.erase(r.first); + m.emplace(k, v); + } + } + ); +} + + +template auto map_if_insertion_operator(Class_ &cl, std::string const &name) +-> decltype(std::declval() << std::declval() << std::declval(), void()) { + + cl.def("__repr__", + [name](Map &m) { + std::ostringstream s; + s << name << '{'; + bool f = false; + for (auto const &kv : m) { + if (f) + s << ", "; + s << kv.first << ": " << kv.second; + f = true; + } + s << '}'; + return s.str(); + }, + "Return the canonical string representation of this map." + ); +} + + +NAMESPACE_END(detail) + +template , typename... Args> +pybind11::class_ bind_map(module &m, const std::string &name, Args&&... args) { + using KeyType = typename Map::key_type; + using MappedType = typename Map::mapped_type; + using Class_ = pybind11::class_; + + Class_ cl(m, name.c_str(), std::forward(args)...); + + cl.def(pybind11::init<>()); + + // Register stream insertion operator (if possible) + detail::map_if_insertion_operator(cl, name); + + cl.def("__bool__", + [](const Map &m) -> bool { return !m.empty(); }, + "Check whether the map is nonempty" + ); + + cl.def("__iter__", + [](Map &m) { return pybind11::make_key_iterator(m.begin(), m.end()); }, + pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + ); + + cl.def("items", + [](Map &m) { return pybind11::make_iterator(m.begin(), m.end()); }, + pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + ); + + cl.def("__getitem__", + [](Map &m, const KeyType &k) -> MappedType & { + auto it = m.find(k); + if (it == m.end()) + throw pybind11::key_error(); + return it->second; + }, + return_value_policy::reference_internal // ref + keepalive + ); + + // Assignment provided only if the type is copyable + detail::map_assignment(cl); + + cl.def("__delitem__", + [](Map &m, const KeyType &k) { + auto it = m.find(k); + if (it == m.end()) + throw pybind11::key_error(); + return m.erase(it); + } + ); + + cl.def("__len__", &Map::size); + + return cl; +} + +NAMESPACE_END(pybind11) diff --git a/resources/pybind11/include/pybind11/typeid.h b/resources/pybind11/include/pybind11/typeid.h new file mode 100755 index 0000000..c903fb1 --- /dev/null +++ b/resources/pybind11/include/pybind11/typeid.h @@ -0,0 +1,53 @@ +/* + pybind11/typeid.h: Compiler-independent access to type identifiers + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include +#include + +#if defined(__GNUG__) +#include +#endif + +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) +/// Erase all occurrences of a substring +inline void erase_all(std::string &string, const std::string &search) { + for (size_t pos = 0;;) { + pos = string.find(search, pos); + if (pos == std::string::npos) break; + string.erase(pos, search.length()); + } +} + +PYBIND11_NOINLINE inline void clean_type_id(std::string &name) { +#if defined(__GNUG__) + int status = 0; + std::unique_ptr res { + abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free }; + if (status == 0) + name = res.get(); +#else + detail::erase_all(name, "class "); + detail::erase_all(name, "struct "); + detail::erase_all(name, "enum "); +#endif + detail::erase_all(name, "pybind11::"); +} +NAMESPACE_END(detail) + +/// Return a string representation of a C++ type +template static std::string type_id() { + std::string name(typeid(T).name()); + detail::clean_type_id(name); + return name; +} + +NAMESPACE_END(pybind11) diff --git a/resources/pybind11/pybind11/__init__.py b/resources/pybind11/pybind11/__init__.py new file mode 100755 index 0000000..a765692 --- /dev/null +++ b/resources/pybind11/pybind11/__init__.py @@ -0,0 +1,11 @@ +from ._version import version_info, __version__ # noqa: F401 imported but unused + + +def get_include(*args, **kwargs): + import os + try: + from pip import locations + return os.path.dirname( + locations.distutils_scheme('pybind11', *args, **kwargs)['headers']) + except ImportError: + return 'include' diff --git a/resources/pybind11/pybind11/_version.py b/resources/pybind11/pybind11/_version.py new file mode 100755 index 0000000..be66f07 --- /dev/null +++ b/resources/pybind11/pybind11/_version.py @@ -0,0 +1,2 @@ +version_info = (1, 9, 'dev0') +__version__ = '.'.join(map(str, version_info)) diff --git a/resources/pybind11/setup.cfg b/resources/pybind11/setup.cfg new file mode 100755 index 0000000..89347b2 --- /dev/null +++ b/resources/pybind11/setup.cfg @@ -0,0 +1,11 @@ +[bdist_wheel] +universal=1 + +[flake8] +show_source = True +exclude = .git, __pycache__, build, dist, docs, tools, venv +ignore = + # line too long + E501, + # required for pretty matrix formating: multiple spaces after `,` and `[` + E201, E241 diff --git a/resources/pybind11/setup.py b/resources/pybind11/setup.py new file mode 100755 index 0000000..e9bc3c3 --- /dev/null +++ b/resources/pybind11/setup.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python + +# Setup script for PyPI; use CMakeFile.txt to build extension modules + +from setuptools import setup +from pybind11 import __version__ + +setup( + name='pybind11', + version=__version__, + description='Seamless operability between C++11 and Python', + author='Wenzel Jakob', + author_email='wenzel.jakob@epfl.ch', + url='https://github.com/wjakob/pybind11', + download_url='https://github.com/wjakob/pybind11/tarball/v' + __version__, + packages=['pybind11'], + license='BSD', + headers=[ + 'include/pybind11/attr.h', + 'include/pybind11/cast.h', + 'include/pybind11/chrono.h', + 'include/pybind11/common.h', + 'include/pybind11/complex.h', + 'include/pybind11/descr.h', + 'include/pybind11/eigen.h', + 'include/pybind11/eval.h', + 'include/pybind11/functional.h', + 'include/pybind11/numpy.h', + 'include/pybind11/operators.h', + 'include/pybind11/options.h', + 'include/pybind11/pybind11.h', + 'include/pybind11/pytypes.h', + 'include/pybind11/stl.h', + 'include/pybind11/stl_bind.h', + 'include/pybind11/typeid.h', + ], + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Topic :: Utilities', + 'Programming Language :: C++', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'License :: OSI Approved :: BSD License', + ], + keywords='C++11, Python bindings', + long_description="""pybind11 is a lightweight header library that exposes +C++ types in Python and vice versa, mainly to create Python bindings of +existing C++ code. Its goals and syntax are similar to the excellent +Boost.Python library by David Abrahams: to minimize boilerplate code in +traditional extension modules by inferring type information using compile-time +introspection. + +The main issue with Boost.Python-and the reason for creating such a similar +project-is Boost. Boost is an enormously large and complex suite of utility +libraries that works with almost every C++ compiler in existence. This +compatibility has its cost: arcane template tricks and workarounds are +necessary to support the oldest and buggiest of compiler specimens. Now that +C++11-compatible compilers are widely available, this heavy machinery has +become an excessively large and unnecessary dependency. + +Think of this library as a tiny self-contained version of Boost.Python with +everything stripped away that isn't relevant for binding generation. Without +comments, the core header files only require ~2.5K lines of code and depend 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 (specifically: +tuples, lambda functions and variadic templates). Since its creation, this +library has grown beyond Boost.Python in many ways, leading to dramatically +simpler binding code in many common situations.""") diff --git a/resources/pybind11/tests/CMakeLists.txt b/resources/pybind11/tests/CMakeLists.txt new file mode 100755 index 0000000..cb87fd8 --- /dev/null +++ b/resources/pybind11/tests/CMakeLists.txt @@ -0,0 +1,111 @@ +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting tests build type to MinSizeRel as none was specified") + set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" + "MinSizeRel" "RelWithDebInfo") +endif() + +# Full set of test files (you can override these; see below) +set(PYBIND11_TEST_FILES + test_alias_initialization.cpp + test_buffers.cpp + test_callbacks.cpp + test_chrono.cpp + test_class_args.cpp + test_constants_and_functions.cpp + test_copy_move_policies.cpp + test_docstring_options.cpp + test_eigen.cpp + test_enum.cpp + test_eval.cpp + test_exceptions.cpp + test_inheritance.cpp + test_issues.cpp + test_keep_alive.cpp + test_kwargs_and_defaults.cpp + test_methods_and_attributes.cpp + test_modules.cpp + test_multiple_inheritance.cpp + test_numpy_array.cpp + test_numpy_dtypes.cpp + test_numpy_vectorize.cpp + test_opaque_types.cpp + test_operator_overloading.cpp + test_pickling.cpp + test_python_types.cpp + test_sequences_and_iterators.cpp + test_smart_ptr.cpp + test_stl_binders.cpp + test_virtual_functions.cpp +) + +# Invoking cmake with something like: +# cmake -DPYBIND11_TEST_OVERRIDE="test_issues.cpp;test_picking.cpp" .. +# lets you override the tests that get compiled and run. You can restore to all tests with: +# cmake -DPYBIND11_TEST_OVERRIDE= .. +if (PYBIND11_TEST_OVERRIDE) + set(PYBIND11_TEST_FILES ${PYBIND11_TEST_OVERRIDE}) +endif() + +string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}") + +# Check if Eigen is available; if not, remove from PYBIND11_TEST_FILES (but +# keep it in PYBIND11_PYTEST_FILES, so that we get the "eigen is not installed" +# skip message). +list(FIND PYBIND11_TEST_FILES test_eigen.cpp PYBIND11_TEST_FILES_EIGEN_I) +if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1) + find_package(Eigen3 QUIET) + + if(EIGEN3_FOUND) + message(STATUS "Building tests with Eigen v${EIGEN3_VERSION}") + else() + list(REMOVE_AT PYBIND11_TEST_FILES ${PYBIND11_TEST_FILES_EIGEN_I}) + message(STATUS "Building tests WITHOUT Eigen") + endif() +endif() + +# Create the binding library +pybind11_add_module(pybind11_tests pybind11_tests.cpp + ${PYBIND11_TEST_FILES} ${PYBIND11_HEADERS}) + +pybind11_enable_warnings(pybind11_tests) + +if(EIGEN3_FOUND) + target_include_directories(pybind11_tests PRIVATE ${EIGEN3_INCLUDE_DIR}) + target_compile_definitions(pybind11_tests PRIVATE -DPYBIND11_TEST_EIGEN) +endif() + +set(testdir ${PROJECT_SOURCE_DIR}/tests) + +# Always write the output file directly into the 'tests' directory (even on MSVC) +if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) + set_target_properties(pybind11_tests PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${testdir}) + foreach(config ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${config} config) + set_target_properties(pybind11_tests PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} ${testdir}) + endforeach() +endif() + +# Make sure pytest is found or produce a fatal error +if(NOT PYBIND11_PYTEST_FOUND) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pytest --version --noconftest OUTPUT_QUIET ERROR_QUIET + RESULT_VARIABLE PYBIND11_EXEC_PYTHON_ERR) + if(PYBIND11_EXEC_PYTHON_ERR) + message(FATAL_ERROR "Running the tests requires pytest. Please install it manually (try: ${PYTHON_EXECUTABLE} -m pip install pytest)") + endif() + set(PYBIND11_PYTEST_FOUND TRUE CACHE INTERNAL "") +endif() + +# A single command to compile and run the tests +add_custom_target(pytest COMMAND ${PYTHON_EXECUTABLE} -m pytest -rws ${PYBIND11_PYTEST_FILES} + DEPENDS pybind11_tests WORKING_DIRECTORY ${testdir}) + +if(PYBIND11_TEST_OVERRIDE) + add_custom_command(TARGET pytest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "Note: not all tests run: -DPYBIND11_TEST_OVERRIDE is in effect") +endif() + +# And another to show the .so size and, if a previous size, compare it: +add_custom_command(TARGET pybind11_tests POST_BUILD + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/libsize.py + $ ${CMAKE_CURRENT_BINARY_DIR}/sosize-$.txt) diff --git a/resources/pybind11/tests/conftest.py b/resources/pybind11/tests/conftest.py new file mode 100755 index 0000000..d4335fc --- /dev/null +++ b/resources/pybind11/tests/conftest.py @@ -0,0 +1,227 @@ +"""pytest configuration + +Extends output capture as needed by pybind11: ignore constructors, optional unordered lines. +Adds docstring and exceptions message sanitizers: ignore Python 2 vs 3 differences. +""" + +import pytest +import textwrap +import difflib +import re +import sys +import contextlib + +_unicode_marker = re.compile(r'u(\'[^\']*\')') +_long_marker = re.compile(r'([0-9])L') +_hexadecimal = re.compile(r'0x[0-9a-fA-F]+') + + +def _strip_and_dedent(s): + """For triple-quote strings""" + return textwrap.dedent(s.lstrip('\n').rstrip()) + + +def _split_and_sort(s): + """For output which does not require specific line order""" + return sorted(_strip_and_dedent(s).splitlines()) + + +def _make_explanation(a, b): + """Explanation for a failed assert -- the a and b arguments are List[str]""" + return ["--- actual / +++ expected"] + [line.strip('\n') for line in difflib.ndiff(a, b)] + + +class Output(object): + """Basic output post-processing and comparison""" + def __init__(self, string): + self.string = string + self.explanation = [] + + def __str__(self): + return self.string + + def __eq__(self, other): + # Ignore constructor/destructor output which is prefixed with "###" + a = [line for line in self.string.strip().splitlines() if not line.startswith("###")] + b = _strip_and_dedent(other).splitlines() + if a == b: + return True + else: + self.explanation = _make_explanation(a, b) + return False + + +class Unordered(Output): + """Custom comparison for output without strict line ordering""" + def __eq__(self, other): + a = _split_and_sort(self.string) + b = _split_and_sort(other) + if a == b: + return True + else: + self.explanation = _make_explanation(a, b) + return False + + +class Capture(object): + def __init__(self, capfd): + self.capfd = capfd + self.out = "" + self.err = "" + + def __enter__(self): + self.capfd.readouterr() + return self + + def __exit__(self, *_): + self.out, self.err = self.capfd.readouterr() + + def __eq__(self, other): + a = Output(self.out) + b = other + if a == b: + return True + else: + self.explanation = a.explanation + return False + + def __str__(self): + return self.out + + def __contains__(self, item): + return item in self.out + + @property + def unordered(self): + return Unordered(self.out) + + @property + def stderr(self): + return Output(self.err) + + +@pytest.fixture +def capture(capfd): + """Extended `capfd` with context manager and custom equality operators""" + return Capture(capfd) + + +class SanitizedString(object): + def __init__(self, sanitizer): + self.sanitizer = sanitizer + self.string = "" + self.explanation = [] + + def __call__(self, thing): + self.string = self.sanitizer(thing) + return self + + def __eq__(self, other): + a = self.string + b = _strip_and_dedent(other) + if a == b: + return True + else: + self.explanation = _make_explanation(a.splitlines(), b.splitlines()) + return False + + +def _sanitize_general(s): + s = s.strip() + s = s.replace("pybind11_tests.", "m.") + s = s.replace("unicode", "str") + s = _long_marker.sub(r"\1", s) + s = _unicode_marker.sub(r"\1", s) + return s + + +def _sanitize_docstring(thing): + s = thing.__doc__ + s = _sanitize_general(s) + return s + + +@pytest.fixture +def doc(): + """Sanitize docstrings and add custom failure explanation""" + return SanitizedString(_sanitize_docstring) + + +def _sanitize_message(thing): + s = str(thing) + s = _sanitize_general(s) + s = _hexadecimal.sub("0", s) + return s + + +@pytest.fixture +def msg(): + """Sanitize messages and add custom failure explanation""" + return SanitizedString(_sanitize_message) + + +# noinspection PyUnusedLocal +def pytest_assertrepr_compare(op, left, right): + """Hook to insert custom failure explanation""" + if hasattr(left, 'explanation'): + return left.explanation + + +@contextlib.contextmanager +def suppress(exception): + """Suppress the desired exception""" + try: + yield + except exception: + pass + + +def pytest_namespace(): + """Add import suppression and test requirements to `pytest` namespace""" + try: + import numpy as np + except ImportError: + np = None + try: + import scipy + except ImportError: + scipy = None + try: + from pybind11_tests import have_eigen + except ImportError: + have_eigen = False + + skipif = pytest.mark.skipif + return { + 'suppress': suppress, + 'requires_numpy': skipif(not np, reason="numpy is not installed"), + 'requires_scipy': skipif(not np, reason="scipy is not installed"), + 'requires_eigen_and_numpy': skipif(not have_eigen or not np, + reason="eigen and/or numpy are not installed"), + 'requires_eigen_and_scipy': skipif(not have_eigen or not scipy, + reason="eigen and/or scipy are not installed"), + } + + +def _test_import_pybind11(): + """Early diagnostic for test module initialization errors + + When there is an error during initialization, the first import will report the + real error while all subsequent imports will report nonsense. This import test + is done early (in the pytest configuration file, before any tests) in order to + avoid the noise of having all tests fail with identical error messages. + + Any possible exception is caught here and reported manually *without* the stack + trace. This further reduces noise since the trace would only show pytest internals + which are not useful for debugging pybind11 module issues. + """ + # noinspection PyBroadException + try: + import pybind11_tests # noqa: F401 imported but unused + except Exception as e: + print("Failed to import pybind11_tests from pytest:") + print(" {}: {}".format(type(e).__name__, e)) + sys.exit(1) + + +_test_import_pybind11() diff --git a/resources/pybind11/tests/constructor_stats.h b/resources/pybind11/tests/constructor_stats.h new file mode 100755 index 0000000..eb3e49c --- /dev/null +++ b/resources/pybind11/tests/constructor_stats.h @@ -0,0 +1,249 @@ +#pragma once +/* + tests/constructor_stats.h -- framework for printing and tracking object + instance lifetimes in example/test code. + + Copyright (c) 2016 Jason Rhinelander + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. + +This header provides a few useful tools for writing examples or tests that want to check and/or +display object instance lifetimes. It requires that you include this header and add the following +function calls to constructors: + + class MyClass { + MyClass() { ...; print_default_created(this); } + ~MyClass() { ...; print_destroyed(this); } + MyClass(const MyClass &c) { ...; print_copy_created(this); } + MyClass(MyClass &&c) { ...; print_move_created(this); } + MyClass(int a, int b) { ...; print_created(this, a, b); } + MyClass &operator=(const MyClass &c) { ...; print_copy_assigned(this); } + MyClass &operator=(MyClass &&c) { ...; print_move_assigned(this); } + + ... + } + +You can find various examples of these in several of the existing example .cpp files. (Of course +you don't need to add any of the above constructors/operators that you don't actually have, except +for the destructor). + +Each of these will print an appropriate message such as: + + ### MyClass @ 0x2801910 created via default constructor + ### MyClass @ 0x27fa780 created 100 200 + ### MyClass @ 0x2801910 destroyed + ### MyClass @ 0x27fa780 destroyed + +You can also include extra arguments (such as the 100, 200 in the output above, coming from the +value constructor) for all of the above methods which will be included in the output. + +For testing, each of these also keeps track the created instances and allows you to check how many +of the various constructors have been invoked from the Python side via code such as: + + from example import ConstructorStats + cstats = ConstructorStats.get(MyClass) + print(cstats.alive()) + print(cstats.default_constructions) + +Note that `.alive()` should usually be the first thing you call as it invokes Python's garbage +collector to actually destroy objects that aren't yet referenced. + +For everything except copy and move constructors and destructors, any extra values given to the +print_...() function is stored in a class-specific values list which you can retrieve and inspect +from the ConstructorStats instance `.values()` method. + +In some cases, when you need to track instances of a C++ class not registered with pybind11, you +need to add a function returning the ConstructorStats for the C++ class; this can be done with: + + m.def("get_special_cstats", &ConstructorStats::get, py::return_value_policy::reference) + +Finally, you can suppress the output messages, but keep the constructor tracking (for +inspection/testing in python) by using the functions with `print_` replaced with `track_` (e.g. +`track_copy_created(this)`). + +*/ + +#include "pybind11_tests.h" +#include +#include +#include +#include + +class ConstructorStats { +protected: + std::unordered_map _instances; // Need a map rather than set because members can shared address with parents + std::list _values; // Used to track values (e.g. of value constructors) +public: + int default_constructions = 0; + int copy_constructions = 0; + int move_constructions = 0; + int copy_assignments = 0; + int move_assignments = 0; + + void copy_created(void *inst) { + created(inst); + copy_constructions++; + } + void move_created(void *inst) { + created(inst); + move_constructions++; + } + void default_created(void *inst) { + created(inst); + default_constructions++; + } + void created(void *inst) { + ++_instances[inst]; + }; + void destroyed(void *inst) { + if (--_instances[inst] < 0) + throw std::runtime_error("cstats.destroyed() called with unknown instance; potential double-destruction or a missing cstats.created()"); + } + + int alive() { + // Force garbage collection to ensure any pending destructors are invoked: + py::module::import("gc").attr("collect")(); + int total = 0; + for (const auto &p : _instances) if (p.second > 0) total += p.second; + return total; + } + + void value() {} // Recursion terminator + // Takes one or more values, converts them to strings, then stores them. + template void value(const T &v, Tmore &&...args) { + std::ostringstream oss; + oss << v; + _values.push_back(oss.str()); + value(std::forward(args)...); + } + + // Move out stored values + py::list values() { + py::list l; + for (const auto &v : _values) l.append(py::cast(v)); + _values.clear(); + return l; + } + + // Gets constructor stats from a C++ type index + static ConstructorStats& get(std::type_index type) { + static std::unordered_map all_cstats; + return all_cstats[type]; + } + + // Gets constructor stats from a C++ type + template static ConstructorStats& get() { + return get(typeid(T)); + } + + // Gets constructor stats from a Python class + static ConstructorStats& get(py::object class_) { + auto &internals = py::detail::get_internals(); + const std::type_index *t1 = nullptr, *t2 = nullptr; + try { + auto *type_info = internals.registered_types_py.at(class_.ptr()); + for (auto &p : internals.registered_types_cpp) { + if (p.second == type_info) { + if (t1) { + t2 = &p.first; + break; + } + t1 = &p.first; + } + } + } + catch (std::out_of_range) {} + if (!t1) throw std::runtime_error("Unknown class passed to ConstructorStats::get()"); + auto &cs1 = get(*t1); + // If we have both a t1 and t2 match, one is probably the trampoline class; return whichever + // has more constructions (typically one or the other will be 0) + if (t2) { + auto &cs2 = get(*t2); + int cs1_total = cs1.default_constructions + cs1.copy_constructions + cs1.move_constructions + (int) cs1._values.size(); + int cs2_total = cs2.default_constructions + cs2.copy_constructions + cs2.move_constructions + (int) cs2._values.size(); + if (cs2_total > cs1_total) return cs2; + } + return cs1; + } +}; + +// To track construction/destruction, you need to call these methods from the various +// constructors/operators. The ones that take extra values record the given values in the +// constructor stats values for later inspection. +template void track_copy_created(T *inst) { ConstructorStats::get().copy_created(inst); } +template void track_move_created(T *inst) { ConstructorStats::get().move_created(inst); } +template void track_copy_assigned(T *, Values &&...values) { + auto &cst = ConstructorStats::get(); + cst.copy_assignments++; + cst.value(std::forward(values)...); +} +template void track_move_assigned(T *, Values &&...values) { + auto &cst = ConstructorStats::get(); + cst.move_assignments++; + cst.value(std::forward(values)...); +} +template void track_default_created(T *inst, Values &&...values) { + auto &cst = ConstructorStats::get(); + cst.default_created(inst); + cst.value(std::forward(values)...); +} +template void track_created(T *inst, Values &&...values) { + auto &cst = ConstructorStats::get(); + cst.created(inst); + cst.value(std::forward(values)...); +} +template void track_destroyed(T *inst) { + ConstructorStats::get().destroyed(inst); +} +template void track_values(T *, Values &&...values) { + ConstructorStats::get().value(std::forward(values)...); +} + +/// Don't cast pointers to Python, print them as strings +inline const char *format_ptrs(const char *p) { return p; } +template +py::str format_ptrs(T *p) { return "{:#x}"_s.format(reinterpret_cast(p)); } +template +auto format_ptrs(T &&x) -> decltype(std::forward(x)) { return std::forward(x); } + +template +void print_constr_details(T *inst, const std::string &action, Output &&...output) { + py::print("###", py::type_id(), "@", format_ptrs(inst), action, + format_ptrs(std::forward(output))...); +} + +// Verbose versions of the above: +template void print_copy_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values + print_constr_details(inst, "created via copy constructor", values...); + track_copy_created(inst); +} +template void print_move_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values + print_constr_details(inst, "created via move constructor", values...); + track_move_created(inst); +} +template void print_copy_assigned(T *inst, Values &&...values) { + print_constr_details(inst, "assigned via copy assignment", values...); + track_copy_assigned(inst, values...); +} +template void print_move_assigned(T *inst, Values &&...values) { + print_constr_details(inst, "assigned via move assignment", values...); + track_move_assigned(inst, values...); +} +template void print_default_created(T *inst, Values &&...values) { + print_constr_details(inst, "created via default constructor", values...); + track_default_created(inst, values...); +} +template void print_created(T *inst, Values &&...values) { + print_constr_details(inst, "created", values...); + track_created(inst, values...); +} +template void print_destroyed(T *inst, Values &&...values) { // Prints but doesn't store given values + print_constr_details(inst, "destroyed", values...); + track_destroyed(inst); +} +template void print_values(T *inst, Values &&...values) { + print_constr_details(inst, ":", values...); + track_values(inst, values...); +} + diff --git a/resources/pybind11/tests/object.h b/resources/pybind11/tests/object.h new file mode 100755 index 0000000..753f654 --- /dev/null +++ b/resources/pybind11/tests/object.h @@ -0,0 +1,175 @@ +#if !defined(__OBJECT_H) +#define __OBJECT_H + +#include +#include "constructor_stats.h" + +/// Reference counted object base class +class Object { +public: + /// Default constructor + Object() { print_default_created(this); } + + /// Copy constructor + Object(const Object &) : m_refCount(0) { print_copy_created(this); } + + /// Return the current reference count + int getRefCount() const { return m_refCount; }; + + /// Increase the object's reference count by one + void incRef() const { ++m_refCount; } + + /** \brief Decrease the reference count of + * the object and possibly deallocate it. + * + * The object will automatically be deallocated once + * the reference count reaches zero. + */ + void decRef(bool dealloc = true) const { + --m_refCount; + if (m_refCount == 0 && dealloc) + delete this; + else if (m_refCount < 0) + throw std::runtime_error("Internal error: reference count < 0!"); + } + + virtual std::string toString() const = 0; +protected: + /** \brief Virtual protected deconstructor. + * (Will only be called by \ref ref) + */ + virtual ~Object() { print_destroyed(this); } +private: + mutable std::atomic m_refCount { 0 }; +}; + +// Tag class used to track constructions of ref objects. When we track constructors, below, we +// track and print out the actual class (e.g. ref), and *also* add a fake tracker for +// ref_tag. This lets us check that the total number of ref constructors/destructors is +// correct without having to check each individual ref type individually. +class ref_tag {}; + +/** + * \brief Reference counting helper + * + * The \a ref refeference template is a simple wrapper to store a + * pointer to an object. It takes care of increasing and decreasing + * the reference count of the object. When the last reference goes + * out of scope, the associated object will be deallocated. + * + * \ingroup libcore + */ +template class ref { +public: + /// Create a nullptr reference + ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); } + + /// Construct a reference from a pointer + ref(T *ptr) : m_ptr(ptr) { + if (m_ptr) ((Object *) m_ptr)->incRef(); + + print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer"); + + } + + /// Copy constructor + ref(const ref &r) : m_ptr(r.m_ptr) { + if (m_ptr) + ((Object *) m_ptr)->incRef(); + + print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this); + } + + /// Move constructor + ref(ref &&r) : m_ptr(r.m_ptr) { + r.m_ptr = nullptr; + + print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this); + } + + /// Destroy this reference + ~ref() { + if (m_ptr) + ((Object *) m_ptr)->decRef(); + + print_destroyed(this); track_destroyed((ref_tag*) this); + } + + /// Move another reference into the current one + ref& operator=(ref&& r) { + print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this); + + if (*this == r) + return *this; + if (m_ptr) + ((Object *) m_ptr)->decRef(); + m_ptr = r.m_ptr; + r.m_ptr = nullptr; + return *this; + } + + /// Overwrite this reference with another reference + ref& operator=(const ref& r) { + print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag*) this); + + if (m_ptr == r.m_ptr) + return *this; + if (m_ptr) + ((Object *) m_ptr)->decRef(); + m_ptr = r.m_ptr; + if (m_ptr) + ((Object *) m_ptr)->incRef(); + return *this; + } + + /// Overwrite this reference with a pointer to another object + ref& operator=(T *ptr) { + print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer"); + + if (m_ptr == ptr) + return *this; + if (m_ptr) + ((Object *) m_ptr)->decRef(); + m_ptr = ptr; + if (m_ptr) + ((Object *) m_ptr)->incRef(); + return *this; + } + + /// Compare this reference with another reference + bool operator==(const ref &r) const { return m_ptr == r.m_ptr; } + + /// Compare this reference with another reference + bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; } + + /// Compare this reference with a pointer + bool operator==(const T* ptr) const { return m_ptr == ptr; } + + /// Compare this reference with a pointer + bool operator!=(const T* ptr) const { return m_ptr != ptr; } + + /// Access the object referenced by this reference + T* operator->() { return m_ptr; } + + /// Access the object referenced by this reference + const T* operator->() const { return m_ptr; } + + /// Return a C++ reference to the referenced object + T& operator*() { return *m_ptr; } + + /// Return a const C++ reference to the referenced object + const T& operator*() const { return *m_ptr; } + + /// Return a pointer to the referenced object + operator T* () { return m_ptr; } + + /// Return a const pointer to the referenced object + T* get() { return m_ptr; } + + /// Return a pointer to the referenced object + const T* get() const { return m_ptr; } +private: + T *m_ptr; +}; + +#endif /* __OBJECT_H */ diff --git a/resources/pybind11/tests/pybind11_tests.cpp b/resources/pybind11/tests/pybind11_tests.cpp new file mode 100755 index 0000000..35981a0 --- /dev/null +++ b/resources/pybind11/tests/pybind11_tests.cpp @@ -0,0 +1,45 @@ +/* + tests/pybind11_tests.cpp -- pybind example plugin + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" + +std::list> &initializers() { + static std::list> inits; + return inits; +} + +test_initializer::test_initializer(std::function initializer) { + initializers().push_back(std::move(initializer)); +} + +void bind_ConstructorStats(py::module &m) { + py::class_(m, "ConstructorStats") + .def("alive", &ConstructorStats::alive) + .def("values", &ConstructorStats::values) + .def_readwrite("default_constructions", &ConstructorStats::default_constructions) + .def_readwrite("copy_assignments", &ConstructorStats::copy_assignments) + .def_readwrite("move_assignments", &ConstructorStats::move_assignments) + .def_readwrite("copy_constructions", &ConstructorStats::copy_constructions) + .def_readwrite("move_constructions", &ConstructorStats::move_constructions) + .def_static("get", (ConstructorStats &(*)(py::object)) &ConstructorStats::get, py::return_value_policy::reference_internal); +} + +PYBIND11_PLUGIN(pybind11_tests) { + py::module m("pybind11_tests", "pybind example plugin"); + + bind_ConstructorStats(m); + + for (const auto &initializer : initializers()) + initializer(m); + + if (!py::hasattr(m, "have_eigen")) m.attr("have_eigen") = py::cast(false); + + return m.ptr(); +} diff --git a/resources/pybind11/tests/pybind11_tests.h b/resources/pybind11/tests/pybind11_tests.h new file mode 100755 index 0000000..c11b687 --- /dev/null +++ b/resources/pybind11/tests/pybind11_tests.h @@ -0,0 +1,12 @@ +#pragma once +#include +#include +#include + +namespace py = pybind11; +using namespace pybind11::literals; + +class test_initializer { +public: + test_initializer(std::function initializer); +}; diff --git a/resources/pybind11/tests/test_alias_initialization.cpp b/resources/pybind11/tests/test_alias_initialization.cpp new file mode 100755 index 0000000..48e5956 --- /dev/null +++ b/resources/pybind11/tests/test_alias_initialization.cpp @@ -0,0 +1,62 @@ +/* + tests/test_alias_initialization.cpp -- test cases and example of different trampoline + initialization modes + + Copyright (c) 2016 Wenzel Jakob , Jason Rhinelander + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +test_initializer alias_initialization([](py::module &m) { + // don't invoke Python dispatch classes by default when instantiating C++ classes that were not + // extended on the Python side + struct A { + virtual ~A() {} + virtual void f() { py::print("A.f()"); } + }; + + struct PyA : A { + PyA() { py::print("PyA.PyA()"); } + ~PyA() { py::print("PyA.~PyA()"); } + + void f() override { + py::print("PyA.f()"); + PYBIND11_OVERLOAD(void, A, f); + } + }; + + auto call_f = [](A *a) { a->f(); }; + + py::class_(m, "A") + .def(py::init<>()) + .def("f", &A::f); + + m.def("call_f", call_f); + + + // ... unless we explicitly request it, as in this example: + struct A2 { + virtual ~A2() {} + virtual void f() { py::print("A2.f()"); } + }; + + struct PyA2 : A2 { + PyA2() { py::print("PyA2.PyA2()"); } + ~PyA2() { py::print("PyA2.~PyA2()"); } + void f() override { + py::print("PyA2.f()"); + PYBIND11_OVERLOAD(void, A2, f); + } + }; + + py::class_(m, "A2") + .def(py::init_alias<>()) + .def("f", &A2::f); + + m.def("call_f", [](A2 *a2) { a2->f(); }); + +}); + diff --git a/resources/pybind11/tests/test_alias_initialization.py b/resources/pybind11/tests/test_alias_initialization.py new file mode 100755 index 0000000..0ed9d2f --- /dev/null +++ b/resources/pybind11/tests/test_alias_initialization.py @@ -0,0 +1,79 @@ +import gc + + +def test_alias_delay_initialization1(capture): + """A only initializes its trampoline class when we inherit from it; if we just + create and use an A instance directly, the trampoline initialization is bypassed + and we only initialize an A() instead (for performance reasons). + """ + from pybind11_tests import A, call_f + + class B(A): + def __init__(self): + super(B, self).__init__() + + def f(self): + print("In python f()") + + # C++ version + with capture: + a = A() + call_f(a) + del a + gc.collect() + assert capture == "A.f()" + + # Python version + with capture: + b = B() + call_f(b) + del b + gc.collect() + assert capture == """ + PyA.PyA() + PyA.f() + In python f() + PyA.~PyA() + """ + + +def test_alias_delay_initialization2(capture): + """A2, unlike the above, is configured to always initialize the alias; while + the extra initialization and extra class layer has small virtual dispatch + performance penalty, it also allows us to do more things with the trampoline + class such as defining local variables and performing construction/destruction. + """ + from pybind11_tests import A2, call_f + + class B2(A2): + def __init__(self): + super(B2, self).__init__() + + def f(self): + print("In python B2.f()") + + # No python subclass version + with capture: + a2 = A2() + call_f(a2) + del a2 + gc.collect() + assert capture == """ + PyA2.PyA2() + PyA2.f() + A2.f() + PyA2.~PyA2() + """ + + # Python subclass version + with capture: + b2 = B2() + call_f(b2) + del b2 + gc.collect() + assert capture == """ + PyA2.PyA2() + PyA2.f() + In python B2.f() + PyA2.~PyA2() + """ diff --git a/resources/pybind11/tests/test_buffers.cpp b/resources/pybind11/tests/test_buffers.cpp new file mode 100755 index 0000000..c3a7a9e --- /dev/null +++ b/resources/pybind11/tests/test_buffers.cpp @@ -0,0 +1,117 @@ +/* + tests/test_buffers.cpp -- supporting Pythons' buffer protocol + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" + +class Matrix { +public: + Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) { + print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); + m_data = new float[rows*cols]; + memset(m_data, 0, sizeof(float) * rows * cols); + } + + Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) { + print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); + m_data = new float[m_rows * m_cols]; + memcpy(m_data, s.m_data, sizeof(float) * m_rows * m_cols); + } + + Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) { + print_move_created(this); + s.m_rows = 0; + s.m_cols = 0; + s.m_data = nullptr; + } + + ~Matrix() { + print_destroyed(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); + delete[] m_data; + } + + Matrix &operator=(const Matrix &s) { + print_copy_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); + delete[] m_data; + m_rows = s.m_rows; + m_cols = s.m_cols; + m_data = new float[m_rows * m_cols]; + memcpy(m_data, s.m_data, sizeof(float) * m_rows * m_cols); + return *this; + } + + Matrix &operator=(Matrix &&s) { + print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); + if (&s != this) { + delete[] m_data; + m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data; + s.m_rows = 0; s.m_cols = 0; s.m_data = nullptr; + } + return *this; + } + + float operator()(size_t i, size_t j) const { + return m_data[i*m_cols + j]; + } + + float &operator()(size_t i, size_t j) { + return m_data[i*m_cols + j]; + } + + float *data() { return m_data; } + + size_t rows() const { return m_rows; } + size_t cols() const { return m_cols; } +private: + size_t m_rows; + size_t m_cols; + float *m_data; +}; + +test_initializer buffers([](py::module &m) { + py::class_ mtx(m, "Matrix"); + + mtx.def(py::init()) + /// Construct from a buffer + .def("__init__", [](Matrix &v, py::buffer b) { + py::buffer_info info = b.request(); + if (info.format != py::format_descriptor::format() || info.ndim != 2) + throw std::runtime_error("Incompatible buffer format!"); + new (&v) Matrix(info.shape[0], info.shape[1]); + memcpy(v.data(), info.ptr, sizeof(float) * v.rows() * v.cols()); + }) + + .def("rows", &Matrix::rows) + .def("cols", &Matrix::cols) + + /// Bare bones interface + .def("__getitem__", [](const Matrix &m, std::pair i) { + if (i.first >= m.rows() || i.second >= m.cols()) + throw py::index_error(); + return m(i.first, i.second); + }) + .def("__setitem__", [](Matrix &m, std::pair i, float v) { + if (i.first >= m.rows() || i.second >= m.cols()) + throw py::index_error(); + m(i.first, i.second) = v; + }) + /// Provide buffer access + .def_buffer([](Matrix &m) -> py::buffer_info { + return py::buffer_info( + m.data(), /* Pointer to buffer */ + sizeof(float), /* Size of one scalar */ + py::format_descriptor::format(), /* Python struct-style format descriptor */ + 2, /* Number of dimensions */ + { m.rows(), m.cols() }, /* Buffer dimensions */ + { sizeof(float) * m.rows(), /* Strides (in bytes) for each index */ + sizeof(float) } + ); + }) + ; +}); diff --git a/resources/pybind11/tests/test_buffers.py b/resources/pybind11/tests/test_buffers.py new file mode 100755 index 0000000..f0ea964 --- /dev/null +++ b/resources/pybind11/tests/test_buffers.py @@ -0,0 +1,57 @@ +import pytest +from pybind11_tests import Matrix, ConstructorStats + +with pytest.suppress(ImportError): + import numpy as np + + +@pytest.requires_numpy +def test_to_python(): + m = Matrix(5, 5) + + assert m[2, 3] == 0 + m[2, 3] = 4 + assert m[2, 3] == 4 + + m2 = np.array(m, copy=False) + assert m2.shape == (5, 5) + assert abs(m2).sum() == 4 + assert m2[2, 3] == 4 + m2[2, 3] = 5 + assert m2[2, 3] == 5 + + cstats = ConstructorStats.get(Matrix) + assert cstats.alive() == 1 + del m + assert cstats.alive() == 1 + del m2 # holds an m reference + assert cstats.alive() == 0 + assert cstats.values() == ["5x5 matrix"] + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Don't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + +@pytest.requires_numpy +def test_from_python(): + with pytest.raises(RuntimeError) as excinfo: + Matrix(np.array([1, 2, 3])) # trying to assign a 1D array + assert str(excinfo.value) == "Incompatible buffer format!" + + m3 = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) + m4 = Matrix(m3) + + for i in range(m4.rows()): + for j in range(m4.cols()): + assert m3[i, j] == m4[i, j] + + cstats = ConstructorStats.get(Matrix) + assert cstats.alive() == 1 + del m3, m4 + assert cstats.alive() == 0 + assert cstats.values() == ["2x3 matrix"] + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Don't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 diff --git a/resources/pybind11/tests/test_callbacks.cpp b/resources/pybind11/tests/test_callbacks.cpp new file mode 100755 index 0000000..31d4e39 --- /dev/null +++ b/resources/pybind11/tests/test_callbacks.cpp @@ -0,0 +1,149 @@ +/* + tests/test_callbacks.cpp -- callbacks + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include + + +py::object test_callback1(py::object func) { + return func(); +} + +py::tuple test_callback2(py::object func) { + return func("Hello", 'x', true, 5); +} + +std::string test_callback3(const std::function &func) { + return "func(43) = " + std::to_string(func(43)); +} + +std::function test_callback4() { + return [](int i) { return i+1; }; +} + +py::cpp_function test_callback5() { + return py::cpp_function([](int i) { return i+1; }, + py::arg("number")); +} + +int dummy_function(int i) { return i + 1; } +int dummy_function2(int i, int j) { return i + j; } +std::function roundtrip(std::function f, bool expect_none = false) { + if (expect_none && f) { + throw std::runtime_error("Expected None to be converted to empty std::function"); + } + return f; +} + +std::string test_dummy_function(const std::function &f) { + using fn_type = int (*)(int); + auto result = f.target(); + if (!result) { + auto r = f(1); + return "can't convert to function pointer: eval(1) = " + std::to_string(r); + } else if (*result == dummy_function) { + auto r = (*result)(1); + return "matches dummy_function: eval(1) = " + std::to_string(r); + } else { + return "argument does NOT match dummy_function. This should never happen!"; + } +} + +struct Payload { + Payload() { + print_default_created(this); + } + ~Payload() { + print_destroyed(this); + } + Payload(const Payload &) { + print_copy_created(this); + } + Payload(Payload &&) { + print_move_created(this); + } +}; + +/// Something to trigger a conversion error +struct Unregistered {}; + +test_initializer callbacks([](py::module &m) { + m.def("test_callback1", &test_callback1); + m.def("test_callback2", &test_callback2); + m.def("test_callback3", &test_callback3); + m.def("test_callback4", &test_callback4); + m.def("test_callback5", &test_callback5); + + // Test keyword args and generalized unpacking + m.def("test_tuple_unpacking", [](py::function f) { + auto t1 = py::make_tuple(2, 3); + auto t2 = py::make_tuple(5, 6); + return f("positional", 1, *t1, 4, *t2); + }); + + m.def("test_dict_unpacking", [](py::function f) { + auto d1 = py::dict("key"_a="value", "a"_a=1); + auto d2 = py::dict(); + auto d3 = py::dict("b"_a=2); + return f("positional", 1, **d1, **d2, **d3); + }); + + m.def("test_keyword_args", [](py::function f) { + return f("x"_a=10, "y"_a=20); + }); + + m.def("test_unpacking_and_keywords1", [](py::function f) { + auto args = py::make_tuple(2); + auto kwargs = py::dict("d"_a=4); + return f(1, *args, "c"_a=3, **kwargs); + }); + + m.def("test_unpacking_and_keywords2", [](py::function f) { + auto kwargs1 = py::dict("a"_a=1); + auto kwargs2 = py::dict("c"_a=3, "d"_a=4); + return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5, + "key"_a="value", **kwargs1, "b"_a=2, **kwargs2, "e"_a=5); + }); + + m.def("test_unpacking_error1", [](py::function f) { + auto kwargs = py::dict("x"_a=3); + return f("x"_a=1, "y"_a=2, **kwargs); // duplicate ** after keyword + }); + + m.def("test_unpacking_error2", [](py::function f) { + auto kwargs = py::dict("x"_a=3); + return f(**kwargs, "x"_a=1); // duplicate keyword after ** + }); + + m.def("test_arg_conversion_error1", [](py::function f) { + f(234, Unregistered(), "kw"_a=567); + }); + + m.def("test_arg_conversion_error2", [](py::function f) { + f(234, "expected_name"_a=Unregistered(), "kw"_a=567); + }); + + /* Test cleanup of lambda closure */ + m.def("test_cleanup", []() -> std::function { + Payload p; + + return [p]() { + /* p should be cleaned up when the returned function is garbage collected */ + }; + }); + + /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */ + m.def("dummy_function", &dummy_function); + m.def("dummy_function2", &dummy_function2); + m.def("roundtrip", &roundtrip, py::arg("f"), py::arg("expect_none")=false); + m.def("test_dummy_function", &test_dummy_function); + // Export the payload constructor statistics for testing purposes: + m.def("payload_cstats", &ConstructorStats::get); +}); diff --git a/resources/pybind11/tests/test_callbacks.py b/resources/pybind11/tests/test_callbacks.py new file mode 100755 index 0000000..c2668aa --- /dev/null +++ b/resources/pybind11/tests/test_callbacks.py @@ -0,0 +1,98 @@ +import pytest + + +def test_callbacks(): + from functools import partial + from pybind11_tests import (test_callback1, test_callback2, test_callback3, + test_callback4, test_callback5) + + def func1(): + return "func1" + + def func2(a, b, c, d): + return "func2", a, b, c, d + + def func3(a): + return "func3({})".format(a) + + assert test_callback1(func1) == "func1" + assert test_callback2(func2) == ("func2", "Hello", "x", True, 5) + assert test_callback1(partial(func2, 1, 2, 3, 4)) == ("func2", 1, 2, 3, 4) + assert test_callback1(partial(func3, "partial")) == "func3(partial)" + assert test_callback3(lambda i: i + 1) == "func(43) = 44" + + f = test_callback4() + assert f(43) == 44 + f = test_callback5() + assert f(number=43) == 44 + + +def test_keyword_args_and_generalized_unpacking(): + from pybind11_tests import (test_tuple_unpacking, test_dict_unpacking, test_keyword_args, + test_unpacking_and_keywords1, test_unpacking_and_keywords2, + test_unpacking_error1, test_unpacking_error2, + test_arg_conversion_error1, test_arg_conversion_error2) + + def f(*args, **kwargs): + return args, kwargs + + assert test_tuple_unpacking(f) == (("positional", 1, 2, 3, 4, 5, 6), {}) + assert test_dict_unpacking(f) == (("positional", 1), {"key": "value", "a": 1, "b": 2}) + assert test_keyword_args(f) == ((), {"x": 10, "y": 20}) + assert test_unpacking_and_keywords1(f) == ((1, 2), {"c": 3, "d": 4}) + assert test_unpacking_and_keywords2(f) == ( + ("positional", 1, 2, 3, 4, 5), + {"key": "value", "a": 1, "b": 2, "c": 3, "d": 4, "e": 5} + ) + + with pytest.raises(TypeError) as excinfo: + test_unpacking_error1(f) + assert "Got multiple values for keyword argument" in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + test_unpacking_error2(f) + assert "Got multiple values for keyword argument" in str(excinfo.value) + + with pytest.raises(RuntimeError) as excinfo: + test_arg_conversion_error1(f) + assert "Unable to convert call argument" in str(excinfo.value) + + with pytest.raises(RuntimeError) as excinfo: + test_arg_conversion_error2(f) + assert "Unable to convert call argument" in str(excinfo.value) + + +def test_lambda_closure_cleanup(): + from pybind11_tests import test_cleanup, payload_cstats + + test_cleanup() + cstats = payload_cstats() + assert cstats.alive() == 0 + assert cstats.copy_constructions == 1 + assert cstats.move_constructions >= 1 + + +def test_cpp_function_roundtrip(): + """Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer""" + from pybind11_tests import dummy_function, dummy_function2, test_dummy_function, roundtrip + + assert test_dummy_function(dummy_function) == "matches dummy_function: eval(1) = 2" + assert test_dummy_function(roundtrip(dummy_function)) == "matches dummy_function: eval(1) = 2" + assert roundtrip(None, expect_none=True) is None + assert test_dummy_function(lambda x: x + 2) == "can't convert to function pointer: eval(1) = 3" + + with pytest.raises(TypeError) as excinfo: + test_dummy_function(dummy_function2) + assert "incompatible function arguments" in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + test_dummy_function(lambda x, y: x + y) + assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument", + "takes exactly 2 arguments")) + + +def test_function_signatures(doc): + from pybind11_tests import test_callback3, test_callback4 + + assert doc(test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str" + assert doc(test_callback4) == "test_callback4() -> Callable[[int], int]" diff --git a/resources/pybind11/tests/test_chrono.cpp b/resources/pybind11/tests/test_chrono.cpp new file mode 100755 index 0000000..b86f57a --- /dev/null +++ b/resources/pybind11/tests/test_chrono.cpp @@ -0,0 +1,59 @@ +/* + tests/test_chrono.cpp -- test conversions to/from std::chrono types + + Copyright (c) 2016 Trent Houliston and + Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include + +// Return the current time off the wall clock +std::chrono::system_clock::time_point test_chrono1() { + return std::chrono::system_clock::now(); +} + +// Round trip the passed in system clock time +std::chrono::system_clock::time_point test_chrono2(std::chrono::system_clock::time_point t) { + return t; +} + +// Round trip the passed in duration +std::chrono::system_clock::duration test_chrono3(std::chrono::system_clock::duration d) { + return d; +} + +// Difference between two passed in time_points +std::chrono::system_clock::duration test_chrono4(std::chrono::system_clock::time_point a, std::chrono::system_clock::time_point b) { + return a - b; +} + +// Return the current time off the steady_clock +std::chrono::steady_clock::time_point test_chrono5() { + return std::chrono::steady_clock::now(); +} + +// Round trip a steady clock timepoint +std::chrono::steady_clock::time_point test_chrono6(std::chrono::steady_clock::time_point t) { + return t; +} + +// Roundtrip a duration in microseconds from a float argument +std::chrono::microseconds test_chrono7(std::chrono::microseconds t) { + return t; +} + +test_initializer chrono([] (py::module &m) { + m.def("test_chrono1", &test_chrono1); + m.def("test_chrono2", &test_chrono2); + m.def("test_chrono3", &test_chrono3); + m.def("test_chrono4", &test_chrono4); + m.def("test_chrono5", &test_chrono5); + m.def("test_chrono6", &test_chrono6); + m.def("test_chrono7", &test_chrono7); +}); diff --git a/resources/pybind11/tests/test_chrono.py b/resources/pybind11/tests/test_chrono.py new file mode 100755 index 0000000..94ca55c --- /dev/null +++ b/resources/pybind11/tests/test_chrono.py @@ -0,0 +1,116 @@ + + +def test_chrono_system_clock(): + from pybind11_tests import test_chrono1 + import datetime + + # Get the time from both c++ and datetime + date1 = test_chrono1() + date2 = datetime.datetime.today() + + # The returned value should be a datetime + assert isinstance(date1, datetime.datetime) + + # The numbers should vary by a very small amount (time it took to execute) + diff = abs(date1 - date2) + + # There should never be a days/seconds difference + assert diff.days == 0 + assert diff.seconds == 0 + + # We test that no more than about 0.5 seconds passes here + # This makes sure that the dates created are very close to the same + # but if the testing system is incredibly overloaded this should still pass + assert diff.microseconds < 500000 + + +def test_chrono_system_clock_roundtrip(): + from pybind11_tests import test_chrono2 + import datetime + + date1 = datetime.datetime.today() + + # Roundtrip the time + date2 = test_chrono2(date1) + + # The returned value should be a datetime + assert isinstance(date2, datetime.datetime) + + # They should be identical (no information lost on roundtrip) + diff = abs(date1 - date2) + assert diff.days == 0 + assert diff.seconds == 0 + assert diff.microseconds == 0 + + +def test_chrono_duration_roundtrip(): + from pybind11_tests import test_chrono3 + import datetime + + # Get the difference between two times (a timedelta) + date1 = datetime.datetime.today() + date2 = datetime.datetime.today() + diff = date2 - date1 + + # Make sure this is a timedelta + assert isinstance(diff, datetime.timedelta) + + cpp_diff = test_chrono3(diff) + + assert cpp_diff.days == diff.days + assert cpp_diff.seconds == diff.seconds + assert cpp_diff.microseconds == diff.microseconds + + +def test_chrono_duration_subtraction_equivalence(): + from pybind11_tests import test_chrono4 + import datetime + + date1 = datetime.datetime.today() + date2 = datetime.datetime.today() + + diff = date2 - date1 + cpp_diff = test_chrono4(date2, date1) + + assert cpp_diff.days == diff.days + assert cpp_diff.seconds == diff.seconds + assert cpp_diff.microseconds == diff.microseconds + + +def test_chrono_steady_clock(): + from pybind11_tests import test_chrono5 + import datetime + + time1 = test_chrono5() + time2 = test_chrono5() + + assert isinstance(time1, datetime.timedelta) + assert isinstance(time2, datetime.timedelta) + + +def test_chrono_steady_clock_roundtrip(): + from pybind11_tests import test_chrono6 + import datetime + + time1 = datetime.timedelta(days=10, seconds=10, microseconds=100) + time2 = test_chrono6(time1) + + assert isinstance(time2, datetime.timedelta) + + # They should be identical (no information lost on roundtrip) + assert time1.days == time2.days + assert time1.seconds == time2.seconds + assert time1.microseconds == time2.microseconds + + +def test_floating_point_duration(): + from pybind11_tests import test_chrono7 + import datetime + + # Test using 35.525123 seconds as an example floating point number in seconds + time = test_chrono7(35.525123) + + assert isinstance(time, datetime.timedelta) + + assert time.seconds == 35 + assert 525122 <= time.microseconds <= 525123 diff --git a/resources/pybind11/tests/test_class_args.cpp b/resources/pybind11/tests/test_class_args.cpp new file mode 100755 index 0000000..e18b39d --- /dev/null +++ b/resources/pybind11/tests/test_class_args.cpp @@ -0,0 +1,68 @@ +/* + tests/test_class_args.cpp -- tests that various way of defining a class work + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + + +template class BreaksBase {}; +template class BreaksTramp : public BreaksBase {}; +// These should all compile just fine: +typedef py::class_, std::unique_ptr>, BreaksTramp<1>> DoesntBreak1; +typedef py::class_, BreaksTramp<2>, std::unique_ptr>> DoesntBreak2; +typedef py::class_, std::unique_ptr>> DoesntBreak3; +typedef py::class_, BreaksTramp<4>> DoesntBreak4; +typedef py::class_> DoesntBreak5; +typedef py::class_, std::shared_ptr>, BreaksTramp<6>> DoesntBreak6; +typedef py::class_, BreaksTramp<7>, std::shared_ptr>> DoesntBreak7; +typedef py::class_, std::shared_ptr>> DoesntBreak8; +#define CHECK_BASE(N) static_assert(std::is_same>::value, \ + "DoesntBreak" #N " has wrong type!") +CHECK_BASE(1); CHECK_BASE(2); CHECK_BASE(3); CHECK_BASE(4); CHECK_BASE(5); CHECK_BASE(6); CHECK_BASE(7); CHECK_BASE(8); +#define CHECK_ALIAS(N) static_assert(DoesntBreak##N::has_alias && std::is_same>::value, \ + "DoesntBreak" #N " has wrong type_alias!") +#define CHECK_NOALIAS(N) static_assert(!DoesntBreak##N::has_alias && std::is_void::value, \ + "DoesntBreak" #N " has type alias, but shouldn't!") +CHECK_ALIAS(1); CHECK_ALIAS(2); CHECK_NOALIAS(3); CHECK_ALIAS(4); CHECK_NOALIAS(5); CHECK_ALIAS(6); CHECK_ALIAS(7); CHECK_NOALIAS(8); +#define CHECK_HOLDER(N, TYPE) static_assert(std::is_same>>::value, \ + "DoesntBreak" #N " has wrong holder_type!") +CHECK_HOLDER(1, unique); CHECK_HOLDER(2, unique); CHECK_HOLDER(3, unique); CHECK_HOLDER(4, unique); CHECK_HOLDER(5, unique); +CHECK_HOLDER(6, shared); CHECK_HOLDER(7, shared); CHECK_HOLDER(8, shared); + +// There's no nice way to test that these fail because they fail to compile; leave them here, +// though, so that they can be manually tested by uncommenting them (and seeing that compilation +// failures occurs). + +// We have to actually look into the type: the typedef alone isn't enough to instantiate the type: +#define CHECK_BROKEN(N) static_assert(std::is_same>::value, \ + "Breaks1 has wrong type!"); + +//// Two holder classes: +//typedef py::class_, std::unique_ptr>, std::unique_ptr>> Breaks1; +//CHECK_BROKEN(1); +//// Two aliases: +//typedef py::class_, BreaksTramp<-2>, BreaksTramp<-2>> Breaks2; +//CHECK_BROKEN(2); +//// Holder + 2 aliases +//typedef py::class_, std::unique_ptr>, BreaksTramp<-3>, BreaksTramp<-3>> Breaks3; +//CHECK_BROKEN(3); +//// Alias + 2 holders +//typedef py::class_, std::unique_ptr>, BreaksTramp<-4>, std::shared_ptr>> Breaks4; +//CHECK_BROKEN(4); +//// Invalid option (not a subclass or holder) +//typedef py::class_, BreaksTramp<-4>> Breaks5; +//CHECK_BROKEN(5); +//// Invalid option: multiple inheritance not supported: +//template <> struct BreaksBase<-8> : BreaksBase<-6>, BreaksBase<-7> {}; +//typedef py::class_, BreaksBase<-6>, BreaksBase<-7>> Breaks8; +//CHECK_BROKEN(8); + +test_initializer class_args([](py::module &m) { + // Just test that this compiled okay + m.def("class_args_noop", []() {}); +}); diff --git a/resources/pybind11/tests/test_class_args.py b/resources/pybind11/tests/test_class_args.py new file mode 100755 index 0000000..91b0320 --- /dev/null +++ b/resources/pybind11/tests/test_class_args.py @@ -0,0 +1,6 @@ + + +def test_class_args(): + # There's basically nothing to test here; just make sure the code compiled and declared its definition + from pybind11_tests import class_args_noop + class_args_noop() diff --git a/resources/pybind11/tests/test_constants_and_functions.cpp b/resources/pybind11/tests/test_constants_and_functions.cpp new file mode 100755 index 0000000..29a2796 --- /dev/null +++ b/resources/pybind11/tests/test_constants_and_functions.cpp @@ -0,0 +1,55 @@ +/* + tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw byte strings + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +enum MyEnum { EFirstEntry = 1, ESecondEntry }; + +std::string test_function1() { + return "test_function()"; +} + +std::string test_function2(MyEnum k) { + return "test_function(enum=" + std::to_string(k) + ")"; +} + +std::string test_function3(int i) { + return "test_function(" + std::to_string(i) + ")"; +} + +py::bytes return_bytes() { + const char *data = "\x01\x00\x02\x00"; + return std::string(data, 4); +} + +std::string print_bytes(py::bytes bytes) { + std::string ret = "bytes["; + const auto value = static_cast(bytes); + for (size_t i = 0; i < value.length(); ++i) { + ret += std::to_string(static_cast(value[i])) + " "; + } + ret.back() = ']'; + return ret; +} + +test_initializer constants_and_functions([](py::module &m) { + m.attr("some_constant") = py::int_(14); + + m.def("test_function", &test_function1); + m.def("test_function", &test_function2); + m.def("test_function", &test_function3); + + py::enum_(m, "MyEnum") + .value("EFirstEntry", EFirstEntry) + .value("ESecondEntry", ESecondEntry) + .export_values(); + + m.def("return_bytes", &return_bytes); + m.def("print_bytes", &print_bytes); +}); diff --git a/resources/pybind11/tests/test_constants_and_functions.py b/resources/pybind11/tests/test_constants_and_functions.py new file mode 100755 index 0000000..2c6321e --- /dev/null +++ b/resources/pybind11/tests/test_constants_and_functions.py @@ -0,0 +1,21 @@ + + +def test_constants(): + from pybind11_tests import some_constant + + assert some_constant == 14 + + +def test_function_overloading(): + from pybind11_tests import MyEnum, test_function + + assert test_function() == "test_function()" + assert test_function(7) == "test_function(7)" + assert test_function(MyEnum.EFirstEntry) == "test_function(enum=1)" + assert test_function(MyEnum.ESecondEntry) == "test_function(enum=2)" + + +def test_bytes(): + from pybind11_tests import return_bytes, print_bytes + + assert print_bytes(return_bytes()) == "bytes[1 0 2 0]" diff --git a/resources/pybind11/tests/test_copy_move_policies.cpp b/resources/pybind11/tests/test_copy_move_policies.cpp new file mode 100755 index 0000000..6f7907c --- /dev/null +++ b/resources/pybind11/tests/test_copy_move_policies.cpp @@ -0,0 +1,41 @@ +/* + tests/test_copy_move_policies.cpp -- 'copy' and 'move' + return value policies + + Copyright (c) 2016 Ben North + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +template +struct empty { + static const derived& get_one() { return instance_; } + static derived instance_; +}; + +struct lacking_copy_ctor : public empty { + lacking_copy_ctor() {} + lacking_copy_ctor(const lacking_copy_ctor& other) = delete; +}; + +template <> lacking_copy_ctor empty::instance_ = {}; + +struct lacking_move_ctor : public empty { + lacking_move_ctor() {} + lacking_move_ctor(const lacking_move_ctor& other) = delete; + lacking_move_ctor(lacking_move_ctor&& other) = delete; +}; + +template <> lacking_move_ctor empty::instance_ = {}; + +test_initializer copy_move_policies([](py::module &m) { + py::class_(m, "lacking_copy_ctor") + .def_static("get_one", &lacking_copy_ctor::get_one, + py::return_value_policy::copy); + py::class_(m, "lacking_move_ctor") + .def_static("get_one", &lacking_move_ctor::get_one, + py::return_value_policy::move); +}); diff --git a/resources/pybind11/tests/test_copy_move_policies.py b/resources/pybind11/tests/test_copy_move_policies.py new file mode 100755 index 0000000..edcf380 --- /dev/null +++ b/resources/pybind11/tests/test_copy_move_policies.py @@ -0,0 +1,15 @@ +import pytest + + +def test_lacking_copy_ctor(): + from pybind11_tests import lacking_copy_ctor + with pytest.raises(RuntimeError) as excinfo: + lacking_copy_ctor.get_one() + assert "the object is non-copyable!" in str(excinfo.value) + + +def test_lacking_move_ctor(): + from pybind11_tests import lacking_move_ctor + with pytest.raises(RuntimeError) as excinfo: + lacking_move_ctor.get_one() + assert "the object is neither movable nor copyable!" in str(excinfo.value) diff --git a/resources/pybind11/tests/test_docstring_options.cpp b/resources/pybind11/tests/test_docstring_options.cpp new file mode 100755 index 0000000..74178c2 --- /dev/null +++ b/resources/pybind11/tests/test_docstring_options.cpp @@ -0,0 +1,53 @@ +/* + tests/test_docstring_options.cpp -- generation of docstrings and signatures + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +struct DocstringTestFoo { + int value; + void setValue(int v) { value = v; } + int getValue() const { return value; } +}; + +test_initializer docstring_generation([](py::module &m) { + + { + py::options options; + options.disable_function_signatures(); + + m.def("test_function1", [](int, int) {}, py::arg("a"), py::arg("b")); + m.def("test_function2", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); + + options.enable_function_signatures(); + + m.def("test_function3", [](int, int) {}, py::arg("a"), py::arg("b")); + m.def("test_function4", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); + + options.disable_function_signatures().disable_user_defined_docstrings(); + + m.def("test_function5", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); + + { + py::options nested_options; + nested_options.enable_user_defined_docstrings(); + m.def("test_function6", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); + } + } + + m.def("test_function7", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); + + { + py::options options; + options.disable_user_defined_docstrings(); + + py::class_(m, "DocstringTestFoo", "This is a class docstring") + .def_property("value_prop", &DocstringTestFoo::getValue, &DocstringTestFoo::setValue, "This is a property docstring") + ; + } +}); diff --git a/resources/pybind11/tests/test_docstring_options.py b/resources/pybind11/tests/test_docstring_options.py new file mode 100755 index 0000000..66ad6b8 --- /dev/null +++ b/resources/pybind11/tests/test_docstring_options.py @@ -0,0 +1,32 @@ + + +def test_docstring_options(): + from pybind11_tests import (test_function1, test_function2, test_function3, + test_function4, test_function5, test_function6, + test_function7, DocstringTestFoo) + + # options.disable_function_signatures() + assert not test_function1.__doc__ + + assert test_function2.__doc__ == "A custom docstring" + + # options.enable_function_signatures() + assert test_function3.__doc__ .startswith("test_function3(a: int, b: int) -> None") + + assert test_function4.__doc__ .startswith("test_function4(a: int, b: int) -> None") + assert test_function4.__doc__ .endswith("A custom docstring\n") + + # options.disable_function_signatures() + # options.disable_user_defined_docstrings() + assert not test_function5.__doc__ + + # nested options.enable_user_defined_docstrings() + assert test_function6.__doc__ == "A custom docstring" + + # RAII destructor + assert test_function7.__doc__ .startswith("test_function7(a: int, b: int) -> None") + assert test_function7.__doc__ .endswith("A custom docstring\n") + + # Suppression of user-defined docstrings for non-function objects + assert not DocstringTestFoo.__doc__ + assert not DocstringTestFoo.value_prop.__doc__ diff --git a/resources/pybind11/tests/test_eigen.cpp b/resources/pybind11/tests/test_eigen.cpp new file mode 100755 index 0000000..a9cb9f2 --- /dev/null +++ b/resources/pybind11/tests/test_eigen.cpp @@ -0,0 +1,134 @@ +/* + tests/eigen.cpp -- automatic conversion of Eigen types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include +#include + +Eigen::VectorXf double_col(const Eigen::VectorXf& x) +{ return 2.0f * x; } + +Eigen::RowVectorXf double_row(const Eigen::RowVectorXf& x) +{ return 2.0f * x; } + +Eigen::MatrixXf double_mat_cm(const Eigen::MatrixXf& x) +{ return 2.0f * x; } + +// Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended +Eigen::MatrixXd cholesky1(Eigen::Ref &x) { return x.llt().matrixL(); } +Eigen::MatrixXd cholesky2(const Eigen::Ref &x) { return x.llt().matrixL(); } +Eigen::MatrixXd cholesky3(const Eigen::Ref &x) { return x.llt().matrixL(); } +Eigen::MatrixXd cholesky4(Eigen::Ref &x) { return x.llt().matrixL(); } +Eigen::MatrixXd cholesky5(Eigen::Ref x) { return x.llt().matrixL(); } +Eigen::MatrixXd cholesky6(Eigen::Ref x) { return x.llt().matrixL(); } + +typedef Eigen::Matrix MatrixXfRowMajor; +MatrixXfRowMajor double_mat_rm(const MatrixXfRowMajor& x) +{ return 2.0f * x; } + +test_initializer eigen([](py::module &m) { + typedef Eigen::Matrix FixedMatrixR; + typedef Eigen::Matrix FixedMatrixC; + typedef Eigen::Matrix DenseMatrixR; + typedef Eigen::Matrix DenseMatrixC; + typedef Eigen::SparseMatrix SparseMatrixR; + typedef Eigen::SparseMatrix SparseMatrixC; + + m.attr("have_eigen") = py::cast(true); + + // Non-symmetric matrix with zero elements + Eigen::MatrixXf mat(5, 6); + mat << 0, 3, 0, 0, 0, 11, 22, 0, 0, 0, 17, 11, 7, 5, 0, 1, 0, 11, 0, + 0, 0, 0, 0, 11, 0, 0, 14, 0, 8, 11; + + m.def("double_col", &double_col); + m.def("double_row", &double_row); + m.def("double_mat_cm", &double_mat_cm); + m.def("double_mat_rm", &double_mat_rm); + m.def("cholesky1", &cholesky1); + m.def("cholesky2", &cholesky2); + m.def("cholesky3", &cholesky3); + m.def("cholesky4", &cholesky4); + m.def("cholesky5", &cholesky5); + m.def("cholesky6", &cholesky6); + + // Returns diagonals: a vector-like object with an inner stride != 1 + m.def("diagonal", [](const Eigen::Ref &x) { return x.diagonal(); }); + m.def("diagonal_1", [](const Eigen::Ref &x) { return x.diagonal<1>(); }); + m.def("diagonal_n", [](const Eigen::Ref &x, int index) { return x.diagonal(index); }); + + // Return a block of a matrix (gives non-standard strides) + m.def("block", [](const Eigen::Ref &x, int start_row, int start_col, int block_rows, int block_cols) { + return x.block(start_row, start_col, block_rows, block_cols); + }); + + // Returns a DiagonalMatrix with diagonal (1,2,3,...) + m.def("incr_diag", [](int k) { + Eigen::DiagonalMatrix m(k); + for (int i = 0; i < k; i++) m.diagonal()[i] = i+1; + return m; + }); + + // Returns a SelfAdjointView referencing the lower triangle of m + m.def("symmetric_lower", [](const Eigen::MatrixXi &m) { + return m.selfadjointView(); + }); + // Returns a SelfAdjointView referencing the lower triangle of m + m.def("symmetric_upper", [](const Eigen::MatrixXi &m) { + return m.selfadjointView(); + }); + + m.def("fixed_r", [mat]() -> FixedMatrixR { + return FixedMatrixR(mat); + }); + + m.def("fixed_c", [mat]() -> FixedMatrixC { + return FixedMatrixC(mat); + }); + + m.def("fixed_passthrough_r", [](const FixedMatrixR &m) -> FixedMatrixR { + return m; + }); + + m.def("fixed_passthrough_c", [](const FixedMatrixC &m) -> FixedMatrixC { + return m; + }); + + m.def("dense_r", [mat]() -> DenseMatrixR { + return DenseMatrixR(mat); + }); + + m.def("dense_c", [mat]() -> DenseMatrixC { + return DenseMatrixC(mat); + }); + + m.def("dense_passthrough_r", [](const DenseMatrixR &m) -> DenseMatrixR { + return m; + }); + + m.def("dense_passthrough_c", [](const DenseMatrixC &m) -> DenseMatrixC { + return m; + }); + + m.def("sparse_r", [mat]() -> SparseMatrixR { + return Eigen::SparseView(mat); + }); + + m.def("sparse_c", [mat]() -> SparseMatrixC { + return Eigen::SparseView(mat); + }); + + m.def("sparse_passthrough_r", [](const SparseMatrixR &m) -> SparseMatrixR { + return m; + }); + + m.def("sparse_passthrough_c", [](const SparseMatrixC &m) -> SparseMatrixC { + return m; + }); +}); diff --git a/resources/pybind11/tests/test_eigen.py b/resources/pybind11/tests/test_eigen.py new file mode 100755 index 0000000..2a58f8c --- /dev/null +++ b/resources/pybind11/tests/test_eigen.py @@ -0,0 +1,135 @@ +import pytest + +with pytest.suppress(ImportError): + import numpy as np + + ref = np.array([[ 0, 3, 0, 0, 0, 11], + [22, 0, 0, 0, 17, 11], + [ 7, 5, 0, 1, 0, 11], + [ 0, 0, 0, 0, 0, 11], + [ 0, 0, 14, 0, 8, 11]]) + + +def assert_equal_ref(mat): + np.testing.assert_array_equal(mat, ref) + + +def assert_sparse_equal_ref(sparse_mat): + assert_equal_ref(sparse_mat.todense()) + + +@pytest.requires_eigen_and_numpy +def test_fixed(): + from pybind11_tests import fixed_r, fixed_c, fixed_passthrough_r, fixed_passthrough_c + + assert_equal_ref(fixed_c()) + assert_equal_ref(fixed_r()) + assert_equal_ref(fixed_passthrough_r(fixed_r())) + assert_equal_ref(fixed_passthrough_c(fixed_c())) + assert_equal_ref(fixed_passthrough_r(fixed_c())) + assert_equal_ref(fixed_passthrough_c(fixed_r())) + + +@pytest.requires_eigen_and_numpy +def test_dense(): + from pybind11_tests import dense_r, dense_c, dense_passthrough_r, dense_passthrough_c + + assert_equal_ref(dense_r()) + assert_equal_ref(dense_c()) + assert_equal_ref(dense_passthrough_r(dense_r())) + assert_equal_ref(dense_passthrough_c(dense_c())) + assert_equal_ref(dense_passthrough_r(dense_c())) + assert_equal_ref(dense_passthrough_c(dense_r())) + + +@pytest.requires_eigen_and_numpy +def test_nonunit_stride_from_python(): + from pybind11_tests import double_row, double_col, double_mat_cm, double_mat_rm + + counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3)) + first_row = counting_mat[0, :] + first_col = counting_mat[:, 0] + assert np.array_equal(double_row(first_row), 2.0 * first_row) + assert np.array_equal(double_col(first_row), 2.0 * first_row) + assert np.array_equal(double_row(first_col), 2.0 * first_col) + assert np.array_equal(double_col(first_col), 2.0 * first_col) + + counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3)) + slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]] + for slice_idx, ref_mat in enumerate(slices): + assert np.array_equal(double_mat_cm(ref_mat), 2.0 * ref_mat) + assert np.array_equal(double_mat_rm(ref_mat), 2.0 * ref_mat) + + +@pytest.requires_eigen_and_numpy +def test_nonunit_stride_to_python(): + from pybind11_tests import diagonal, diagonal_1, diagonal_n, block + + assert np.all(diagonal(ref) == ref.diagonal()) + assert np.all(diagonal_1(ref) == ref.diagonal(1)) + for i in range(-5, 7): + assert np.all(diagonal_n(ref, i) == ref.diagonal(i)), "diagonal_n({})".format(i) + + assert np.all(block(ref, 2, 1, 3, 3) == ref[2:5, 1:4]) + assert np.all(block(ref, 1, 4, 4, 2) == ref[1:, 4:]) + assert np.all(block(ref, 1, 4, 3, 2) == ref[1:4, 4:]) + + +@pytest.requires_eigen_and_numpy +def test_eigen_ref_to_python(): + from pybind11_tests import cholesky1, cholesky2, cholesky3, cholesky4, cholesky5, cholesky6 + + chols = [cholesky1, cholesky2, cholesky3, cholesky4, cholesky5, cholesky6] + for i, chol in enumerate(chols, start=1): + mymat = chol(np.array([[1, 2, 4], [2, 13, 23], [4, 23, 77]])) + assert np.all(mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])), "cholesky{}".format(i) + + +@pytest.requires_eigen_and_numpy +def test_special_matrix_objects(): + from pybind11_tests import incr_diag, symmetric_upper, symmetric_lower + + assert np.all(incr_diag(7) == np.diag([1, 2, 3, 4, 5, 6, 7])) + + asymm = np.array([[ 1, 2, 3, 4], + [ 5, 6, 7, 8], + [ 9, 10, 11, 12], + [13, 14, 15, 16]]) + symm_lower = np.array(asymm) + symm_upper = np.array(asymm) + for i in range(4): + for j in range(i + 1, 4): + symm_lower[i, j] = symm_lower[j, i] + symm_upper[j, i] = symm_upper[i, j] + + assert np.all(symmetric_lower(asymm) == symm_lower) + assert np.all(symmetric_upper(asymm) == symm_upper) + + +@pytest.requires_eigen_and_numpy +def test_dense_signature(doc): + from pybind11_tests import double_col, double_row, double_mat_rm + + assert doc(double_col) == "double_col(arg0: numpy.ndarray[float32[m, 1]]) -> numpy.ndarray[float32[m, 1]]" + assert doc(double_row) == "double_row(arg0: numpy.ndarray[float32[1, n]]) -> numpy.ndarray[float32[1, n]]" + assert doc(double_mat_rm) == "double_mat_rm(arg0: numpy.ndarray[float32[m, n]]) -> numpy.ndarray[float32[m, n]]" + + +@pytest.requires_eigen_and_scipy +def test_sparse(): + from pybind11_tests import sparse_r, sparse_c, sparse_passthrough_r, sparse_passthrough_c + + assert_sparse_equal_ref(sparse_r()) + assert_sparse_equal_ref(sparse_c()) + assert_sparse_equal_ref(sparse_passthrough_r(sparse_r())) + assert_sparse_equal_ref(sparse_passthrough_c(sparse_c())) + assert_sparse_equal_ref(sparse_passthrough_r(sparse_c())) + assert_sparse_equal_ref(sparse_passthrough_c(sparse_r())) + + +@pytest.requires_eigen_and_scipy +def test_sparse_signature(doc): + from pybind11_tests import sparse_passthrough_r, sparse_passthrough_c + + assert doc(sparse_passthrough_r) == "sparse_passthrough_r(arg0: scipy.sparse.csr_matrix[float32]) -> scipy.sparse.csr_matrix[float32]" + assert doc(sparse_passthrough_c) == "sparse_passthrough_c(arg0: scipy.sparse.csc_matrix[float32]) -> scipy.sparse.csc_matrix[float32]" diff --git a/resources/pybind11/tests/test_enum.cpp b/resources/pybind11/tests/test_enum.cpp new file mode 100755 index 0000000..09f334c --- /dev/null +++ b/resources/pybind11/tests/test_enum.cpp @@ -0,0 +1,68 @@ +/* + tests/test_enums.cpp -- enumerations + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +enum UnscopedEnum { + EOne = 1, + ETwo +}; + +enum class ScopedEnum { + Two = 2, + Three +}; + +enum Flags { + Read = 4, + Write = 2, + Execute = 1 +}; + +class ClassWithUnscopedEnum { +public: + enum EMode { + EFirstMode = 1, + ESecondMode + }; + + static EMode test_function(EMode mode) { + return mode; + } +}; + +std::string test_scoped_enum(ScopedEnum z) { + return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three"); +} + +test_initializer enums([](py::module &m) { + m.def("test_scoped_enum", &test_scoped_enum); + + py::enum_(m, "UnscopedEnum", py::arithmetic()) + .value("EOne", EOne) + .value("ETwo", ETwo) + .export_values(); + + py::enum_(m, "ScopedEnum", py::arithmetic()) + .value("Two", ScopedEnum::Two) + .value("Three", ScopedEnum::Three); + + py::enum_(m, "Flags", py::arithmetic()) + .value("Read", Flags::Read) + .value("Write", Flags::Write) + .value("Execute", Flags::Execute) + .export_values(); + + py::class_ exenum_class(m, "ClassWithUnscopedEnum"); + exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function); + py::enum_(exenum_class, "EMode") + .value("EFirstMode", ClassWithUnscopedEnum::EFirstMode) + .value("ESecondMode", ClassWithUnscopedEnum::ESecondMode) + .export_values(); +}); diff --git a/resources/pybind11/tests/test_enum.py b/resources/pybind11/tests/test_enum.py new file mode 100755 index 0000000..de5f3c6 --- /dev/null +++ b/resources/pybind11/tests/test_enum.py @@ -0,0 +1,108 @@ +import pytest + + +def test_unscoped_enum(): + from pybind11_tests import UnscopedEnum, EOne + + assert str(UnscopedEnum.EOne) == "UnscopedEnum.EOne" + assert str(UnscopedEnum.ETwo) == "UnscopedEnum.ETwo" + assert str(EOne) == "UnscopedEnum.EOne" + + # no TypeError exception for unscoped enum ==/!= int comparisons + y = UnscopedEnum.ETwo + assert y == 2 + assert y != 3 + + assert int(UnscopedEnum.ETwo) == 2 + assert str(UnscopedEnum(2)) == "UnscopedEnum.ETwo" + + # order + assert UnscopedEnum.EOne < UnscopedEnum.ETwo + assert UnscopedEnum.EOne < 2 + assert UnscopedEnum.ETwo > UnscopedEnum.EOne + assert UnscopedEnum.ETwo > 1 + assert UnscopedEnum.ETwo <= 2 + assert UnscopedEnum.ETwo >= 2 + assert UnscopedEnum.EOne <= UnscopedEnum.ETwo + assert UnscopedEnum.EOne <= 2 + assert UnscopedEnum.ETwo >= UnscopedEnum.EOne + assert UnscopedEnum.ETwo >= 1 + assert not (UnscopedEnum.ETwo < UnscopedEnum.EOne) + assert not (2 < UnscopedEnum.EOne) + + +def test_scoped_enum(): + from pybind11_tests import ScopedEnum, test_scoped_enum + + assert test_scoped_enum(ScopedEnum.Three) == "ScopedEnum::Three" + z = ScopedEnum.Two + assert test_scoped_enum(z) == "ScopedEnum::Two" + + # expected TypeError exceptions for scoped enum ==/!= int comparisons + with pytest.raises(TypeError): + assert z == 2 + with pytest.raises(TypeError): + assert z != 3 + + # order + assert ScopedEnum.Two < ScopedEnum.Three + assert ScopedEnum.Three > ScopedEnum.Two + assert ScopedEnum.Two <= ScopedEnum.Three + assert ScopedEnum.Two <= ScopedEnum.Two + assert ScopedEnum.Two >= ScopedEnum.Two + assert ScopedEnum.Three >= ScopedEnum.Two + + +def test_implicit_conversion(): + from pybind11_tests import ClassWithUnscopedEnum + + assert str(ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode" + assert str(ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode" + + f = ClassWithUnscopedEnum.test_function + first = ClassWithUnscopedEnum.EFirstMode + second = ClassWithUnscopedEnum.ESecondMode + + assert f(first) == 1 + + assert f(first) == f(first) + assert not f(first) != f(first) + + assert f(first) != f(second) + assert not f(first) == f(second) + + assert f(first) == int(f(first)) + assert not f(first) != int(f(first)) + + assert f(first) != int(f(second)) + assert not f(first) == int(f(second)) + + # noinspection PyDictCreation + x = {f(first): 1, f(second): 2} + x[f(first)] = 3 + x[f(second)] = 4 + # Hashing test + assert str(x) == "{EMode.EFirstMode: 3, EMode.ESecondMode: 4}" + + +def test_binary_operators(): + from pybind11_tests import Flags + + assert int(Flags.Read) == 4 + assert int(Flags.Write) == 2 + assert int(Flags.Execute) == 1 + assert int(Flags.Read | Flags.Write | Flags.Execute) == 7 + assert int(Flags.Read | Flags.Write) == 6 + assert int(Flags.Read | Flags.Execute) == 5 + assert int(Flags.Write | Flags.Execute) == 3 + assert int(Flags.Write | 1) == 3 + + state = Flags.Read | Flags.Write + assert (state & Flags.Read) != 0 + assert (state & Flags.Write) != 0 + assert (state & Flags.Execute) == 0 + assert (state & 1) == 0 + + state2 = ~state + assert state2 == -7 + assert int(state ^ state2) == -1 diff --git a/resources/pybind11/tests/test_eval.cpp b/resources/pybind11/tests/test_eval.cpp new file mode 100755 index 0000000..ed4c226 --- /dev/null +++ b/resources/pybind11/tests/test_eval.cpp @@ -0,0 +1,79 @@ +/* + tests/test_eval.cpp -- Usage of eval() and eval_file() + + Copyright (c) 2016 Klemens D. Morgenstern + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + + +#include +#include "pybind11_tests.h" + +test_initializer eval([](py::module &m) { + auto global = py::dict(py::module::import("__main__").attr("__dict__")); + + m.def("test_eval_statements", [global]() { + auto local = py::dict(); + local["call_test"] = py::cpp_function([&]() -> int { + return 42; + }); + + auto result = py::eval( + "print('Hello World!');\n" + "x = call_test();", + global, local + ); + auto x = local["x"].cast(); + + return result == py::none() && x == 42; + }); + + m.def("test_eval", [global]() { + auto local = py::dict(); + local["x"] = py::int_(42); + auto x = py::eval("x", global, local); + return x.cast() == 42; + }); + + m.def("test_eval_single_statement", []() { + auto local = py::dict(); + local["call_test"] = py::cpp_function([&]() -> int { + return 42; + }); + + auto result = py::eval("x = call_test()", py::dict(), local); + auto x = local["x"].cast(); + return result == py::none() && x == 42; + }); + + m.def("test_eval_file", [global](py::str filename) { + auto local = py::dict(); + local["y"] = py::int_(43); + + int val_out; + local["call_test2"] = py::cpp_function([&](int value) { val_out = value; }); + + auto result = py::eval_file(filename, global, local); + return val_out == 43 && result == py::none(); + }); + + m.def("test_eval_failure", []() { + try { + py::eval("nonsense code ..."); + } catch (py::error_already_set &) { + return true; + } + return false; + }); + + m.def("test_eval_file_failure", []() { + try { + py::eval_file("non-existing file"); + } catch (std::exception &) { + return true; + } + return false; + }); +}); diff --git a/resources/pybind11/tests/test_eval.py b/resources/pybind11/tests/test_eval.py new file mode 100755 index 0000000..8715dba --- /dev/null +++ b/resources/pybind11/tests/test_eval.py @@ -0,0 +1,19 @@ +import os + + +def test_evals(capture): + from pybind11_tests import (test_eval_statements, test_eval, test_eval_single_statement, + test_eval_file, test_eval_failure, test_eval_file_failure) + + with capture: + assert test_eval_statements() + assert capture == "Hello World!" + + assert test_eval() + assert test_eval_single_statement() + + filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py") + assert test_eval_file(filename) + + assert test_eval_failure() + assert test_eval_file_failure() diff --git a/resources/pybind11/tests/test_eval_call.py b/resources/pybind11/tests/test_eval_call.py new file mode 100755 index 0000000..53c7e72 --- /dev/null +++ b/resources/pybind11/tests/test_eval_call.py @@ -0,0 +1,4 @@ +# This file is called from 'test_eval.py' + +if 'call_test2' in locals(): + call_test2(y) # noqa: F821 undefined name diff --git a/resources/pybind11/tests/test_exceptions.cpp b/resources/pybind11/tests/test_exceptions.cpp new file mode 100755 index 0000000..ca2afa6 --- /dev/null +++ b/resources/pybind11/tests/test_exceptions.cpp @@ -0,0 +1,173 @@ +/* + tests/test_custom-exceptions.cpp -- exception translation + + Copyright (c) 2016 Pim Schellart + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +// A type that should be raised as an exeption in Python +class MyException : public std::exception { +public: + explicit MyException(const char * m) : message{m} {} + virtual const char * what() const noexcept override {return message.c_str();} +private: + std::string message = ""; +}; + +// A type that should be translated to a standard Python exception +class MyException2 : public std::exception { +public: + explicit MyException2(const char * m) : message{m} {} + virtual const char * what() const noexcept override {return message.c_str();} +private: + std::string message = ""; +}; + +// A type that is not derived from std::exception (and is thus unknown) +class MyException3 { +public: + explicit MyException3(const char * m) : message{m} {} + virtual const char * what() const noexcept {return message.c_str();} +private: + std::string message = ""; +}; + +// A type that should be translated to MyException +// and delegated to its exception translator +class MyException4 : public std::exception { +public: + explicit MyException4(const char * m) : message{m} {} + virtual const char * what() const noexcept override {return message.c_str();} +private: + std::string message = ""; +}; + + +// Like the above, but declared via the helper function +class MyException5 : public std::logic_error { +public: + explicit MyException5(const std::string &what) : std::logic_error(what) {} +}; + +// Inherits from MyException5 +class MyException5_1 : public MyException5 { + using MyException5::MyException5; +}; + +void throws1() { + throw MyException("this error should go to a custom type"); +} + +void throws2() { + throw MyException2("this error should go to a standard Python exception"); +} + +void throws3() { + throw MyException3("this error cannot be translated"); +} + +void throws4() { + throw MyException4("this error is rethrown"); +} + +void throws5() { + throw MyException5("this is a helper-defined translated exception"); +} + +void throws5_1() { + throw MyException5_1("MyException5 subclass"); +} + +void throws_logic_error() { + throw std::logic_error("this error should fall through to the standard handler"); +} + +struct PythonCallInDestructor { + PythonCallInDestructor(const py::dict &d) : d(d) {} + ~PythonCallInDestructor() { d["good"] = py::cast(true); } + + py::dict d; +}; + +test_initializer custom_exceptions([](py::module &m) { + // make a new custom exception and use it as a translation target + static py::exception ex(m, "MyException"); + py::register_exception_translator([](std::exception_ptr p) { + try { + if (p) std::rethrow_exception(p); + } catch (const MyException &e) { + // Set MyException as the active python error + ex(e.what()); + } + }); + + // register new translator for MyException2 + // no need to store anything here because this type will + // never by visible from Python + py::register_exception_translator([](std::exception_ptr p) { + try { + if (p) std::rethrow_exception(p); + } catch (const MyException2 &e) { + // Translate this exception to a standard RuntimeError + PyErr_SetString(PyExc_RuntimeError, e.what()); + } + }); + + // register new translator for MyException4 + // which will catch it and delegate to the previously registered + // translator for MyException by throwing a new exception + py::register_exception_translator([](std::exception_ptr p) { + try { + if (p) std::rethrow_exception(p); + } catch (const MyException4 &e) { + throw MyException(e.what()); + } + }); + + // A simple exception translation: + auto ex5 = py::register_exception(m, "MyException5"); + // A slightly more complicated one that declares MyException5_1 as a subclass of MyException5 + py::register_exception(m, "MyException5_1", ex5.ptr()); + + m.def("throws1", &throws1); + m.def("throws2", &throws2); + m.def("throws3", &throws3); + m.def("throws4", &throws4); + m.def("throws5", &throws5); + m.def("throws5_1", &throws5_1); + m.def("throws_logic_error", &throws_logic_error); + + m.def("throw_already_set", [](bool err) { + if (err) + PyErr_SetString(PyExc_ValueError, "foo"); + try { + throw py::error_already_set(); + } catch (const std::runtime_error& e) { + if ((err && e.what() != std::string("ValueError: foo")) || + (!err && e.what() != std::string("Unknown internal error occurred"))) + { + PyErr_Clear(); + throw std::runtime_error("error message mismatch"); + } + } + PyErr_Clear(); + if (err) + PyErr_SetString(PyExc_ValueError, "foo"); + throw py::error_already_set(); + }); + + m.def("python_call_in_destructor", [](py::dict d) { + try { + PythonCallInDestructor set_dict_in_destructor(d); + PyErr_SetString(PyExc_ValueError, "foo"); + throw py::error_already_set(); + } catch (const py::error_already_set&) { + return true; + } + return false; + }); +}); diff --git a/resources/pybind11/tests/test_exceptions.py b/resources/pybind11/tests/test_exceptions.py new file mode 100755 index 0000000..0025e4e --- /dev/null +++ b/resources/pybind11/tests/test_exceptions.py @@ -0,0 +1,74 @@ +import pytest + + +def test_error_already_set(msg): + from pybind11_tests import throw_already_set + + with pytest.raises(RuntimeError) as excinfo: + throw_already_set(False) + assert msg(excinfo.value) == "Unknown internal error occurred" + + with pytest.raises(ValueError) as excinfo: + throw_already_set(True) + assert msg(excinfo.value) == "foo" + + +def test_python_call_in_catch(): + from pybind11_tests import python_call_in_destructor + + d = {} + assert python_call_in_destructor(d) is True + assert d["good"] is True + + +def test_custom(msg): + from pybind11_tests import (MyException, MyException5, MyException5_1, + throws1, throws2, throws3, throws4, throws5, throws5_1, + throws_logic_error) + + # Can we catch a MyException?" + with pytest.raises(MyException) as excinfo: + throws1() + assert msg(excinfo.value) == "this error should go to a custom type" + + # Can we translate to standard Python exceptions? + with pytest.raises(RuntimeError) as excinfo: + throws2() + assert msg(excinfo.value) == "this error should go to a standard Python exception" + + # Can we handle unknown exceptions? + with pytest.raises(RuntimeError) as excinfo: + throws3() + assert msg(excinfo.value) == "Caught an unknown exception!" + + # Can we delegate to another handler by rethrowing? + with pytest.raises(MyException) as excinfo: + throws4() + assert msg(excinfo.value) == "this error is rethrown" + + # "Can we fall-through to the default handler?" + with pytest.raises(RuntimeError) as excinfo: + throws_logic_error() + assert msg(excinfo.value) == "this error should fall through to the standard handler" + + # Can we handle a helper-declared exception? + with pytest.raises(MyException5) as excinfo: + throws5() + assert msg(excinfo.value) == "this is a helper-defined translated exception" + + # Exception subclassing: + with pytest.raises(MyException5) as excinfo: + throws5_1() + assert msg(excinfo.value) == "MyException5 subclass" + assert isinstance(excinfo.value, MyException5_1) + + with pytest.raises(MyException5_1) as excinfo: + throws5_1() + assert msg(excinfo.value) == "MyException5 subclass" + + with pytest.raises(MyException5) as excinfo: + try: + throws5() + except MyException5_1: + raise RuntimeError("Exception error: caught child from parent") + assert msg(excinfo.value) == "this is a helper-defined translated exception" diff --git a/resources/pybind11/tests/test_inheritance.cpp b/resources/pybind11/tests/test_inheritance.cpp new file mode 100755 index 0000000..2ec0b4a --- /dev/null +++ b/resources/pybind11/tests/test_inheritance.cpp @@ -0,0 +1,100 @@ +/* + tests/test_inheritance.cpp -- inheritance, automatic upcasting for polymorphic types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +class Pet { +public: + Pet(const std::string &name, const std::string &species) + : m_name(name), m_species(species) {} + std::string name() const { return m_name; } + std::string species() const { return m_species; } +private: + std::string m_name; + std::string m_species; +}; + +class Dog : public Pet { +public: + Dog(const std::string &name) : Pet(name, "dog") {} + std::string bark() const { return "Woof!"; } +}; + +class Rabbit : public Pet { +public: + Rabbit(const std::string &name) : Pet(name, "parrot") {} +}; + +class Hamster : public Pet { +public: + Hamster(const std::string &name) : Pet(name, "rodent") {} +}; + +std::string pet_name_species(const Pet &pet) { + return pet.name() + " is a " + pet.species(); +} + +std::string dog_bark(const Dog &dog) { + return dog.bark(); +} + + +struct BaseClass { virtual ~BaseClass() {} }; +struct DerivedClass1 : BaseClass { }; +struct DerivedClass2 : BaseClass { }; + +test_initializer inheritance([](py::module &m) { + py::class_ pet_class(m, "Pet"); + pet_class + .def(py::init()) + .def("name", &Pet::name) + .def("species", &Pet::species); + + /* One way of declaring a subclass relationship: reference parent's class_ object */ + py::class_(m, "Dog", pet_class) + .def(py::init()); + + /* Another way of declaring a subclass relationship: reference parent's C++ type */ + py::class_(m, "Rabbit") + .def(py::init()); + + /* And another: list parent in class template arguments */ + py::class_(m, "Hamster") + .def(py::init()); + + m.def("pet_name_species", pet_name_species); + m.def("dog_bark", dog_bark); + + py::class_(m, "BaseClass").def(py::init<>()); + py::class_(m, "DerivedClass1").def(py::init<>()); + py::class_(m, "DerivedClass2").def(py::init<>()); + + m.def("return_class_1", []() -> BaseClass* { return new DerivedClass1(); }); + m.def("return_class_2", []() -> BaseClass* { return new DerivedClass2(); }); + m.def("return_class_n", [](int n) -> BaseClass* { + if (n == 1) return new DerivedClass1(); + if (n == 2) return new DerivedClass2(); + return new BaseClass(); + }); + m.def("return_none", []() -> BaseClass* { return nullptr; }); + + m.def("test_isinstance", [](py::list l) { + struct Unregistered { }; // checks missing type_info code path + + return py::make_tuple( + py::isinstance(l[0]), + py::isinstance(l[1]), + py::isinstance(l[2]), + py::isinstance(l[3]), + py::isinstance(l[4]), + py::isinstance(l[5]), + py::isinstance(l[6]) + ); + }); +}); diff --git a/resources/pybind11/tests/test_inheritance.py b/resources/pybind11/tests/test_inheritance.py new file mode 100755 index 0000000..7bb52be --- /dev/null +++ b/resources/pybind11/tests/test_inheritance.py @@ -0,0 +1,55 @@ +import pytest + + +def test_inheritance(msg): + from pybind11_tests import Pet, Dog, Rabbit, Hamster, dog_bark, pet_name_species + + roger = Rabbit('Rabbit') + assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot" + assert pet_name_species(roger) == "Rabbit is a parrot" + + polly = Pet('Polly', 'parrot') + assert polly.name() + " is a " + polly.species() == "Polly is a parrot" + assert pet_name_species(polly) == "Polly is a parrot" + + molly = Dog('Molly') + assert molly.name() + " is a " + molly.species() == "Molly is a dog" + assert pet_name_species(molly) == "Molly is a dog" + + fred = Hamster('Fred') + assert fred.name() + " is a " + fred.species() == "Fred is a rodent" + + assert dog_bark(molly) == "Woof!" + + with pytest.raises(TypeError) as excinfo: + dog_bark(polly) + assert msg(excinfo.value) == """ + dog_bark(): incompatible function arguments. The following argument types are supported: + 1. (arg0: m.Dog) -> str + + Invoked with: + """ + + +def test_automatic_upcasting(): + from pybind11_tests import return_class_1, return_class_2, return_class_n, return_none + + assert type(return_class_1()).__name__ == "DerivedClass1" + assert type(return_class_2()).__name__ == "DerivedClass2" + assert type(return_none()).__name__ == "NoneType" + # Repeat these a few times in a random order to ensure no invalid caching is applied + assert type(return_class_n(1)).__name__ == "DerivedClass1" + assert type(return_class_n(2)).__name__ == "DerivedClass2" + assert type(return_class_n(0)).__name__ == "BaseClass" + assert type(return_class_n(2)).__name__ == "DerivedClass2" + assert type(return_class_n(2)).__name__ == "DerivedClass2" + assert type(return_class_n(0)).__name__ == "BaseClass" + assert type(return_class_n(1)).__name__ == "DerivedClass1" + + +def test_isinstance(): + from pybind11_tests import test_isinstance, Pet, Dog + + objects = [tuple(), dict(), Pet("Polly", "parrot")] + [Dog("Molly")] * 4 + expected = (True, True, True, True, True, False, False) + assert test_isinstance(objects) == expected diff --git a/resources/pybind11/tests/test_issues.cpp b/resources/pybind11/tests/test_issues.cpp new file mode 100755 index 0000000..378da52 --- /dev/null +++ b/resources/pybind11/tests/test_issues.cpp @@ -0,0 +1,396 @@ +/* + tests/test_issues.cpp -- collection of testcases for miscellaneous issues + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include +#include +#include + +#define TRACKERS(CLASS) CLASS() { print_default_created(this); } ~CLASS() { print_destroyed(this); } +struct NestABase { int value = -2; TRACKERS(NestABase) }; +struct NestA : NestABase { int value = 3; NestA& operator+=(int i) { value += i; return *this; } TRACKERS(NestA) }; +struct NestB { NestA a; int value = 4; NestB& operator-=(int i) { value -= i; return *this; } TRACKERS(NestB) }; +struct NestC { NestB b; int value = 5; NestC& operator*=(int i) { value *= i; return *this; } TRACKERS(NestC) }; + +/// #393 +class OpTest1 {}; +class OpTest2 {}; + +OpTest1 operator+(const OpTest1 &, const OpTest1 &) { + py::print("Add OpTest1 with OpTest1"); + return OpTest1(); +} +OpTest2 operator+(const OpTest2 &, const OpTest2 &) { + py::print("Add OpTest2 with OpTest2"); + return OpTest2(); +} +OpTest2 operator+(const OpTest2 &, const OpTest1 &) { + py::print("Add OpTest2 with OpTest1"); + return OpTest2(); +} + +// #461 +class Dupe1 { +public: + Dupe1(int v) : v_{v} {} + int get_value() const { return v_; } +private: + int v_; +}; +class Dupe2 {}; +class Dupe3 {}; +class DupeException : public std::runtime_error {}; + +// #478 +template class custom_unique_ptr { +public: + custom_unique_ptr() { print_default_created(this); } + custom_unique_ptr(T *ptr) : _ptr{ptr} { print_created(this, ptr); } + custom_unique_ptr(custom_unique_ptr &&move) : _ptr{move._ptr} { move._ptr = nullptr; print_move_created(this); } + custom_unique_ptr &operator=(custom_unique_ptr &&move) { print_move_assigned(this); if (_ptr) destruct_ptr(); _ptr = move._ptr; move._ptr = nullptr; return *this; } + custom_unique_ptr(const custom_unique_ptr &) = delete; + void operator=(const custom_unique_ptr ©) = delete; + ~custom_unique_ptr() { print_destroyed(this); if (_ptr) destruct_ptr(); } +private: + T *_ptr = nullptr; + void destruct_ptr() { delete _ptr; } +}; +PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr); + +/// Issue #528: templated constructor +struct TplConstrClass { + template TplConstrClass(const T &arg) : str{arg} {} + std::string str; + bool operator==(const TplConstrClass &t) const { return t.str == str; } +}; +namespace std { +template <> struct hash { size_t operator()(const TplConstrClass &t) const { return std::hash()(t.str); } }; +} + + +void init_issues(py::module &m) { + py::module m2 = m.def_submodule("issues"); + +#if !defined(_MSC_VER) + // Visual Studio 2015 currently cannot compile this test + // (see the comment in type_caster_base::make_copy_constructor) + // #70 compilation issue if operator new is not public + class NonConstructible { private: void *operator new(size_t bytes) throw(); }; + py::class_(m, "Foo"); + m2.def("getstmt", []() -> NonConstructible * { return nullptr; }, + py::return_value_policy::reference); +#endif + + // #137: const char* isn't handled properly + m2.def("print_cchar", [](const char *s) { return std::string(s); }); + + // #150: char bindings broken + m2.def("print_char", [](char c) { return std::string(1, c); }); + + // #159: virtual function dispatch has problems with similar-named functions + struct Base { virtual std::string dispatch() const { + /* for some reason MSVC2015 can't compile this if the function is pure virtual */ + return {}; + }; }; + + struct DispatchIssue : Base { + virtual std::string dispatch() const { + PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */); + } + }; + + py::class_(m2, "DispatchIssue") + .def(py::init<>()) + .def("dispatch", &Base::dispatch); + + m2.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); }); + + struct Placeholder { int i; Placeholder(int i) : i(i) { } }; + + py::class_(m2, "Placeholder") + .def(py::init()) + .def("__repr__", [](const Placeholder &p) { return "Placeholder[" + std::to_string(p.i) + "]"; }); + + // #171: Can't return reference wrappers (or STL datastructures containing them) + m2.def("return_vec_of_reference_wrapper", [](std::reference_wrapper p4) { + Placeholder *p1 = new Placeholder{1}; + Placeholder *p2 = new Placeholder{2}; + Placeholder *p3 = new Placeholder{3}; + std::vector> v; + v.push_back(std::ref(*p1)); + v.push_back(std::ref(*p2)); + v.push_back(std::ref(*p3)); + v.push_back(p4); + return v; + }); + + // #181: iterator passthrough did not compile + m2.def("iterator_passthrough", [](py::iterator s) -> py::iterator { + return py::make_iterator(std::begin(s), std::end(s)); + }); + + // #187: issue involving std::shared_ptr<> return value policy & garbage collection + struct ElementBase { virtual void foo() { } /* Force creation of virtual table */ }; + struct ElementA : ElementBase { + ElementA(int v) : v(v) { } + int value() { return v; } + int v; + }; + + struct ElementList { + void add(std::shared_ptr e) { l.push_back(e); } + std::vector> l; + }; + + py::class_> (m2, "ElementBase"); + + py::class_>(m2, "ElementA") + .def(py::init()) + .def("value", &ElementA::value); + + py::class_>(m2, "ElementList") + .def(py::init<>()) + .def("add", &ElementList::add) + .def("get", [](ElementList &el) { + py::list list; + for (auto &e : el.l) + list.append(py::cast(e)); + return list; + }); + + // (no id): should not be able to pass 'None' to a reference argument + m2.def("get_element", [](ElementA &el) { return el.value(); }); + + // (no id): don't cast doubles to ints + m2.def("expect_float", [](float f) { return f; }); + m2.def("expect_int", [](int i) { return i; }); + + try { + py::class_(m2, "Placeholder"); + throw std::logic_error("Expected an exception!"); + } catch (std::runtime_error &) { + /* All good */ + } + + // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid + class StrIssue { + public: + StrIssue(int i) : val{i} {} + StrIssue() : StrIssue(-1) {} + int value() const { return val; } + private: + int val; + }; + py::class_ si(m2, "StrIssue"); + si .def(py::init()) + .def(py::init<>()) + .def("__str__", [](const StrIssue &si) { return "StrIssue[" + std::to_string(si.value()) + "]"; }) + ; + + // Issue #328: first member in a class can't be used in operators + py::class_(m2, "NestABase").def(py::init<>()).def_readwrite("value", &NestABase::value); + py::class_(m2, "NestA").def(py::init<>()).def(py::self += int()) + .def("as_base", [](NestA &a) -> NestABase& { return (NestABase&) a; }, py::return_value_policy::reference_internal); + py::class_(m2, "NestB").def(py::init<>()).def(py::self -= int()).def_readwrite("a", &NestB::a); + py::class_(m2, "NestC").def(py::init<>()).def(py::self *= int()).def_readwrite("b", &NestC::b); + m2.def("get_NestA", [](const NestA &a) { return a.value; }); + m2.def("get_NestB", [](const NestB &b) { return b.value; }); + m2.def("get_NestC", [](const NestC &c) { return c.value; }); + + // Issue 389: r_v_p::move should fall-through to copy on non-movable objects + class MoveIssue1 { + public: + MoveIssue1(int v) : v{v} {} + MoveIssue1(const MoveIssue1 &c) { v = c.v; } + MoveIssue1(MoveIssue1 &&) = delete; + int v; + }; + class MoveIssue2 { + public: + MoveIssue2(int v) : v{v} {} + MoveIssue2(MoveIssue2 &&) = default; + int v; + }; + py::class_(m2, "MoveIssue1").def(py::init()).def_readwrite("value", &MoveIssue1::v); + py::class_(m2, "MoveIssue2").def(py::init()).def_readwrite("value", &MoveIssue2::v); + m2.def("get_moveissue1", [](int i) -> MoveIssue1 * { return new MoveIssue1(i); }, py::return_value_policy::move); + m2.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move); + + // Issues 392/397: overridding reference-returning functions + class OverrideTest { + public: + struct A { std::string value = "hi"; }; + std::string v; + A a; + explicit OverrideTest(const std::string &v) : v{v} {} + virtual std::string str_value() { return v; } + virtual std::string &str_ref() { return v; } + virtual A A_value() { return a; } + virtual A &A_ref() { return a; } + }; + class PyOverrideTest : public OverrideTest { + public: + using OverrideTest::OverrideTest; + std::string str_value() override { PYBIND11_OVERLOAD(std::string, OverrideTest, str_value); } + // Not allowed (uncommenting should hit a static_assert failure): we can't get a reference + // to a python numeric value, since we only copy values in the numeric type caster: +// std::string &str_ref() override { PYBIND11_OVERLOAD(std::string &, OverrideTest, str_ref); } + // But we can work around it like this: + private: + std::string _tmp; + std::string str_ref_helper() { PYBIND11_OVERLOAD(std::string, OverrideTest, str_ref); } + public: + std::string &str_ref() override { return _tmp = str_ref_helper(); } + + A A_value() override { PYBIND11_OVERLOAD(A, OverrideTest, A_value); } + A &A_ref() override { PYBIND11_OVERLOAD(A &, OverrideTest, A_ref); } + }; + py::class_(m2, "OverrideTest_A") + .def_readwrite("value", &OverrideTest::A::value); + py::class_(m2, "OverrideTest") + .def(py::init()) + .def("str_value", &OverrideTest::str_value) +// .def("str_ref", &OverrideTest::str_ref) + .def("A_value", &OverrideTest::A_value) + .def("A_ref", &OverrideTest::A_ref); + + /// Issue 393: need to return NotSupported to ensure correct arithmetic operator behavior + py::class_(m2, "OpTest1") + .def(py::init<>()) + .def(py::self + py::self); + + py::class_(m2, "OpTest2") + .def(py::init<>()) + .def(py::self + py::self) + .def("__add__", [](const OpTest2& c2, const OpTest1& c1) { return c2 + c1; }) + .def("__radd__", [](const OpTest2& c2, const OpTest1& c1) { return c2 + c1; }); + + // Issue 388: Can't make iterators via make_iterator() with different r/v policies + static std::vector list = { 1, 2, 3 }; + m2.def("make_iterator_1", []() { return py::make_iterator(list); }); + m2.def("make_iterator_2", []() { return py::make_iterator(list); }); + + static std::vector nothrows; + // Issue 461: registering two things with the same name: + py::class_(m2, "Dupe1") + .def("get_value", &Dupe1::get_value) + ; + m2.def("dupe1_factory", [](int v) { return new Dupe1(v); }); + + py::class_(m2, "Dupe2"); + py::exception(m2, "DupeException"); + + try { + m2.def("Dupe1", [](int v) { return new Dupe1(v); }); + nothrows.emplace_back("Dupe1"); + } + catch (std::runtime_error &) {} + try { + py::class_(m2, "dupe1_factory"); + nothrows.emplace_back("dupe1_factory"); + } + catch (std::runtime_error &) {} + try { + py::exception(m2, "Dupe2"); + nothrows.emplace_back("Dupe2"); + } + catch (std::runtime_error &) {} + try { + m2.def("DupeException", []() { return 30; }); + nothrows.emplace_back("DupeException1"); + } + catch (std::runtime_error &) {} + try { + py::class_(m2, "DupeException"); + nothrows.emplace_back("DupeException2"); + } + catch (std::runtime_error &) {} + m2.def("dupe_exception_failures", []() { + py::list l; + for (auto &e : nothrows) l.append(py::cast(e)); + return l; + }); + + /// Issue #471: shared pointer instance not dellocated + class SharedChild : public std::enable_shared_from_this { + public: + SharedChild() { print_created(this); } + ~SharedChild() { print_destroyed(this); } + }; + + class SharedParent { + public: + SharedParent() : child(std::make_shared()) { } + const SharedChild &get_child() const { return *child; } + + private: + std::shared_ptr child; + }; + + py::class_>(m, "SharedChild"); + py::class_>(m, "SharedParent") + .def(py::init<>()) + .def("get_child", &SharedParent::get_child, py::return_value_policy::reference); + + /// Issue/PR #478: unique ptrs constructed and freed without destruction + class SpecialHolderObj { + public: + int val = 0; + SpecialHolderObj *ch = nullptr; + SpecialHolderObj(int v, bool make_child = true) : val{v}, ch{make_child ? new SpecialHolderObj(val+1, false) : nullptr} + { print_created(this, val); } + ~SpecialHolderObj() { delete ch; print_destroyed(this); } + SpecialHolderObj *child() { return ch; } + }; + + py::class_>(m, "SpecialHolderObj") + .def(py::init()) + .def("child", &SpecialHolderObj::child, pybind11::return_value_policy::reference_internal) + .def_readwrite("val", &SpecialHolderObj::val) + .def_static("holder_cstats", &ConstructorStats::get>, + py::return_value_policy::reference); + + /// Issue #484: number conversion generates unhandled exceptions + m2.def("test_complex", [](float x) { py::print("{}"_s.format(x)); }); + m2.def("test_complex", [](std::complex x) { py::print("({}, {})"_s.format(x.real(), x.imag())); }); + + /// Issue #511: problem with inheritance + overwritten def_static + struct MyBase { + static std::unique_ptr make() { + return std::unique_ptr(new MyBase()); + } + }; + + struct MyDerived : MyBase { + static std::unique_ptr make() { + return std::unique_ptr(new MyDerived()); + } + }; + + py::class_(m2, "MyBase") + .def_static("make", &MyBase::make); + + py::class_(m2, "MyDerived") + .def_static("make", &MyDerived::make) + .def_static("make2", &MyDerived::make); + + /// Issue #528: templated constructor + m2.def("tpl_constr_vector", [](std::vector &) {}); + m2.def("tpl_constr_map", [](std::unordered_map &) {}); + m2.def("tpl_constr_set", [](std::unordered_set &) {}); +#if defined(PYBIND11_HAS_OPTIONAL) + m2.def("tpl_constr_optional", [](std::optional &) {}); +#elif defined(PYBIND11_HAS_EXP_OPTIONAL) + m2.def("tpl_constr_optional", [](std::experimental::optional &) {}); +#endif +} + +// MSVC workaround: trying to use a lambda here crashes MSCV +test_initializer issues(&init_issues); diff --git a/resources/pybind11/tests/test_issues.py b/resources/pybind11/tests/test_issues.py new file mode 100755 index 0000000..2098ff8 --- /dev/null +++ b/resources/pybind11/tests/test_issues.py @@ -0,0 +1,252 @@ +import pytest +import gc +from pybind11_tests import ConstructorStats + + +def test_regressions(): + from pybind11_tests.issues import print_cchar, print_char + + # #137: const char* isn't handled properly + assert print_cchar("const char *") == "const char *" + # #150: char bindings broken + assert print_char("c") == "c" + + +def test_dispatch_issue(msg): + """#159: virtual function dispatch has problems with similar-named functions""" + from pybind11_tests.issues import DispatchIssue, dispatch_issue_go + + class PyClass1(DispatchIssue): + def dispatch(self): + return "Yay.." + + class PyClass2(DispatchIssue): + def dispatch(self): + with pytest.raises(RuntimeError) as excinfo: + super(PyClass2, self).dispatch() + assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"' + + p = PyClass1() + return dispatch_issue_go(p) + + b = PyClass2() + assert dispatch_issue_go(b) == "Yay.." + + +def test_reference_wrapper(): + """#171: Can't return reference wrappers (or STL data structures containing them)""" + from pybind11_tests.issues import Placeholder, return_vec_of_reference_wrapper + + assert str(return_vec_of_reference_wrapper(Placeholder(4))) == \ + "[Placeholder[1], Placeholder[2], Placeholder[3], Placeholder[4]]" + + +def test_iterator_passthrough(): + """#181: iterator passthrough did not compile""" + from pybind11_tests.issues import iterator_passthrough + + assert list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15]))) == [3, 5, 7, 9, 11, 13, 15] + + +def test_shared_ptr_gc(): + """// #187: issue involving std::shared_ptr<> return value policy & garbage collection""" + from pybind11_tests.issues import ElementList, ElementA + + el = ElementList() + for i in range(10): + el.add(ElementA(i)) + gc.collect() + for i, v in enumerate(el.get()): + assert i == v.value() + + +def test_no_id(msg): + from pybind11_tests.issues import get_element, expect_float, expect_int + + with pytest.raises(TypeError) as excinfo: + get_element(None) + assert msg(excinfo.value) == """ + get_element(): incompatible function arguments. The following argument types are supported: + 1. (arg0: m.issues.ElementA) -> int + + Invoked with: None + """ + + with pytest.raises(TypeError) as excinfo: + expect_int(5.2) + assert msg(excinfo.value) == """ + expect_int(): incompatible function arguments. The following argument types are supported: + 1. (arg0: int) -> int + + Invoked with: 5.2 + """ + assert expect_float(12) == 12 + + +def test_str_issue(msg): + """Issue #283: __str__ called on uninitialized instance when constructor arguments invalid""" + from pybind11_tests.issues import StrIssue + + assert str(StrIssue(3)) == "StrIssue[3]" + + with pytest.raises(TypeError) as excinfo: + str(StrIssue("no", "such", "constructor")) + assert msg(excinfo.value) == """ + __init__(): incompatible constructor arguments. The following argument types are supported: + 1. m.issues.StrIssue(arg0: int) + 2. m.issues.StrIssue() + + Invoked with: 'no', 'such', 'constructor' + """ + + +def test_nested(): + """ #328: first member in a class can't be used in operators""" + from pybind11_tests.issues import NestA, NestB, NestC, get_NestA, get_NestB, get_NestC + + a = NestA() + b = NestB() + c = NestC() + + a += 10 + assert get_NestA(a) == 13 + b.a += 100 + assert get_NestA(b.a) == 103 + c.b.a += 1000 + assert get_NestA(c.b.a) == 1003 + b -= 1 + assert get_NestB(b) == 3 + c.b -= 3 + assert get_NestB(c.b) == 1 + c *= 7 + assert get_NestC(c) == 35 + + abase = a.as_base() + assert abase.value == -2 + a.as_base().value += 44 + assert abase.value == 42 + assert c.b.a.as_base().value == -2 + c.b.a.as_base().value += 44 + assert c.b.a.as_base().value == 42 + + del c + gc.collect() + del a # Should't delete while abase is still alive + gc.collect() + + assert abase.value == 42 + del abase, b + gc.collect() + + +def test_move_fallback(): + from pybind11_tests.issues import get_moveissue1, get_moveissue2 + m2 = get_moveissue2(2) + assert m2.value == 2 + m1 = get_moveissue1(1) + assert m1.value == 1 + + +def test_override_ref(): + from pybind11_tests.issues import OverrideTest + o = OverrideTest("asdf") + + # Not allowed (see associated .cpp comment) + # i = o.str_ref() + # assert o.str_ref() == "asdf" + assert o.str_value() == "asdf" + + assert o.A_value().value == "hi" + a = o.A_ref() + assert a.value == "hi" + a.value = "bye" + assert a.value == "bye" + + +def test_operators_notimplemented(capture): + from pybind11_tests.issues import OpTest1, OpTest2 + with capture: + c1, c2 = OpTest1(), OpTest2() + c1 + c1 + c2 + c2 + c2 + c1 + c1 + c2 + assert capture == """ + Add OpTest1 with OpTest1 + Add OpTest2 with OpTest2 + Add OpTest2 with OpTest1 + Add OpTest2 with OpTest1 + """ + + +def test_iterator_rvpolicy(): + """ Issue 388: Can't make iterators via make_iterator() with different r/v policies """ + from pybind11_tests.issues import make_iterator_1 + from pybind11_tests.issues import make_iterator_2 + + assert list(make_iterator_1()) == [1, 2, 3] + assert list(make_iterator_2()) == [1, 2, 3] + assert not isinstance(make_iterator_1(), type(make_iterator_2())) + + +def test_dupe_assignment(): + """ Issue 461: overwriting a class with a function """ + from pybind11_tests.issues import dupe_exception_failures + assert dupe_exception_failures() == [] + + +def test_enable_shared_from_this_with_reference_rvp(): + """ Issue #471: shared pointer instance not dellocated """ + from pybind11_tests import SharedParent, SharedChild + + parent = SharedParent() + child = parent.get_child() + + cstats = ConstructorStats.get(SharedChild) + assert cstats.alive() == 1 + del child, parent + assert cstats.alive() == 0 + + +def test_non_destructed_holders(): + """ Issue #478: unique ptrs constructed and freed without destruction """ + from pybind11_tests import SpecialHolderObj + + a = SpecialHolderObj(123) + b = a.child() + + assert a.val == 123 + assert b.val == 124 + + cstats = SpecialHolderObj.holder_cstats() + assert cstats.alive() == 1 + del b + assert cstats.alive() == 1 + del a + assert cstats.alive() == 0 + + +def test_complex_cast(capture): + """ Issue #484: number conversion generates unhandled exceptions """ + from pybind11_tests.issues import test_complex + + with capture: + test_complex(1) + test_complex(2j) + + assert capture == """ + 1.0 + (0.0, 2.0) + """ + + +def test_inheritance_override_def_static(): + from pybind11_tests.issues import MyBase, MyDerived + + b = MyBase.make() + d1 = MyDerived.make2() + d2 = MyDerived.make() + + assert isinstance(b, MyBase) + assert isinstance(d1, MyDerived) + assert isinstance(d2, MyDerived) diff --git a/resources/pybind11/tests/test_keep_alive.cpp b/resources/pybind11/tests/test_keep_alive.cpp new file mode 100755 index 0000000..cd62a02 --- /dev/null +++ b/resources/pybind11/tests/test_keep_alive.cpp @@ -0,0 +1,40 @@ +/* + tests/test_keep_alive.cpp -- keep_alive modifier (pybind11's version + of Boost.Python's with_custodian_and_ward / with_custodian_and_ward_postcall) + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +class Child { +public: + Child() { py::print("Allocating child."); } + ~Child() { py::print("Releasing child."); } +}; + +class Parent { +public: + Parent() { py::print("Allocating parent."); } + ~Parent() { py::print("Releasing parent."); } + void addChild(Child *) { } + Child *returnChild() { return new Child(); } + Child *returnNullChild() { return nullptr; } +}; + +test_initializer keep_alive([](py::module &m) { + py::class_(m, "Parent") + .def(py::init<>()) + .def("addChild", &Parent::addChild) + .def("addChildKeepAlive", &Parent::addChild, py::keep_alive<1, 2>()) + .def("returnChild", &Parent::returnChild) + .def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>()) + .def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>()) + .def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>()); + + py::class_(m, "Child") + .def(py::init<>()); +}); diff --git a/resources/pybind11/tests/test_keep_alive.py b/resources/pybind11/tests/test_keep_alive.py new file mode 100755 index 0000000..0cef346 --- /dev/null +++ b/resources/pybind11/tests/test_keep_alive.py @@ -0,0 +1,97 @@ +import gc + + +def test_keep_alive_argument(capture): + from pybind11_tests import Parent, Child + + with capture: + p = Parent() + assert capture == "Allocating parent." + with capture: + p.addChild(Child()) + gc.collect() + assert capture == """ + Allocating child. + Releasing child. + """ + with capture: + del p + gc.collect() + assert capture == "Releasing parent." + + with capture: + p = Parent() + assert capture == "Allocating parent." + with capture: + p.addChildKeepAlive(Child()) + gc.collect() + assert capture == "Allocating child." + with capture: + del p + gc.collect() + assert capture == """ + Releasing parent. + Releasing child. + """ + + +def test_keep_alive_return_value(capture): + from pybind11_tests import Parent + + with capture: + p = Parent() + assert capture == "Allocating parent." + with capture: + p.returnChild() + gc.collect() + assert capture == """ + Allocating child. + Releasing child. + """ + with capture: + del p + gc.collect() + assert capture == "Releasing parent." + + with capture: + p = Parent() + assert capture == "Allocating parent." + with capture: + p.returnChildKeepAlive() + gc.collect() + assert capture == "Allocating child." + with capture: + del p + gc.collect() + assert capture == """ + Releasing parent. + Releasing child. + """ + + +def test_return_none(capture): + from pybind11_tests import Parent + + with capture: + p = Parent() + assert capture == "Allocating parent." + with capture: + p.returnNullChildKeepAliveChild() + gc.collect() + assert capture == "" + with capture: + del p + gc.collect() + assert capture == "Releasing parent." + + with capture: + p = Parent() + assert capture == "Allocating parent." + with capture: + p.returnNullChildKeepAliveParent() + gc.collect() + assert capture == "" + with capture: + del p + gc.collect() + assert capture == "Releasing parent." diff --git a/resources/pybind11/tests/test_kwargs_and_defaults.cpp b/resources/pybind11/tests/test_kwargs_and_defaults.cpp new file mode 100755 index 0000000..24fc0cd --- /dev/null +++ b/resources/pybind11/tests/test_kwargs_and_defaults.cpp @@ -0,0 +1,56 @@ +/* + tests/test_kwargs_and_defaults.cpp -- keyword arguments and default values + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include + +std::string kw_func(int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); } + +std::string kw_func4(const std::vector &entries) { + std::string ret = "{"; + for (int i : entries) + ret += std::to_string(i) + " "; + ret.back() = '}'; + return ret; +} + +py::tuple args_function(py::args args) { + return args; +} + +py::tuple args_kwargs_function(py::args args, py::kwargs kwargs) { + return py::make_tuple(args, kwargs); +} + +struct KWClass { + void foo(int, float) {} +}; + +test_initializer arg_keywords_and_defaults([](py::module &m) { + m.def("kw_func0", &kw_func); + m.def("kw_func1", &kw_func, py::arg("x"), py::arg("y")); + m.def("kw_func2", &kw_func, py::arg("x") = 100, py::arg("y") = 200); + m.def("kw_func3", [](const char *) { }, py::arg("data") = std::string("Hello world!")); + + /* A fancier default argument */ + std::vector list; + list.push_back(13); + list.push_back(17); + m.def("kw_func4", &kw_func4, py::arg("myList") = list); + + m.def("args_function", &args_function); + m.def("args_kwargs_function", &args_kwargs_function); + + m.def("kw_func_udl", &kw_func, "x"_a, "y"_a=300); + m.def("kw_func_udl_z", &kw_func, "x"_a, "y"_a=0); + + py::class_(m, "KWClass") + .def("foo0", &KWClass::foo) + .def("foo1", &KWClass::foo, "x"_a, "y"_a); +}); diff --git a/resources/pybind11/tests/test_kwargs_and_defaults.py b/resources/pybind11/tests/test_kwargs_and_defaults.py new file mode 100755 index 0000000..852d03c --- /dev/null +++ b/resources/pybind11/tests/test_kwargs_and_defaults.py @@ -0,0 +1,57 @@ +import pytest +from pybind11_tests import (kw_func0, kw_func1, kw_func2, kw_func3, kw_func4, args_function, + args_kwargs_function, kw_func_udl, kw_func_udl_z, KWClass) + + +def test_function_signatures(doc): + assert doc(kw_func0) == "kw_func0(arg0: int, arg1: int) -> str" + assert doc(kw_func1) == "kw_func1(x: int, y: int) -> str" + assert doc(kw_func2) == "kw_func2(x: int=100, y: int=200) -> str" + assert doc(kw_func3) == "kw_func3(data: str='Hello world!') -> None" + assert doc(kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> str" + assert doc(kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> str" + assert doc(kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> str" + assert doc(args_function) == "args_function(*args) -> tuple" + assert doc(args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple" + assert doc(KWClass.foo0) == "foo0(self: m.KWClass, arg0: int, arg1: float) -> None" + assert doc(KWClass.foo1) == "foo1(self: m.KWClass, x: int, y: float) -> None" + + +def test_named_arguments(msg): + assert kw_func0(5, 10) == "x=5, y=10" + + assert kw_func1(5, 10) == "x=5, y=10" + assert kw_func1(5, y=10) == "x=5, y=10" + assert kw_func1(y=10, x=5) == "x=5, y=10" + + assert kw_func2() == "x=100, y=200" + assert kw_func2(5) == "x=5, y=200" + assert kw_func2(x=5) == "x=5, y=200" + assert kw_func2(y=10) == "x=100, y=10" + assert kw_func2(5, 10) == "x=5, y=10" + assert kw_func2(x=5, y=10) == "x=5, y=10" + + with pytest.raises(TypeError) as excinfo: + # noinspection PyArgumentList + kw_func2(x=5, y=10, z=12) + assert msg(excinfo.value) == """ + kw_func2(): incompatible function arguments. The following argument types are supported: + 1. (x: int=100, y: int=200) -> str + + Invoked with: + """ + + assert kw_func4() == "{13 17}" + assert kw_func4(myList=[1, 2, 3]) == "{1 2 3}" + + assert kw_func_udl(x=5, y=10) == "x=5, y=10" + assert kw_func_udl_z(x=5) == "x=5, y=0" + + +def test_arg_and_kwargs(): + args = 'arg1_value', 'arg2_value', 3 + assert args_function(*args) == args + + args = 'a1', 'a2' + kwargs = dict(arg3='a3', arg4=4) + assert args_kwargs_function(*args, **kwargs) == (args, kwargs) diff --git a/resources/pybind11/tests/test_methods_and_attributes.cpp b/resources/pybind11/tests/test_methods_and_attributes.cpp new file mode 100755 index 0000000..ab59d8c --- /dev/null +++ b/resources/pybind11/tests/test_methods_and_attributes.cpp @@ -0,0 +1,169 @@ +/* + tests/test_methods_and_attributes.cpp -- constructors, deconstructors, attribute access, + __str__, argument and return value conventions + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" + +class ExampleMandA { +public: + ExampleMandA() { print_default_created(this); } + ExampleMandA(int value) : value(value) { print_created(this, value); } + ExampleMandA(const ExampleMandA &e) : value(e.value) { print_copy_created(this); } + ExampleMandA(ExampleMandA &&e) : value(e.value) { print_move_created(this); } + ~ExampleMandA() { print_destroyed(this); } + + std::string toString() { + return "ExampleMandA[value=" + std::to_string(value) + "]"; + } + + void operator=(const ExampleMandA &e) { print_copy_assigned(this); value = e.value; } + void operator=(ExampleMandA &&e) { print_move_assigned(this); value = e.value; } + + void add1(ExampleMandA other) { value += other.value; } // passing by value + void add2(ExampleMandA &other) { value += other.value; } // passing by reference + void add3(const ExampleMandA &other) { value += other.value; } // passing by const reference + void add4(ExampleMandA *other) { value += other->value; } // passing by pointer + void add5(const ExampleMandA *other) { value += other->value; } // passing by const pointer + + void add6(int other) { value += other; } // passing by value + void add7(int &other) { value += other; } // passing by reference + void add8(const int &other) { value += other; } // passing by const reference + void add9(int *other) { value += *other; } // passing by pointer + void add10(const int *other) { value += *other; } // passing by const pointer + + ExampleMandA self1() { return *this; } // return by value + ExampleMandA &self2() { return *this; } // return by reference + const ExampleMandA &self3() { return *this; } // return by const reference + ExampleMandA *self4() { return this; } // return by pointer + const ExampleMandA *self5() { return this; } // return by const pointer + + int internal1() { return value; } // return by value + int &internal2() { return value; } // return by reference + const int &internal3() { return value; } // return by const reference + int *internal4() { return &value; } // return by pointer + const int *internal5() { return &value; } // return by const pointer + + int value = 0; +}; + +struct TestProperties { + int value = 1; + static int static_value; + + int get() const { return value; } + void set(int v) { value = v; } + + static int static_get() { return static_value; } + static void static_set(int v) { static_value = v; } +}; + +int TestProperties::static_value = 1; + +struct SimpleValue { int value = 1; }; + +struct TestPropRVP { + SimpleValue v1; + SimpleValue v2; + static SimpleValue sv1; + static SimpleValue sv2; + + const SimpleValue &get1() const { return v1; } + const SimpleValue &get2() const { return v2; } + SimpleValue get_rvalue() const { return v2; } + void set1(int v) { v1.value = v; } + void set2(int v) { v2.value = v; } +}; + +SimpleValue TestPropRVP::sv1{}; +SimpleValue TestPropRVP::sv2{}; + +class DynamicClass { +public: + DynamicClass() { print_default_created(this); } + ~DynamicClass() { print_destroyed(this); } +}; + +class CppDerivedDynamicClass : public DynamicClass { }; + +test_initializer methods_and_attributes([](py::module &m) { + py::class_(m, "ExampleMandA") + .def(py::init<>()) + .def(py::init()) + .def(py::init()) + .def("add1", &ExampleMandA::add1) + .def("add2", &ExampleMandA::add2) + .def("add3", &ExampleMandA::add3) + .def("add4", &ExampleMandA::add4) + .def("add5", &ExampleMandA::add5) + .def("add6", &ExampleMandA::add6) + .def("add7", &ExampleMandA::add7) + .def("add8", &ExampleMandA::add8) + .def("add9", &ExampleMandA::add9) + .def("add10", &ExampleMandA::add10) + .def("self1", &ExampleMandA::self1) + .def("self2", &ExampleMandA::self2) + .def("self3", &ExampleMandA::self3) + .def("self4", &ExampleMandA::self4) + .def("self5", &ExampleMandA::self5) + .def("internal1", &ExampleMandA::internal1) + .def("internal2", &ExampleMandA::internal2) + .def("internal3", &ExampleMandA::internal3) + .def("internal4", &ExampleMandA::internal4) + .def("internal5", &ExampleMandA::internal5) + .def("__str__", &ExampleMandA::toString) + .def_readwrite("value", &ExampleMandA::value) + ; + + py::class_(m, "TestProperties") + .def(py::init<>()) + .def_readonly("def_readonly", &TestProperties::value) + .def_readwrite("def_readwrite", &TestProperties::value) + .def_property_readonly("def_property_readonly", &TestProperties::get) + .def_property("def_property", &TestProperties::get, &TestProperties::set) + .def_readonly_static("def_readonly_static", &TestProperties::static_value) + .def_readwrite_static("def_readwrite_static", &TestProperties::static_value) + .def_property_readonly_static("def_property_readonly_static", + [](py::object) { return TestProperties::static_get(); }) + .def_property_static("def_property_static", + [](py::object) { return TestProperties::static_get(); }, + [](py::object, int v) { return TestProperties::static_set(v); }); + + py::class_(m, "SimpleValue") + .def_readwrite("value", &SimpleValue::value); + + auto static_get1 = [](py::object) -> const SimpleValue & { return TestPropRVP::sv1; }; + auto static_get2 = [](py::object) -> const SimpleValue & { return TestPropRVP::sv2; }; + auto static_set1 = [](py::object, int v) { TestPropRVP::sv1.value = v; }; + auto static_set2 = [](py::object, int v) { TestPropRVP::sv2.value = v; }; + auto rvp_copy = py::return_value_policy::copy; + + py::class_(m, "TestPropRVP") + .def(py::init<>()) + .def_property_readonly("ro_ref", &TestPropRVP::get1) + .def_property_readonly("ro_copy", &TestPropRVP::get2, rvp_copy) + .def_property_readonly("ro_func", py::cpp_function(&TestPropRVP::get2, rvp_copy)) + .def_property("rw_ref", &TestPropRVP::get1, &TestPropRVP::set1) + .def_property("rw_copy", &TestPropRVP::get2, &TestPropRVP::set2, rvp_copy) + .def_property("rw_func", py::cpp_function(&TestPropRVP::get2, rvp_copy), &TestPropRVP::set2) + .def_property_readonly_static("static_ro_ref", static_get1) + .def_property_readonly_static("static_ro_copy", static_get2, rvp_copy) + .def_property_readonly_static("static_ro_func", py::cpp_function(static_get2, rvp_copy)) + .def_property_static("static_rw_ref", static_get1, static_set1) + .def_property_static("static_rw_copy", static_get2, static_set2, rvp_copy) + .def_property_static("static_rw_func", py::cpp_function(static_get2, rvp_copy), static_set2) + .def_property_readonly("rvalue", &TestPropRVP::get_rvalue) + .def_property_readonly_static("static_rvalue", [](py::object) { return SimpleValue(); }); + + py::class_(m, "DynamicClass", py::dynamic_attr()) + .def(py::init()); + + py::class_(m, "CppDerivedDynamicClass") + .def(py::init()); +}); diff --git a/resources/pybind11/tests/test_methods_and_attributes.py b/resources/pybind11/tests/test_methods_and_attributes.py new file mode 100755 index 0000000..28c0de5 --- /dev/null +++ b/resources/pybind11/tests/test_methods_and_attributes.py @@ -0,0 +1,189 @@ +import pytest +from pybind11_tests import ExampleMandA, ConstructorStats + + +def test_methods_and_attributes(): + instance1 = ExampleMandA() + instance2 = ExampleMandA(32) + + instance1.add1(instance2) + instance1.add2(instance2) + instance1.add3(instance2) + instance1.add4(instance2) + instance1.add5(instance2) + instance1.add6(32) + instance1.add7(32) + instance1.add8(32) + instance1.add9(32) + instance1.add10(32) + + assert str(instance1) == "ExampleMandA[value=320]" + assert str(instance2) == "ExampleMandA[value=32]" + assert str(instance1.self1()) == "ExampleMandA[value=320]" + assert str(instance1.self2()) == "ExampleMandA[value=320]" + assert str(instance1.self3()) == "ExampleMandA[value=320]" + assert str(instance1.self4()) == "ExampleMandA[value=320]" + assert str(instance1.self5()) == "ExampleMandA[value=320]" + + assert instance1.internal1() == 320 + assert instance1.internal2() == 320 + assert instance1.internal3() == 320 + assert instance1.internal4() == 320 + assert instance1.internal5() == 320 + + assert instance1.value == 320 + instance1.value = 100 + assert str(instance1) == "ExampleMandA[value=100]" + + cstats = ConstructorStats.get(ExampleMandA) + assert cstats.alive() == 2 + del instance1, instance2 + assert cstats.alive() == 0 + assert cstats.values() == ["32"] + assert cstats.default_constructions == 1 + assert cstats.copy_constructions == 3 + assert cstats.move_constructions >= 1 + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + +def test_properties(): + from pybind11_tests import TestProperties + + instance = TestProperties() + + assert instance.def_readonly == 1 + with pytest.raises(AttributeError): + instance.def_readonly = 2 + + instance.def_readwrite = 2 + assert instance.def_readwrite == 2 + + assert instance.def_property_readonly == 2 + with pytest.raises(AttributeError): + instance.def_property_readonly = 3 + + instance.def_property = 3 + assert instance.def_property == 3 + + +def test_static_properties(): + from pybind11_tests import TestProperties as Type + + assert Type.def_readonly_static == 1 + with pytest.raises(AttributeError): + Type.def_readonly_static = 2 + + Type.def_readwrite_static = 2 + assert Type.def_readwrite_static == 2 + + assert Type.def_property_readonly_static == 2 + with pytest.raises(AttributeError): + Type.def_property_readonly_static = 3 + + Type.def_property_static = 3 + assert Type.def_property_static == 3 + + +@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"]) +def test_property_return_value_policies(access): + from pybind11_tests import TestPropRVP + + if not access.startswith("static"): + obj = TestPropRVP() + else: + obj = TestPropRVP + + ref = getattr(obj, access + "_ref") + assert ref.value == 1 + ref.value = 2 + assert getattr(obj, access + "_ref").value == 2 + ref.value = 1 # restore original value for static properties + + copy = getattr(obj, access + "_copy") + assert copy.value == 1 + copy.value = 2 + assert getattr(obj, access + "_copy").value == 1 + + copy = getattr(obj, access + "_func") + assert copy.value == 1 + copy.value = 2 + assert getattr(obj, access + "_func").value == 1 + + +def test_property_rvalue_policy(): + """When returning an rvalue, the return value policy is automatically changed from + `reference(_internal)` to `move`. The following would not work otherwise. + """ + from pybind11_tests import TestPropRVP + + instance = TestPropRVP() + o = instance.rvalue + assert o.value == 1 + o = TestPropRVP.static_rvalue + assert o.value == 1 + + +def test_dynamic_attributes(): + from pybind11_tests import DynamicClass, CppDerivedDynamicClass + + instance = DynamicClass() + assert not hasattr(instance, "foo") + assert "foo" not in dir(instance) + + # Dynamically add attribute + instance.foo = 42 + assert hasattr(instance, "foo") + assert instance.foo == 42 + assert "foo" in dir(instance) + + # __dict__ should be accessible and replaceable + assert "foo" in instance.__dict__ + instance.__dict__ = {"bar": True} + assert not hasattr(instance, "foo") + assert hasattr(instance, "bar") + + with pytest.raises(TypeError) as excinfo: + instance.__dict__ = [] + assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'" + + cstats = ConstructorStats.get(DynamicClass) + assert cstats.alive() == 1 + del instance + assert cstats.alive() == 0 + + # Derived classes should work as well + class PythonDerivedDynamicClass(DynamicClass): + pass + + for cls in CppDerivedDynamicClass, PythonDerivedDynamicClass: + derived = cls() + derived.foobar = 100 + assert derived.foobar == 100 + + assert cstats.alive() == 1 + del derived + assert cstats.alive() == 0 + + +def test_cyclic_gc(): + from pybind11_tests import DynamicClass + + # One object references itself + instance = DynamicClass() + instance.circular_reference = instance + + cstats = ConstructorStats.get(DynamicClass) + assert cstats.alive() == 1 + del instance + assert cstats.alive() == 0 + + # Two object reference each other + i1 = DynamicClass() + i2 = DynamicClass() + i1.cycle = i2 + i2.cycle = i1 + + assert cstats.alive() == 2 + del i1, i2 + assert cstats.alive() == 0 diff --git a/resources/pybind11/tests/test_modules.cpp b/resources/pybind11/tests/test_modules.cpp new file mode 100755 index 0000000..50c7d84 --- /dev/null +++ b/resources/pybind11/tests/test_modules.cpp @@ -0,0 +1,58 @@ +/* + tests/test_modules.cpp -- nested modules, importing modules, and + internal references + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" + +std::string submodule_func() { + return "submodule_func()"; +} + +class A { +public: + A(int v) : v(v) { print_created(this, v); } + ~A() { print_destroyed(this); } + A(const A&) { print_copy_created(this); } + A& operator=(const A ©) { print_copy_assigned(this); v = copy.v; return *this; } + std::string toString() { return "A[" + std::to_string(v) + "]"; } +private: + int v; +}; + +class B { +public: + B() { print_default_created(this); } + ~B() { print_destroyed(this); } + B(const B&) { print_copy_created(this); } + B& operator=(const B ©) { print_copy_assigned(this); a1 = copy.a1; a2 = copy.a2; return *this; } + A &get_a1() { return a1; } + A &get_a2() { return a2; } + + A a1{1}; + A a2{2}; +}; + +test_initializer modules([](py::module &m) { + py::module m_sub = m.def_submodule("submodule"); + m_sub.def("submodule_func", &submodule_func); + + py::class_(m_sub, "A") + .def(py::init()) + .def("__repr__", &A::toString); + + py::class_(m_sub, "B") + .def(py::init<>()) + .def("get_a1", &B::get_a1, "Return the internal A 1", py::return_value_policy::reference_internal) + .def("get_a2", &B::get_a2, "Return the internal A 2", py::return_value_policy::reference_internal) + .def_readwrite("a1", &B::a1) // def_readonly uses an internal reference return policy by default + .def_readwrite("a2", &B::a2); + + m.attr("OD") = py::module::import("collections").attr("OrderedDict"); +}); diff --git a/resources/pybind11/tests/test_modules.py b/resources/pybind11/tests/test_modules.py new file mode 100755 index 0000000..fe72f19 --- /dev/null +++ b/resources/pybind11/tests/test_modules.py @@ -0,0 +1,54 @@ + +def test_nested_modules(): + import pybind11_tests + from pybind11_tests.submodule import submodule_func + + assert pybind11_tests.__name__ == "pybind11_tests" + assert pybind11_tests.submodule.__name__ == "pybind11_tests.submodule" + + assert submodule_func() == "submodule_func()" + + +def test_reference_internal(): + from pybind11_tests import ConstructorStats + from pybind11_tests.submodule import A, B + + b = B() + assert str(b.get_a1()) == "A[1]" + assert str(b.a1) == "A[1]" + assert str(b.get_a2()) == "A[2]" + assert str(b.a2) == "A[2]" + + b.a1 = A(42) + b.a2 = A(43) + assert str(b.get_a1()) == "A[42]" + assert str(b.a1) == "A[42]" + assert str(b.get_a2()) == "A[43]" + assert str(b.a2) == "A[43]" + + astats, bstats = ConstructorStats.get(A), ConstructorStats.get(B) + assert astats.alive() == 2 + assert bstats.alive() == 1 + del b + assert astats.alive() == 0 + assert bstats.alive() == 0 + assert astats.values() == ['1', '2', '42', '43'] + assert bstats.values() == [] + assert astats.default_constructions == 0 + assert bstats.default_constructions == 1 + assert astats.copy_constructions == 0 + assert bstats.copy_constructions == 0 + # assert astats.move_constructions >= 0 # Don't invoke any + # assert bstats.move_constructions >= 0 # Don't invoke any + assert astats.copy_assignments == 2 + assert bstats.copy_assignments == 0 + assert astats.move_assignments == 0 + assert bstats.move_assignments == 0 + + +def test_importing(): + from pybind11_tests import OD + from collections import OrderedDict + + assert OD is OrderedDict + assert str(OD([(1, 'a'), (2, 'b')])) == "OrderedDict([(1, 'a'), (2, 'b')])" diff --git a/resources/pybind11/tests/test_multiple_inheritance.cpp b/resources/pybind11/tests/test_multiple_inheritance.cpp new file mode 100755 index 0000000..3cb12b6 --- /dev/null +++ b/resources/pybind11/tests/test_multiple_inheritance.cpp @@ -0,0 +1,84 @@ +/* + tests/test_multiple_inheritance.cpp -- multiple inheritance, + implicit MI casts + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + + +struct Base1 { + Base1(int i) : i(i) { } + int foo() { return i; } + int i; +}; + +struct Base2 { + Base2(int i) : i(i) { } + int bar() { return i; } + int i; +}; + +struct Base12 : Base1, Base2 { + Base12(int i, int j) : Base1(i), Base2(j) { } +}; + +struct MIType : Base12 { + MIType(int i, int j) : Base12(i, j) { } +}; + +test_initializer multiple_inheritance([](py::module &m) { + py::class_(m, "Base1") + .def(py::init()) + .def("foo", &Base1::foo); + + py::class_(m, "Base2") + .def(py::init()) + .def("bar", &Base2::bar); + + py::class_(m, "Base12"); + + py::class_(m, "MIType") + .def(py::init()); +}); + +/* Test the case where not all base classes are specified, + and where pybind11 requires the py::multiple_inheritance + flag to perform proper casting between types */ + +struct Base1a { + Base1a(int i) : i(i) { } + int foo() { return i; } + int i; +}; + +struct Base2a { + Base2a(int i) : i(i) { } + int bar() { return i; } + int i; +}; + +struct Base12a : Base1a, Base2a { + Base12a(int i, int j) : Base1a(i), Base2a(j) { } +}; + +test_initializer multiple_inheritance_nonexplicit([](py::module &m) { + py::class_>(m, "Base1a") + .def(py::init()) + .def("foo", &Base1a::foo); + + py::class_>(m, "Base2a") + .def(py::init()) + .def("bar", &Base2a::bar); + + py::class_>(m, "Base12a", py::multiple_inheritance()) + .def(py::init()); + + m.def("bar_base2a", [](Base2a *b) { return b->bar(); }); + m.def("bar_base2a_sharedptr", [](std::shared_ptr b) { return b->bar(); }); +}); diff --git a/resources/pybind11/tests/test_multiple_inheritance.py b/resources/pybind11/tests/test_multiple_inheritance.py new file mode 100755 index 0000000..581cf56 --- /dev/null +++ b/resources/pybind11/tests/test_multiple_inheritance.py @@ -0,0 +1,64 @@ + + +def test_multiple_inheritance_cpp(): + from pybind11_tests import MIType + + mt = MIType(3, 4) + + assert mt.foo() == 3 + assert mt.bar() == 4 + + +def test_multiple_inheritance_mix1(): + from pybind11_tests import Base2 + + class Base1: + def __init__(self, i): + self.i = i + + def foo(self): + return self.i + + class MITypePy(Base1, Base2): + def __init__(self, i, j): + Base1.__init__(self, i) + Base2.__init__(self, j) + + mt = MITypePy(3, 4) + + assert mt.foo() == 3 + assert mt.bar() == 4 + + +def test_multiple_inheritance_mix2(): + from pybind11_tests import Base1 + + class Base2: + def __init__(self, i): + self.i = i + + def bar(self): + return self.i + + class MITypePy(Base1, Base2): + def __init__(self, i, j): + Base1.__init__(self, i) + Base2.__init__(self, j) + + mt = MITypePy(3, 4) + + assert mt.foo() == 3 + assert mt.bar() == 4 + + +def test_multiple_inheritance_virtbase(): + from pybind11_tests import Base12a, bar_base2a, bar_base2a_sharedptr + + class MITypePy(Base12a): + def __init__(self, i, j): + Base12a.__init__(self, i, j) + + mt = MITypePy(3, 4) + assert mt.bar() == 4 + assert bar_base2a(mt) == 4 + assert bar_base2a_sharedptr(mt) == 4 diff --git a/resources/pybind11/tests/test_numpy_array.cpp b/resources/pybind11/tests/test_numpy_array.cpp new file mode 100755 index 0000000..14c4c29 --- /dev/null +++ b/resources/pybind11/tests/test_numpy_array.cpp @@ -0,0 +1,153 @@ +/* + tests/test_numpy_array.cpp -- test core array functionality + + Copyright (c) 2016 Ivan Smirnov + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +#include +#include + +#include +#include + +using arr = py::array; +using arr_t = py::array_t; + +template arr data(const arr& a, Ix... index) { + return arr(a.nbytes() - a.offset_at(index...), (const uint8_t *) a.data(index...)); +} + +template arr data_t(const arr_t& a, Ix... index) { + return arr(a.size() - a.index_at(index...), a.data(index...)); +} + +arr& mutate_data(arr& a) { + auto ptr = (uint8_t *) a.mutable_data(); + for (size_t i = 0; i < a.nbytes(); i++) + ptr[i] = (uint8_t) (ptr[i] * 2); + return a; +} + +arr_t& mutate_data_t(arr_t& a) { + auto ptr = a.mutable_data(); + for (size_t i = 0; i < a.size(); i++) + ptr[i]++; + return a; +} + +template arr& mutate_data(arr& a, Ix... index) { + auto ptr = (uint8_t *) a.mutable_data(index...); + for (size_t i = 0; i < a.nbytes() - a.offset_at(index...); i++) + ptr[i] = (uint8_t) (ptr[i] * 2); + return a; +} + +template arr_t& mutate_data_t(arr_t& a, Ix... index) { + auto ptr = a.mutable_data(index...); + for (size_t i = 0; i < a.size() - a.index_at(index...); i++) + ptr[i]++; + return a; +} + +template size_t index_at(const arr& a, Ix... idx) { return a.index_at(idx...); } +template size_t index_at_t(const arr_t& a, Ix... idx) { return a.index_at(idx...); } +template size_t offset_at(const arr& a, Ix... idx) { return a.offset_at(idx...); } +template size_t offset_at_t(const arr_t& a, Ix... idx) { return a.offset_at(idx...); } +template size_t at_t(const arr_t& a, Ix... idx) { return a.at(idx...); } +template arr_t& mutate_at_t(arr_t& a, Ix... idx) { a.mutable_at(idx...)++; return a; } + +#define def_index_fn(name, type) \ + sm.def(#name, [](type a) { return name(a); }); \ + sm.def(#name, [](type a, int i) { return name(a, i); }); \ + sm.def(#name, [](type a, int i, int j) { return name(a, i, j); }); \ + sm.def(#name, [](type a, int i, int j, int k) { return name(a, i, j, k); }); + +test_initializer numpy_array([](py::module &m) { + auto sm = m.def_submodule("array"); + + sm.def("ndim", [](const arr& a) { return a.ndim(); }); + sm.def("shape", [](const arr& a) { return arr(a.ndim(), a.shape()); }); + sm.def("shape", [](const arr& a, size_t dim) { return a.shape(dim); }); + sm.def("strides", [](const arr& a) { return arr(a.ndim(), a.strides()); }); + sm.def("strides", [](const arr& a, size_t dim) { return a.strides(dim); }); + sm.def("writeable", [](const arr& a) { return a.writeable(); }); + sm.def("size", [](const arr& a) { return a.size(); }); + sm.def("itemsize", [](const arr& a) { return a.itemsize(); }); + sm.def("nbytes", [](const arr& a) { return a.nbytes(); }); + sm.def("owndata", [](const arr& a) { return a.owndata(); }); + + def_index_fn(data, const arr&); + def_index_fn(data_t, const arr_t&); + def_index_fn(index_at, const arr&); + def_index_fn(index_at_t, const arr_t&); + def_index_fn(offset_at, const arr&); + def_index_fn(offset_at_t, const arr_t&); + def_index_fn(mutate_data, arr&); + def_index_fn(mutate_data_t, arr_t&); + def_index_fn(at_t, const arr_t&); + def_index_fn(mutate_at_t, arr_t&); + + sm.def("make_f_array", [] { + return py::array_t({ 2, 2 }, { 4, 8 }); + }); + + sm.def("make_c_array", [] { + return py::array_t({ 2, 2 }, { 8, 4 }); + }); + + sm.def("wrap", [](py::array a) { + return py::array( + a.dtype(), + std::vector(a.shape(), a.shape() + a.ndim()), + std::vector(a.strides(), a.strides() + a.ndim()), + a.data(), + a + ); + }); + + struct ArrayClass { + int data[2] = { 1, 2 }; + ArrayClass() { py::print("ArrayClass()"); } + ~ArrayClass() { py::print("~ArrayClass()"); } + }; + + py::class_(sm, "ArrayClass") + .def(py::init<>()) + .def("numpy_view", [](py::object &obj) { + py::print("ArrayClass::numpy_view()"); + ArrayClass &a = obj.cast(); + return py::array_t({2}, {4}, a.data, obj); + } + ); + + sm.def("function_taking_uint64", [](uint64_t) { }); + + sm.def("isinstance_untyped", [](py::object yes, py::object no) { + return py::isinstance(yes) && !py::isinstance(no); + }); + + sm.def("isinstance_typed", [](py::object o) { + return py::isinstance>(o) && !py::isinstance>(o); + }); + + sm.def("default_constructors", []() { + return py::dict( + "array"_a=py::array(), + "array_t"_a=py::array_t(), + "array_t"_a=py::array_t() + ); + }); + + sm.def("converting_constructors", [](py::object o) { + return py::dict( + "array"_a=py::array(o), + "array_t"_a=py::array_t(o), + "array_t"_a=py::array_t(o) + ); + }); +}); diff --git a/resources/pybind11/tests/test_numpy_array.py b/resources/pybind11/tests/test_numpy_array.py new file mode 100755 index 0000000..1c218a1 --- /dev/null +++ b/resources/pybind11/tests/test_numpy_array.py @@ -0,0 +1,273 @@ +import pytest +import gc + +with pytest.suppress(ImportError): + import numpy as np + + +@pytest.fixture(scope='function') +def arr(): + return np.array([[1, 2, 3], [4, 5, 6]], '"].dtype == np.int32 + assert defaults["array_t"].dtype == np.float64 + + results = converting_constructors([1, 2, 3]) + for a in results.values(): + np.testing.assert_array_equal(a, [1, 2, 3]) + assert results["array"].dtype == np.int_ + assert results["array_t"].dtype == np.int32 + assert results["array_t"].dtype == np.float64 diff --git a/resources/pybind11/tests/test_numpy_dtypes.cpp b/resources/pybind11/tests/test_numpy_dtypes.cpp new file mode 100755 index 0000000..3894f6a --- /dev/null +++ b/resources/pybind11/tests/test_numpy_dtypes.cpp @@ -0,0 +1,363 @@ +/* + tests/test_numpy_dtypes.cpp -- Structured and compound NumPy dtypes + + Copyright (c) 2016 Ivan Smirnov + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include + +#ifdef __GNUC__ +#define PYBIND11_PACKED(cls) cls __attribute__((__packed__)) +#else +#define PYBIND11_PACKED(cls) __pragma(pack(push, 1)) cls __pragma(pack(pop)) +#endif + +namespace py = pybind11; + +struct SimpleStruct { + bool x; + uint32_t y; + float z; +}; + +std::ostream& operator<<(std::ostream& os, const SimpleStruct& v) { + return os << "s:" << v.x << "," << v.y << "," << v.z; +} + +PYBIND11_PACKED(struct PackedStruct { + bool x; + uint32_t y; + float z; +}); + +std::ostream& operator<<(std::ostream& os, const PackedStruct& v) { + return os << "p:" << v.x << "," << v.y << "," << v.z; +} + +PYBIND11_PACKED(struct NestedStruct { + SimpleStruct a; + PackedStruct b; +}); + +std::ostream& operator<<(std::ostream& os, const NestedStruct& v) { + return os << "n:a=" << v.a << ";b=" << v.b; +} + +struct PartialStruct { + bool x; + uint32_t y; + float z; + uint64_t dummy2; +}; + +struct PartialNestedStruct { + uint64_t dummy1; + PartialStruct a; + uint64_t dummy2; +}; + +struct UnboundStruct { }; + +struct StringStruct { + char a[3]; + std::array b; +}; + +PYBIND11_PACKED(struct StructWithUglyNames { + int8_t __x__; + uint64_t __y__; +}); + +enum class E1 : int64_t { A = -1, B = 1 }; +enum E2 : uint8_t { X = 1, Y = 2 }; + +PYBIND11_PACKED(struct EnumStruct { + E1 e1; + E2 e2; +}); + +std::ostream& operator<<(std::ostream& os, const StringStruct& v) { + os << "a='"; + for (size_t i = 0; i < 3 && v.a[i]; i++) os << v.a[i]; + os << "',b='"; + for (size_t i = 0; i < 3 && v.b[i]; i++) os << v.b[i]; + return os << "'"; +} + +std::ostream& operator<<(std::ostream& os, const EnumStruct& v) { + return os << "e1=" << (v.e1 == E1::A ? "A" : "B") << ",e2=" << (v.e2 == E2::X ? "X" : "Y"); +} + +template +py::array mkarray_via_buffer(size_t n) { + return py::array(py::buffer_info(nullptr, sizeof(T), + py::format_descriptor::format(), + 1, { n }, { sizeof(T) })); +} + +template +py::array_t create_recarray(size_t n) { + auto arr = mkarray_via_buffer(n); + auto req = arr.request(); + auto ptr = static_cast(req.ptr); + for (size_t i = 0; i < n; i++) { + ptr[i].x = i % 2 != 0; ptr[i].y = (uint32_t) i; ptr[i].z = (float) i * 1.5f; + } + return arr; +} + +std::string get_format_unbound() { + return py::format_descriptor::format(); +} + +py::array_t create_nested(size_t n) { + auto arr = mkarray_via_buffer(n); + auto req = arr.request(); + auto ptr = static_cast(req.ptr); + for (size_t i = 0; i < n; i++) { + ptr[i].a.x = i % 2 != 0; ptr[i].a.y = (uint32_t) i; ptr[i].a.z = (float) i * 1.5f; + ptr[i].b.x = (i + 1) % 2 != 0; ptr[i].b.y = (uint32_t) (i + 1); ptr[i].b.z = (float) (i + 1) * 1.5f; + } + return arr; +} + +py::array_t create_partial_nested(size_t n) { + auto arr = mkarray_via_buffer(n); + auto req = arr.request(); + auto ptr = static_cast(req.ptr); + for (size_t i = 0; i < n; i++) { + ptr[i].a.x = i % 2 != 0; ptr[i].a.y = (uint32_t) i; ptr[i].a.z = (float) i * 1.5f; + } + return arr; +} + +py::array_t create_string_array(bool non_empty) { + auto arr = mkarray_via_buffer(non_empty ? 4 : 0); + if (non_empty) { + auto req = arr.request(); + auto ptr = static_cast(req.ptr); + for (size_t i = 0; i < req.size * req.itemsize; i++) + static_cast(req.ptr)[i] = 0; + ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a'; + ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a'; + ptr[3].a[0] = 'a'; ptr[3].b[0] = 'a'; + + ptr[2].a[1] = 'b'; ptr[2].b[1] = 'b'; + ptr[3].a[1] = 'b'; ptr[3].b[1] = 'b'; + + ptr[3].a[2] = 'c'; ptr[3].b[2] = 'c'; + } + return arr; +} + +py::array_t create_enum_array(size_t n) { + auto arr = mkarray_via_buffer(n); + auto ptr = (EnumStruct *) arr.mutable_data(); + for (size_t i = 0; i < n; i++) { + ptr[i].e1 = static_cast(-1 + ((int) i % 2) * 2); + ptr[i].e2 = static_cast(1 + (i % 2)); + } + return arr; +} + +template +py::list print_recarray(py::array_t arr) { + const auto req = arr.request(); + const auto ptr = static_cast(req.ptr); + auto l = py::list(); + for (size_t i = 0; i < req.size; i++) { + std::stringstream ss; + ss << ptr[i]; + l.append(py::str(ss.str())); + } + return l; +} + +py::list print_format_descriptors() { + const auto fmts = { + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format() + }; + auto l = py::list(); + for (const auto &fmt : fmts) { + l.append(py::cast(fmt)); + } + return l; +} + +py::list print_dtypes() { + const auto dtypes = { + py::str(py::dtype::of()), + py::str(py::dtype::of()), + py::str(py::dtype::of()), + py::str(py::dtype::of()), + py::str(py::dtype::of()), + py::str(py::dtype::of()), + py::str(py::dtype::of()), + py::str(py::dtype::of()) + }; + auto l = py::list(); + for (const auto &s : dtypes) { + l.append(s); + } + return l; +} + +py::array_t test_array_ctors(int i) { + using arr_t = py::array_t; + + std::vector data { 1, 2, 3, 4, 5, 6 }; + std::vector shape { 3, 2 }; + std::vector strides { 8, 4 }; + + auto ptr = data.data(); + auto vptr = (void *) ptr; + auto dtype = py::dtype("int32"); + + py::buffer_info buf_ndim1(vptr, 4, "i", 6); + py::buffer_info buf_ndim1_null(nullptr, 4, "i", 6); + py::buffer_info buf_ndim2(vptr, 4, "i", 2, shape, strides); + py::buffer_info buf_ndim2_null(nullptr, 4, "i", 2, shape, strides); + + auto fill = [](py::array arr) { + auto req = arr.request(); + for (int i = 0; i < 6; i++) ((int32_t *) req.ptr)[i] = i + 1; + return arr; + }; + + switch (i) { + // shape: (3, 2) + case 10: return arr_t(shape, strides, ptr); + case 11: return py::array(shape, strides, ptr); + case 12: return py::array(dtype, shape, strides, vptr); + case 13: return arr_t(shape, ptr); + case 14: return py::array(shape, ptr); + case 15: return py::array(dtype, shape, vptr); + case 16: return arr_t(buf_ndim2); + case 17: return py::array(buf_ndim2); + // shape: (3, 2) - post-fill + case 20: return fill(arr_t(shape, strides)); + case 21: return py::array(shape, strides, ptr); // can't have nullptr due to templated ctor + case 22: return fill(py::array(dtype, shape, strides)); + case 23: return fill(arr_t(shape)); + case 24: return py::array(shape, ptr); // can't have nullptr due to templated ctor + case 25: return fill(py::array(dtype, shape)); + case 26: return fill(arr_t(buf_ndim2_null)); + case 27: return fill(py::array(buf_ndim2_null)); + // shape: (6, ) + case 30: return arr_t(6, ptr); + case 31: return py::array(6, ptr); + case 32: return py::array(dtype, 6, vptr); + case 33: return arr_t(buf_ndim1); + case 34: return py::array(buf_ndim1); + // shape: (6, ) + case 40: return fill(arr_t(6)); + case 41: return py::array(6, ptr); // can't have nullptr due to templated ctor + case 42: return fill(py::array(dtype, 6)); + case 43: return fill(arr_t(buf_ndim1_null)); + case 44: return fill(py::array(buf_ndim1_null)); + } + return arr_t(); +} + +py::list test_dtype_ctors() { + py::list list; + list.append(py::dtype("int32")); + list.append(py::dtype(std::string("float64"))); + list.append(py::dtype::from_args(py::str("bool"))); + py::list names, offsets, formats; + py::dict dict; + names.append(py::str("a")); names.append(py::str("b")); dict["names"] = names; + offsets.append(py::int_(1)); offsets.append(py::int_(10)); dict["offsets"] = offsets; + formats.append(py::dtype("int32")); formats.append(py::dtype("float64")); dict["formats"] = formats; + dict["itemsize"] = py::int_(20); + list.append(py::dtype::from_args(dict)); + list.append(py::dtype(names, formats, offsets, 20)); + list.append(py::dtype(py::buffer_info((void *) 0, sizeof(unsigned int), "I", 1))); + list.append(py::dtype(py::buffer_info((void *) 0, 0, "T{i:a:f:b:}", 1))); + return list; +} + +struct TrailingPaddingStruct { + int32_t a; + char b; +}; + +py::dtype trailing_padding_dtype() { + return py::dtype::of(); +} + +py::dtype buffer_to_dtype(py::buffer& buf) { + return py::dtype(buf.request()); +} + +py::list test_dtype_methods() { + py::list list; + auto dt1 = py::dtype::of(); + auto dt2 = py::dtype::of(); + list.append(dt1); list.append(dt2); + list.append(py::bool_(dt1.has_fields())); list.append(py::bool_(dt2.has_fields())); + list.append(py::int_(dt1.itemsize())); list.append(py::int_(dt2.itemsize())); + return list; +} + +test_initializer numpy_dtypes([](py::module &m) { + try { + py::module::import("numpy"); + } catch (...) { + return; + } + + // typeinfo may be registered before the dtype descriptor for scalar casts to work... + py::class_(m, "SimpleStruct"); + + PYBIND11_NUMPY_DTYPE(SimpleStruct, x, y, z); + PYBIND11_NUMPY_DTYPE(PackedStruct, x, y, z); + PYBIND11_NUMPY_DTYPE(NestedStruct, a, b); + PYBIND11_NUMPY_DTYPE(PartialStruct, x, y, z); + PYBIND11_NUMPY_DTYPE(PartialNestedStruct, a); + PYBIND11_NUMPY_DTYPE(StringStruct, a, b); + PYBIND11_NUMPY_DTYPE(EnumStruct, e1, e2); + PYBIND11_NUMPY_DTYPE(TrailingPaddingStruct, a, b); + + // ... or after + py::class_(m, "PackedStruct"); + + PYBIND11_NUMPY_DTYPE_EX(StructWithUglyNames, __x__, "x", __y__, "y"); + + m.def("create_rec_simple", &create_recarray); + m.def("create_rec_packed", &create_recarray); + m.def("create_rec_nested", &create_nested); + m.def("create_rec_partial", &create_recarray); + m.def("create_rec_partial_nested", &create_partial_nested); + m.def("print_format_descriptors", &print_format_descriptors); + m.def("print_rec_simple", &print_recarray); + m.def("print_rec_packed", &print_recarray); + m.def("print_rec_nested", &print_recarray); + m.def("print_dtypes", &print_dtypes); + m.def("get_format_unbound", &get_format_unbound); + m.def("create_string_array", &create_string_array); + m.def("print_string_array", &print_recarray); + m.def("create_enum_array", &create_enum_array); + m.def("print_enum_array", &print_recarray); + m.def("test_array_ctors", &test_array_ctors); + m.def("test_dtype_ctors", &test_dtype_ctors); + m.def("test_dtype_methods", &test_dtype_methods); + m.def("trailing_padding_dtype", &trailing_padding_dtype); + m.def("buffer_to_dtype", &buffer_to_dtype); + m.def("f_simple", [](SimpleStruct s) { return s.y * 10; }); + m.def("f_packed", [](PackedStruct s) { return s.y * 10; }); + m.def("f_nested", [](NestedStruct s) { return s.a.y * 10; }); + m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, x, y, z); }); +}); + +#undef PYBIND11_PACKED diff --git a/resources/pybind11/tests/test_numpy_dtypes.py b/resources/pybind11/tests/test_numpy_dtypes.py new file mode 100755 index 0000000..48b2ff6 --- /dev/null +++ b/resources/pybind11/tests/test_numpy_dtypes.py @@ -0,0 +1,219 @@ +import re +import pytest + +with pytest.suppress(ImportError): + import numpy as np + + +@pytest.fixture(scope='module') +def simple_dtype(): + return np.dtype({'names': ['x', 'y', 'z'], + 'formats': ['?', 'u4', 'f4'], + 'offsets': [0, 4, 8]}) + + +@pytest.fixture(scope='module') +def packed_dtype(): + return np.dtype([('x', '?'), ('y', 'u4'), ('z', 'f4')]) + + +def assert_equal(actual, expected_data, expected_dtype): + np.testing.assert_equal(actual, np.array(expected_data, dtype=expected_dtype)) + + +@pytest.requires_numpy +def test_format_descriptors(): + from pybind11_tests import get_format_unbound, print_format_descriptors + + with pytest.raises(RuntimeError) as excinfo: + get_format_unbound() + assert re.match('^NumPy type info missing for .*UnboundStruct.*$', str(excinfo.value)) + + assert print_format_descriptors() == [ + "T{?:x:3xI:y:f:z:}", + "T{?:x:=I:y:=f:z:}", + "T{T{?:x:3xI:y:f:z:}:a:T{?:x:=I:y:=f:z:}:b:}", + "T{?:x:3xI:y:f:z:12x}", + "T{8xT{?:x:3xI:y:f:z:12x}:a:8x}", + "T{3s:a:3s:b:}", + 'T{q:e1:B:e2:}' + ] + + +@pytest.requires_numpy +def test_dtype(simple_dtype): + from pybind11_tests import print_dtypes, test_dtype_ctors, test_dtype_methods, trailing_padding_dtype, buffer_to_dtype + + assert print_dtypes() == [ + "{'names':['x','y','z'], 'formats':['?',' simple_dtype.itemsize + assert_equal(arr, elements, simple_dtype) + assert_equal(arr, elements, packed_dtype) + + arr = create_rec_partial_nested(3) + assert str(arr.dtype) == "{'names':['a'], 'formats':[{'names':['x','y','z'], 'formats':['?',' partial_dtype.itemsize + np.testing.assert_equal(arr['a'], create_rec_partial(3)) + + +@pytest.requires_numpy +def test_array_constructors(): + from pybind11_tests import test_array_ctors + + data = np.arange(1, 7, dtype='int32') + for i in range(8): + np.testing.assert_array_equal(test_array_ctors(10 + i), data.reshape((3, 2))) + np.testing.assert_array_equal(test_array_ctors(20 + i), data.reshape((3, 2))) + for i in range(5): + np.testing.assert_array_equal(test_array_ctors(30 + i), data) + np.testing.assert_array_equal(test_array_ctors(40 + i), data) + + +@pytest.requires_numpy +def test_string_array(): + from pybind11_tests import create_string_array, print_string_array + + arr = create_string_array(True) + assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]" + assert print_string_array(arr) == [ + "a='',b=''", + "a='a',b='a'", + "a='ab',b='ab'", + "a='abc',b='abc'" + ] + dtype = arr.dtype + assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc'] + assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc'] + arr = create_string_array(False) + assert dtype == arr.dtype + + +@pytest.requires_numpy +def test_enum_array(): + from pybind11_tests import create_enum_array, print_enum_array + + arr = create_enum_array(3) + dtype = arr.dtype + assert dtype == np.dtype([('e1', ' numpy.ndarray[NestedStruct]" + + +@pytest.requires_numpy +def test_scalar_conversion(): + from pybind11_tests import (create_rec_simple, f_simple, + create_rec_packed, f_packed, + create_rec_nested, f_nested, + create_enum_array) + + n = 3 + arrays = [create_rec_simple(n), create_rec_packed(n), + create_rec_nested(n), create_enum_array(n)] + funcs = [f_simple, f_packed, f_nested] + + for i, func in enumerate(funcs): + for j, arr in enumerate(arrays): + if i == j and i < 2: + assert [func(arr[k]) for k in range(n)] == [k * 10 for k in range(n)] + else: + with pytest.raises(TypeError) as excinfo: + func(arr[0]) + assert 'incompatible function arguments' in str(excinfo.value) + + +@pytest.requires_numpy +def test_register_dtype(): + from pybind11_tests import register_dtype + + with pytest.raises(RuntimeError) as excinfo: + register_dtype() + assert 'dtype is already registered' in str(excinfo.value) diff --git a/resources/pybind11/tests/test_numpy_vectorize.cpp b/resources/pybind11/tests/test_numpy_vectorize.cpp new file mode 100755 index 0000000..6d94db2 --- /dev/null +++ b/resources/pybind11/tests/test_numpy_vectorize.cpp @@ -0,0 +1,41 @@ +/* + tests/test_numpy_vectorize.cpp -- auto-vectorize functions over NumPy array + arguments + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include + +double my_func(int x, float y, double z) { + py::print("my_func(x:int={}, y:float={:.0f}, z:float={:.0f})"_s.format(x, y, z)); + return (float) x*y*z; +} + +std::complex my_func3(std::complex c) { + return c * std::complex(2.f); +} + +test_initializer numpy_vectorize([](py::module &m) { + // Vectorize all arguments of a function (though non-vector arguments are also allowed) + m.def("vectorized_func", py::vectorize(my_func)); + + // Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the vectorization) + m.def("vectorized_func2", + [](py::array_t x, py::array_t y, float z) { + return py::vectorize([z](int x, float y) { return my_func(x, y, z); })(x, y); + } + ); + + // Vectorize a complex-valued function + m.def("vectorized_func3", py::vectorize(my_func3)); + + /// Numpy function which only accepts specific data types + m.def("selective_func", [](py::array_t) { return "Int branch taken."; }); + m.def("selective_func", [](py::array_t) { return "Float branch taken."; }); + m.def("selective_func", [](py::array_t, py::array::c_style>) { return "Complex float branch taken."; }); +}); diff --git a/resources/pybind11/tests/test_numpy_vectorize.py b/resources/pybind11/tests/test_numpy_vectorize.py new file mode 100755 index 0000000..73da819 --- /dev/null +++ b/resources/pybind11/tests/test_numpy_vectorize.py @@ -0,0 +1,74 @@ +import pytest + +with pytest.suppress(ImportError): + import numpy as np + + +@pytest.requires_numpy +def test_vectorize(capture): + from pybind11_tests import vectorized_func, vectorized_func2, vectorized_func3 + + assert np.isclose(vectorized_func3(np.array(3 + 7j)), [6 + 14j]) + + for f in [vectorized_func, vectorized_func2]: + with capture: + assert np.isclose(f(1, 2, 3), 6) + assert capture == "my_func(x:int=1, y:float=2, z:float=3)" + with capture: + assert np.isclose(f(np.array(1), np.array(2), 3), 6) + assert capture == "my_func(x:int=1, y:float=2, z:float=3)" + with capture: + assert np.allclose(f(np.array([1, 3]), np.array([2, 4]), 3), [6, 36]) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=3) + my_func(x:int=3, y:float=4, z:float=3) + """ + with capture: + a, b, c = np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3 + assert np.allclose(f(a, b, c), a * b * c) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=3) + my_func(x:int=3, y:float=4, z:float=3) + my_func(x:int=5, y:float=6, z:float=3) + my_func(x:int=7, y:float=8, z:float=3) + my_func(x:int=9, y:float=10, z:float=3) + my_func(x:int=11, y:float=12, z:float=3) + """ + with capture: + a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2 + assert np.allclose(f(a, b, c), a * b * c) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=2) + my_func(x:int=2, y:float=3, z:float=2) + my_func(x:int=3, y:float=4, z:float=2) + my_func(x:int=4, y:float=2, z:float=2) + my_func(x:int=5, y:float=3, z:float=2) + my_func(x:int=6, y:float=4, z:float=2) + """ + with capture: + a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2 + assert np.allclose(f(a, b, c), a * b * c) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=2) + my_func(x:int=2, y:float=2, z:float=2) + my_func(x:int=3, y:float=2, z:float=2) + my_func(x:int=4, y:float=3, z:float=2) + my_func(x:int=5, y:float=3, z:float=2) + my_func(x:int=6, y:float=3, z:float=2) + """ + + +@pytest.requires_numpy +def test_type_selection(): + from pybind11_tests import selective_func + + assert selective_func(np.array([1], dtype=np.int32)) == "Int branch taken." + assert selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken." + assert selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken." + + +@pytest.requires_numpy +def test_docs(doc): + from pybind11_tests import vectorized_func + + assert doc(vectorized_func) == "vectorized_func(arg0: numpy.ndarray[int], arg1: numpy.ndarray[float], arg2: numpy.ndarray[float]) -> object" diff --git a/resources/pybind11/tests/test_opaque_types.cpp b/resources/pybind11/tests/test_opaque_types.cpp new file mode 100755 index 0000000..54f4dc7 --- /dev/null +++ b/resources/pybind11/tests/test_opaque_types.cpp @@ -0,0 +1,62 @@ +/* + tests/test_opaque_types.cpp -- opaque types, passing void pointers + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include +#include + +typedef std::vector StringList; + +class ClassWithSTLVecProperty { +public: + StringList stringList; +}; + +/* IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures */ +PYBIND11_MAKE_OPAQUE(StringList); + +test_initializer opaque_types([](py::module &m) { + py::class_(m, "StringList") + .def(py::init<>()) + .def("pop_back", &StringList::pop_back) + /* There are multiple versions of push_back(), etc. Select the right ones. */ + .def("push_back", (void (StringList::*)(const std::string &)) &StringList::push_back) + .def("back", (std::string &(StringList::*)()) &StringList::back) + .def("__len__", [](const StringList &v) { return v.size(); }) + .def("__iter__", [](StringList &v) { + return py::make_iterator(v.begin(), v.end()); + }, py::keep_alive<0, 1>()); + + py::class_(m, "ClassWithSTLVecProperty") + .def(py::init<>()) + .def_readwrite("stringList", &ClassWithSTLVecProperty::stringList); + + m.def("print_opaque_list", [](const StringList &l) { + std::string ret = "Opaque list: ["; + bool first = true; + for (auto entry : l) { + if (!first) + ret += ", "; + ret += entry; + first = false; + } + return ret + "]"; + }); + + m.def("return_void_ptr", []() { return (void *) 0x1234; }); + m.def("get_void_ptr_value", [](void *ptr) { return reinterpret_cast(ptr); }); + m.def("return_null_str", []() { return (char *) nullptr; }); + m.def("get_null_str_value", [](char *ptr) { return reinterpret_cast(ptr); }); + + m.def("return_unique_ptr", []() -> std::unique_ptr { + StringList *result = new StringList(); + result->push_back("some value"); + return std::unique_ptr(result); + }); +}); diff --git a/resources/pybind11/tests/test_opaque_types.py b/resources/pybind11/tests/test_opaque_types.py new file mode 100755 index 0000000..8a6a4c3 --- /dev/null +++ b/resources/pybind11/tests/test_opaque_types.py @@ -0,0 +1,49 @@ +import pytest + + +def test_string_list(): + from pybind11_tests import StringList, ClassWithSTLVecProperty, print_opaque_list + + l = StringList() + l.push_back("Element 1") + l.push_back("Element 2") + assert print_opaque_list(l) == "Opaque list: [Element 1, Element 2]" + assert l.back() == "Element 2" + + for i, k in enumerate(l, start=1): + assert k == "Element {}".format(i) + l.pop_back() + assert print_opaque_list(l) == "Opaque list: [Element 1]" + + cvp = ClassWithSTLVecProperty() + assert print_opaque_list(cvp.stringList) == "Opaque list: []" + + cvp.stringList = l + cvp.stringList.push_back("Element 3") + assert print_opaque_list(cvp.stringList) == "Opaque list: [Element 1, Element 3]" + + +def test_pointers(msg): + from pybind11_tests import (return_void_ptr, get_void_ptr_value, ExampleMandA, + print_opaque_list, return_null_str, get_null_str_value, + return_unique_ptr, ConstructorStats) + + assert get_void_ptr_value(return_void_ptr()) == 0x1234 + assert get_void_ptr_value(ExampleMandA()) # Should also work for other C++ types + assert ConstructorStats.get(ExampleMandA).alive() == 0 + + with pytest.raises(TypeError) as excinfo: + get_void_ptr_value([1, 2, 3]) # This should not work + assert msg(excinfo.value) == """ + get_void_ptr_value(): incompatible function arguments. The following argument types are supported: + 1. (arg0: capsule) -> int + + Invoked with: [1, 2, 3] + """ + + assert return_null_str() is None + assert get_null_str_value(return_null_str()) is not None + + ptr = return_unique_ptr() + assert "StringList" in repr(ptr) + assert print_opaque_list(ptr) == "Opaque list: [some value]" diff --git a/resources/pybind11/tests/test_operator_overloading.cpp b/resources/pybind11/tests/test_operator_overloading.cpp new file mode 100755 index 0000000..93aea80 --- /dev/null +++ b/resources/pybind11/tests/test_operator_overloading.cpp @@ -0,0 +1,76 @@ +/* + tests/test_operator_overloading.cpp -- operator overloading + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include + +class Vector2 { +public: + Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); } + Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); } + Vector2(Vector2 &&v) : x(v.x), y(v.y) { print_move_created(this); v.x = v.y = 0; } + ~Vector2() { print_destroyed(this); } + + std::string toString() const { + return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; + } + + void operator=(const Vector2 &v) { + print_copy_assigned(this); + x = v.x; + y = v.y; + } + + void operator=(Vector2 &&v) { + print_move_assigned(this); + x = v.x; y = v.y; v.x = v.y = 0; + } + + Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); } + Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); } + Vector2 operator-(float value) const { return Vector2(x - value, y - value); } + Vector2 operator+(float value) const { return Vector2(x + value, y + value); } + Vector2 operator*(float value) const { return Vector2(x * value, y * value); } + Vector2 operator/(float value) const { return Vector2(x / value, y / value); } + Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; } + Vector2& operator-=(const Vector2 &v) { x -= v.x; y -= v.y; return *this; } + Vector2& operator*=(float v) { x *= v; y *= v; return *this; } + Vector2& operator/=(float v) { x /= v; y /= v; return *this; } + + friend Vector2 operator+(float f, const Vector2 &v) { return Vector2(f + v.x, f + v.y); } + friend Vector2 operator-(float f, const Vector2 &v) { return Vector2(f - v.x, f - v.y); } + friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); } + friend Vector2 operator/(float f, const Vector2 &v) { return Vector2(f / v.x, f / v.y); } +private: + float x, y; +}; + +test_initializer operator_overloading([](py::module &m) { + py::class_(m, "Vector2") + .def(py::init()) + .def(py::self + py::self) + .def(py::self + float()) + .def(py::self - py::self) + .def(py::self - float()) + .def(py::self * float()) + .def(py::self / float()) + .def(py::self += py::self) + .def(py::self -= py::self) + .def(py::self *= float()) + .def(py::self /= float()) + .def(float() + py::self) + .def(float() - py::self) + .def(float() * py::self) + .def(float() / py::self) + .def("__str__", &Vector2::toString) + ; + + m.attr("Vector") = m.attr("Vector2"); +}); diff --git a/resources/pybind11/tests/test_operator_overloading.py b/resources/pybind11/tests/test_operator_overloading.py new file mode 100755 index 0000000..e0d4239 --- /dev/null +++ b/resources/pybind11/tests/test_operator_overloading.py @@ -0,0 +1,41 @@ + +def test_operator_overloading(): + from pybind11_tests import Vector2, Vector, ConstructorStats + + v1 = Vector2(1, 2) + v2 = Vector(3, -1) + assert str(v1) == "[1.000000, 2.000000]" + assert str(v2) == "[3.000000, -1.000000]" + + assert str(v1 + v2) == "[4.000000, 1.000000]" + assert str(v1 - v2) == "[-2.000000, 3.000000]" + assert str(v1 - 8) == "[-7.000000, -6.000000]" + assert str(v1 + 8) == "[9.000000, 10.000000]" + assert str(v1 * 8) == "[8.000000, 16.000000]" + assert str(v1 / 8) == "[0.125000, 0.250000]" + assert str(8 - v1) == "[7.000000, 6.000000]" + assert str(8 + v1) == "[9.000000, 10.000000]" + assert str(8 * v1) == "[8.000000, 16.000000]" + assert str(8 / v1) == "[8.000000, 4.000000]" + + v1 += v2 + v1 *= 2 + assert str(v1) == "[8.000000, 2.000000]" + + cstats = ConstructorStats.get(Vector2) + assert cstats.alive() == 2 + del v1 + assert cstats.alive() == 1 + del v2 + assert cstats.alive() == 0 + assert cstats.values() == ['[1.000000, 2.000000]', '[3.000000, -1.000000]', + '[4.000000, 1.000000]', '[-2.000000, 3.000000]', + '[-7.000000, -6.000000]', '[9.000000, 10.000000]', + '[8.000000, 16.000000]', '[0.125000, 0.250000]', + '[7.000000, 6.000000]', '[9.000000, 10.000000]', + '[8.000000, 16.000000]', '[8.000000, 4.000000]'] + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + assert cstats.move_constructions >= 10 + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 diff --git a/resources/pybind11/tests/test_pickling.cpp b/resources/pybind11/tests/test_pickling.cpp new file mode 100755 index 0000000..3941dc5 --- /dev/null +++ b/resources/pybind11/tests/test_pickling.cpp @@ -0,0 +1,81 @@ +/* + tests/test_pickling.cpp -- pickle support + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +class Pickleable { +public: + Pickleable(const std::string &value) : m_value(value) { } + const std::string &value() const { return m_value; } + + void setExtra1(int extra1) { m_extra1 = extra1; } + void setExtra2(int extra2) { m_extra2 = extra2; } + int extra1() const { return m_extra1; } + int extra2() const { return m_extra2; } +private: + std::string m_value; + int m_extra1 = 0; + int m_extra2 = 0; +}; + +class PickleableWithDict { +public: + PickleableWithDict(const std::string &value) : value(value) { } + + std::string value; + int extra; +}; + +test_initializer pickling([](py::module &m) { + py::class_(m, "Pickleable") + .def(py::init()) + .def("value", &Pickleable::value) + .def("extra1", &Pickleable::extra1) + .def("extra2", &Pickleable::extra2) + .def("setExtra1", &Pickleable::setExtra1) + .def("setExtra2", &Pickleable::setExtra2) + // For details on the methods below, refer to + // http://docs.python.org/3/library/pickle.html#pickling-class-instances + .def("__getstate__", [](const Pickleable &p) { + /* Return a tuple that fully encodes the state of the object */ + return py::make_tuple(p.value(), p.extra1(), p.extra2()); + }) + .def("__setstate__", [](Pickleable &p, py::tuple t) { + if (t.size() != 3) + throw std::runtime_error("Invalid state!"); + /* Invoke the constructor (need to use in-place version) */ + new (&p) Pickleable(t[0].cast()); + + /* Assign any additional state */ + p.setExtra1(t[1].cast()); + p.setExtra2(t[2].cast()); + }); + + py::class_(m, "PickleableWithDict", py::dynamic_attr()) + .def(py::init()) + .def_readwrite("value", &PickleableWithDict::value) + .def_readwrite("extra", &PickleableWithDict::extra) + .def("__getstate__", [](py::object self) { + /* Also include __dict__ in state */ + return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__")); + }) + .def("__setstate__", [](py::object self, py::tuple t) { + if (t.size() != 3) + throw std::runtime_error("Invalid state!"); + /* Cast and construct */ + auto& p = self.cast(); + new (&p) Pickleable(t[0].cast()); + + /* Assign C++ state */ + p.extra = t[1].cast(); + + /* Assign Python state */ + self.attr("__dict__") = t[2]; + }); +}); diff --git a/resources/pybind11/tests/test_pickling.py b/resources/pybind11/tests/test_pickling.py new file mode 100755 index 0000000..5e62e1f --- /dev/null +++ b/resources/pybind11/tests/test_pickling.py @@ -0,0 +1,32 @@ +try: + import cPickle as pickle # Use cPickle on Python 2.7 +except ImportError: + import pickle + + +def test_roundtrip(): + from pybind11_tests import Pickleable + + p = Pickleable("test_value") + p.setExtra1(15) + p.setExtra2(48) + + data = pickle.dumps(p, 2) # Must use pickle protocol >= 2 + p2 = pickle.loads(data) + assert p2.value() == p.value() + assert p2.extra1() == p.extra1() + assert p2.extra2() == p.extra2() + + +def test_roundtrip_with_dict(): + from pybind11_tests import PickleableWithDict + + p = PickleableWithDict("test_value") + p.extra = 15 + p.dynamic = "Attribute" + + data = pickle.dumps(p, pickle.HIGHEST_PROTOCOL) + p2 = pickle.loads(data) + assert p2.value == p.value + assert p2.extra == p.extra + assert p2.dynamic == p.dynamic diff --git a/resources/pybind11/tests/test_python_types.cpp b/resources/pybind11/tests/test_python_types.cpp new file mode 100755 index 0000000..30fa3c7 --- /dev/null +++ b/resources/pybind11/tests/test_python_types.cpp @@ -0,0 +1,380 @@ +/* + tests/test_python_types.cpp -- singleton design pattern, static functions and + variables, passing and interacting with Python types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include + +#ifdef _WIN32 +# include +# include +#endif + +class ExamplePythonTypes { +public: + static ExamplePythonTypes *new_instance() { + auto *ptr = new ExamplePythonTypes(); + print_created(ptr, "via new_instance"); + return ptr; + } + ~ExamplePythonTypes() { print_destroyed(this); } + + /* Create and return a Python dictionary */ + py::dict get_dict() { + py::dict dict; + dict[py::str("key")] = py::str("value"); + return dict; + } + + /* Create and return a Python set */ + py::set get_set() { + py::set set; + set.add(py::str("key1")); + set.add(py::str("key2")); + return set; + } + + /* Create and return a C++ dictionary */ + std::map get_dict_2() { + std::map result; + result["key"] = "value"; + return result; + } + + /* Create and return a C++ set */ + std::set get_set_2() { + std::set result; + result.insert("key1"); + result.insert("key2"); + return result; + } + + /* Create, manipulate, and return a Python list */ + py::list get_list() { + py::list list; + list.append(py::str("value")); + py::print("Entry at position 0:", list[0]); + list[0] = py::str("overwritten"); + return list; + } + + /* C++ STL data types are automatically casted */ + std::vector get_list_2() { + std::vector list; + list.push_back(L"value"); + return list; + } + + /* C++ STL data types are automatically casted */ + std::array get_array() { + return std::array {{ "array entry 1" , "array entry 2"}}; + } + + /* Easily iterate over a dictionary using a C++11 range-based for loop */ + void print_dict(py::dict dict) { + for (auto item : dict) + py::print("key: {}, value={}"_s.format(item.first, item.second)); + } + + /* Easily iterate over a set using a C++11 range-based for loop */ + void print_set(py::set set) { + for (auto item : set) + py::print("key:", item); + } + + /* Easily iterate over a list using a C++11 range-based for loop */ + void print_list(py::list list) { + int index = 0; + for (auto item : list) + py::print("list item {}: {}"_s.format(index++, item)); + } + + /* STL data types (such as maps) are automatically casted from Python */ + void print_dict_2(const std::map &dict) { + for (auto item : dict) + py::print("key: {}, value={}"_s.format(item.first, item.second)); + } + + /* STL data types (such as sets) are automatically casted from Python */ + void print_set_2(const std::set &set) { + for (auto item : set) + py::print("key:", item); + } + + /* STL data types (such as vectors) are automatically casted from Python */ + void print_list_2(std::vector &list) { + int index = 0; + for (auto item : list) + py::print("list item {}: {}"_s.format(index++, item)); + } + + /* pybind automatically translates between C++11 and Python tuples */ + std::pair pair_passthrough(std::pair input) { + return std::make_pair(input.second, input.first); + } + + /* pybind automatically translates between C++11 and Python tuples */ + std::tuple tuple_passthrough(std::tuple input) { + return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input)); + } + + /* STL data types (such as arrays) are automatically casted from Python */ + void print_array(std::array &array) { + int index = 0; + for (auto item : array) + py::print("array item {}: {}"_s.format(index++, item)); + } + + void throw_exception() { + throw std::runtime_error("This exception was intentionally thrown."); + } + + py::bytes get_bytes_from_string() { + return (py::bytes) std::string("foo"); + } + + py::bytes get_bytes_from_str() { + return (py::bytes) py::str("bar", 3); + } + + py::str get_str_from_string() { + return (py::str) std::string("baz"); + } + + py::str get_str_from_bytes() { + return (py::str) py::bytes("boo", 3); + } + + void test_print(const py::object& obj) { + py::print(py::str(obj)); + py::print(py::repr(obj)); + } + + static int value; + static const int value2; +}; + +int ExamplePythonTypes::value = 0; +const int ExamplePythonTypes::value2 = 5; + +struct MoveOutContainer { + struct Value { int value; }; + + std::list move_list() const { return {{0}, {1}, {2}}; } +}; + + +test_initializer python_types([](py::module &m) { + /* No constructor is explicitly defined below. An exception is raised when + trying to construct it directly from Python */ + py::class_(m, "ExamplePythonTypes", "Example 2 documentation") + .def("get_dict", &ExamplePythonTypes::get_dict, "Return a Python dictionary") + .def("get_dict_2", &ExamplePythonTypes::get_dict_2, "Return a C++ dictionary") + .def("get_list", &ExamplePythonTypes::get_list, "Return a Python list") + .def("get_list_2", &ExamplePythonTypes::get_list_2, "Return a C++ list") + .def("get_set", &ExamplePythonTypes::get_set, "Return a Python set") + .def("get_set2", &ExamplePythonTypes::get_set_2, "Return a C++ set") + .def("get_array", &ExamplePythonTypes::get_array, "Return a C++ array") + .def("print_dict", &ExamplePythonTypes::print_dict, "Print entries of a Python dictionary") + .def("print_dict_2", &ExamplePythonTypes::print_dict_2, "Print entries of a C++ dictionary") + .def("print_set", &ExamplePythonTypes::print_set, "Print entries of a Python set") + .def("print_set_2", &ExamplePythonTypes::print_set_2, "Print entries of a C++ set") + .def("print_list", &ExamplePythonTypes::print_list, "Print entries of a Python list") + .def("print_list_2", &ExamplePythonTypes::print_list_2, "Print entries of a C++ list") + .def("print_array", &ExamplePythonTypes::print_array, "Print entries of a C++ array") + .def("pair_passthrough", &ExamplePythonTypes::pair_passthrough, "Return a pair in reversed order") + .def("tuple_passthrough", &ExamplePythonTypes::tuple_passthrough, "Return a triple in reversed order") + .def("throw_exception", &ExamplePythonTypes::throw_exception, "Throw an exception") + .def("get_bytes_from_string", &ExamplePythonTypes::get_bytes_from_string, "py::bytes from std::string") + .def("get_bytes_from_str", &ExamplePythonTypes::get_bytes_from_str, "py::bytes from py::str") + .def("get_str_from_string", &ExamplePythonTypes::get_str_from_string, "py::str from std::string") + .def("get_str_from_bytes", &ExamplePythonTypes::get_str_from_bytes, "py::str from py::bytes") + .def("test_print", &ExamplePythonTypes::test_print, "test the print function") + .def_static("new_instance", &ExamplePythonTypes::new_instance, "Return an instance") + .def_readwrite_static("value", &ExamplePythonTypes::value, "Static value member") + .def_readonly_static("value2", &ExamplePythonTypes::value2, "Static value member (readonly)") + ; + + m.def("test_print_function", []() { + py::print("Hello, World!"); + py::print(1, 2.0, "three", true, std::string("-- multiple args")); + auto args = py::make_tuple("and", "a", "custom", "separator"); + py::print("*args", *args, "sep"_a="-"); + py::print("no new line here", "end"_a=" -- "); + py::print("next print"); + + auto py_stderr = py::module::import("sys").attr("stderr"); + py::print("this goes to stderr", "file"_a=py_stderr); + + py::print("flush", "flush"_a=true); + + py::print("{a} + {b} = {c}"_s.format("a"_a="py::print", "b"_a="str.format", "c"_a="this")); + }); + + m.def("test_str_format", []() { + auto s1 = "{} + {} = {}"_s.format(1, 2, 3); + auto s2 = "{a} + {b} = {c}"_s.format("a"_a=1, "b"_a=2, "c"_a=3); + return py::make_tuple(s1, s2); + }); + + m.def("test_dict_keyword_constructor", []() { + auto d1 = py::dict("x"_a=1, "y"_a=2); + auto d2 = py::dict("z"_a=3, **d1); + return d2; + }); + + m.def("test_accessor_api", [](py::object o) { + auto d = py::dict(); + + d["basic_attr"] = o.attr("basic_attr"); + + auto l = py::list(); + for (const auto &item : o.attr("begin_end")) { + l.append(item); + } + d["begin_end"] = l; + + d["operator[object]"] = o.attr("d")["operator[object]"_s]; + d["operator[char *]"] = o.attr("d")["operator[char *]"]; + + d["attr(object)"] = o.attr("sub").attr("attr_obj"); + d["attr(char *)"] = o.attr("sub").attr("attr_char"); + try { + o.attr("sub").attr("missing").ptr(); + } catch (const py::error_already_set &) { + d["missing_attr_ptr"] = "raised"_s; + } + try { + o.attr("missing").attr("doesn't matter"); + } catch (const py::error_already_set &) { + d["missing_attr_chain"] = "raised"_s; + } + + d["is_none"] = py::cast(o.attr("basic_attr").is_none()); + + d["operator()"] = o.attr("func")(1); + d["operator*"] = o.attr("func")(*o.attr("begin_end")); + + return d; + }); + + m.def("test_tuple_accessor", [](py::tuple existing_t) { + try { + existing_t[0] = py::cast(1); + } catch (const py::error_already_set &) { + // --> Python system error + // Only new tuples (refcount == 1) are mutable + auto new_t = py::tuple(3); + for (size_t i = 0; i < new_t.size(); ++i) { + new_t[i] = py::cast(i); + } + return new_t; + } + return py::tuple(); + }); + + m.def("test_accessor_assignment", []() { + auto l = py::list(1); + l[0] = py::cast(0); + + auto d = py::dict(); + d["get"] = l[0]; + auto var = l[0]; + d["deferred_get"] = var; + l[0] = py::cast(1); + d["set"] = l[0]; + var = py::cast(99); // this assignment should not overwrite l[0] + d["deferred_set"] = l[0]; + d["var"] = var; + + return d; + }); + + bool has_optional = false, has_exp_optional = false; +#ifdef PYBIND11_HAS_OPTIONAL + has_optional = true; + using opt_int = std::optional; + m.def("double_or_zero", [](const opt_int& x) -> int { + return x.value_or(0) * 2; + }); + m.def("half_or_none", [](int x) -> opt_int { + return x ? opt_int(x / 2) : opt_int(); + }); + m.def("test_nullopt", [](opt_int x) { + return x.value_or(42); + }, py::arg_v("x", std::nullopt, "None")); +#endif + +#ifdef PYBIND11_HAS_EXP_OPTIONAL + has_exp_optional = true; + using opt_int = std::experimental::optional; + m.def("double_or_zero_exp", [](const opt_int& x) -> int { + return x.value_or(0) * 2; + }); + m.def("half_or_none_exp", [](int x) -> opt_int { + return x ? opt_int(x / 2) : opt_int(); + }); + m.def("test_nullopt_exp", [](opt_int x) { + return x.value_or(42); + }, py::arg_v("x", std::experimental::nullopt, "None")); +#endif + + m.attr("has_optional") = py::cast(has_optional); + m.attr("has_exp_optional") = py::cast(has_exp_optional); + + m.def("test_default_constructors", []() { + return py::dict( + "str"_a=py::str(), + "bool"_a=py::bool_(), + "int"_a=py::int_(), + "float"_a=py::float_(), + "tuple"_a=py::tuple(), + "list"_a=py::list(), + "dict"_a=py::dict(), + "set"_a=py::set() + ); + }); + + m.def("test_converting_constructors", [](py::dict d) { + return py::dict( + "str"_a=py::str(d["str"]), + "bool"_a=py::bool_(d["bool"]), + "int"_a=py::int_(d["int"]), + "float"_a=py::float_(d["float"]), + "tuple"_a=py::tuple(d["tuple"]), + "list"_a=py::list(d["list"]), + "dict"_a=py::dict(d["dict"]), + "set"_a=py::set(d["set"]), + "memoryview"_a=py::memoryview(d["memoryview"]) + ); + }); + + m.def("test_cast_functions", [](py::dict d) { + // When converting between Python types, obj.cast() should be the same as T(obj) + return py::dict( + "str"_a=d["str"].cast(), + "bool"_a=d["bool"].cast(), + "int"_a=d["int"].cast(), + "float"_a=d["float"].cast(), + "tuple"_a=d["tuple"].cast(), + "list"_a=d["list"].cast(), + "dict"_a=d["dict"].cast(), + "set"_a=d["set"].cast(), + "memoryview"_a=d["memoryview"].cast() + ); + }); + + py::class_(m, "MoveOutContainerValue") + .def_readonly("value", &MoveOutContainer::Value::value); + + py::class_(m, "MoveOutContainer") + .def(py::init<>()) + .def_property_readonly("move_list", &MoveOutContainer::move_list); +}); diff --git a/resources/pybind11/tests/test_python_types.py b/resources/pybind11/tests/test_python_types.py new file mode 100755 index 0000000..abffa1a --- /dev/null +++ b/resources/pybind11/tests/test_python_types.py @@ -0,0 +1,374 @@ +import pytest + +from pybind11_tests import ExamplePythonTypes, ConstructorStats, has_optional, has_exp_optional + + +def test_static(): + ExamplePythonTypes.value = 15 + assert ExamplePythonTypes.value == 15 + assert ExamplePythonTypes.value2 == 5 + + with pytest.raises(AttributeError) as excinfo: + ExamplePythonTypes.value2 = 15 + assert str(excinfo.value) == "can't set attribute" + + +def test_instance(capture): + with pytest.raises(TypeError) as excinfo: + ExamplePythonTypes() + assert str(excinfo.value) == "pybind11_tests.ExamplePythonTypes: No constructor defined!" + + instance = ExamplePythonTypes.new_instance() + + with capture: + dict_result = instance.get_dict() + dict_result['key2'] = 'value2' + instance.print_dict(dict_result) + assert capture.unordered == """ + key: key, value=value + key: key2, value=value2 + """ + with capture: + dict_result = instance.get_dict_2() + dict_result['key2'] = 'value2' + instance.print_dict_2(dict_result) + assert capture.unordered == """ + key: key, value=value + key: key2, value=value2 + """ + with capture: + set_result = instance.get_set() + set_result.add('key3') + instance.print_set(set_result) + assert capture.unordered == """ + key: key1 + key: key2 + key: key3 + """ + with capture: + set_result = instance.get_set2() + set_result.add('key3') + instance.print_set_2(set_result) + assert capture.unordered == """ + key: key1 + key: key2 + key: key3 + """ + with capture: + list_result = instance.get_list() + list_result.append('value2') + instance.print_list(list_result) + assert capture.unordered == """ + Entry at position 0: value + list item 0: overwritten + list item 1: value2 + """ + with capture: + list_result = instance.get_list_2() + list_result.append('value2') + instance.print_list_2(list_result) + assert capture.unordered == """ + list item 0: value + list item 1: value2 + """ + with capture: + list_result = instance.get_list_2() + list_result.append('value2') + instance.print_list_2(tuple(list_result)) + assert capture.unordered == """ + list item 0: value + list item 1: value2 + """ + array_result = instance.get_array() + assert array_result == ['array entry 1', 'array entry 2'] + with capture: + instance.print_array(array_result) + assert capture.unordered == """ + array item 0: array entry 1 + array item 1: array entry 2 + """ + with pytest.raises(RuntimeError) as excinfo: + instance.throw_exception() + assert str(excinfo.value) == "This exception was intentionally thrown." + + assert instance.pair_passthrough((True, "test")) == ("test", True) + assert instance.tuple_passthrough((True, "test", 5)) == (5, "test", True) + # Any sequence can be cast to a std::pair or std::tuple + assert instance.pair_passthrough([True, "test"]) == ("test", True) + assert instance.tuple_passthrough([True, "test", 5]) == (5, "test", True) + + assert instance.get_bytes_from_string().decode() == "foo" + assert instance.get_bytes_from_str().decode() == "bar" + assert instance.get_str_from_string().encode().decode() == "baz" + assert instance.get_str_from_bytes().encode().decode() == "boo" + + class A(object): + def __str__(self): + return "this is a str" + + def __repr__(self): + return "this is a repr" + + with capture: + instance.test_print(A()) + assert capture == """ + this is a str + this is a repr + """ + + cstats = ConstructorStats.get(ExamplePythonTypes) + assert cstats.alive() == 1 + del instance + assert cstats.alive() == 0 + + +def test_docs(doc): + assert doc(ExamplePythonTypes) == "Example 2 documentation" + assert doc(ExamplePythonTypes.get_dict) == """ + get_dict(self: m.ExamplePythonTypes) -> dict + + Return a Python dictionary + """ + assert doc(ExamplePythonTypes.get_dict_2) == """ + get_dict_2(self: m.ExamplePythonTypes) -> Dict[str, str] + + Return a C++ dictionary + """ + assert doc(ExamplePythonTypes.get_list) == """ + get_list(self: m.ExamplePythonTypes) -> list + + Return a Python list + """ + assert doc(ExamplePythonTypes.get_list_2) == """ + get_list_2(self: m.ExamplePythonTypes) -> List[str] + + Return a C++ list + """ + assert doc(ExamplePythonTypes.get_dict) == """ + get_dict(self: m.ExamplePythonTypes) -> dict + + Return a Python dictionary + """ + assert doc(ExamplePythonTypes.get_set) == """ + get_set(self: m.ExamplePythonTypes) -> set + + Return a Python set + """ + assert doc(ExamplePythonTypes.get_set2) == """ + get_set2(self: m.ExamplePythonTypes) -> Set[str] + + Return a C++ set + """ + assert doc(ExamplePythonTypes.get_array) == """ + get_array(self: m.ExamplePythonTypes) -> List[str[2]] + + Return a C++ array + """ + assert doc(ExamplePythonTypes.print_dict) == """ + print_dict(self: m.ExamplePythonTypes, arg0: dict) -> None + + Print entries of a Python dictionary + """ + assert doc(ExamplePythonTypes.print_dict_2) == """ + print_dict_2(self: m.ExamplePythonTypes, arg0: Dict[str, str]) -> None + + Print entries of a C++ dictionary + """ + assert doc(ExamplePythonTypes.print_set) == """ + print_set(self: m.ExamplePythonTypes, arg0: set) -> None + + Print entries of a Python set + """ + assert doc(ExamplePythonTypes.print_set_2) == """ + print_set_2(self: m.ExamplePythonTypes, arg0: Set[str]) -> None + + Print entries of a C++ set + """ + assert doc(ExamplePythonTypes.print_list) == """ + print_list(self: m.ExamplePythonTypes, arg0: list) -> None + + Print entries of a Python list + """ + assert doc(ExamplePythonTypes.print_list_2) == """ + print_list_2(self: m.ExamplePythonTypes, arg0: List[str]) -> None + + Print entries of a C++ list + """ + assert doc(ExamplePythonTypes.print_array) == """ + print_array(self: m.ExamplePythonTypes, arg0: List[str[2]]) -> None + + Print entries of a C++ array + """ + assert doc(ExamplePythonTypes.pair_passthrough) == """ + pair_passthrough(self: m.ExamplePythonTypes, arg0: Tuple[bool, str]) -> Tuple[str, bool] + + Return a pair in reversed order + """ + assert doc(ExamplePythonTypes.tuple_passthrough) == """ + tuple_passthrough(self: m.ExamplePythonTypes, arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool] + + Return a triple in reversed order + """ + assert doc(ExamplePythonTypes.throw_exception) == """ + throw_exception(self: m.ExamplePythonTypes) -> None + + Throw an exception + """ + assert doc(ExamplePythonTypes.new_instance) == """ + new_instance() -> m.ExamplePythonTypes + + Return an instance + """ + + +def test_module(): + import pybind11_tests + + assert pybind11_tests.__name__ == "pybind11_tests" + assert ExamplePythonTypes.__name__ == "ExamplePythonTypes" + assert ExamplePythonTypes.__module__ == "pybind11_tests" + assert ExamplePythonTypes.get_set.__name__ == "get_set" + assert ExamplePythonTypes.get_set.__module__ == "pybind11_tests" + + +def test_print(capture): + from pybind11_tests import test_print_function + + with capture: + test_print_function() + assert capture == """ + Hello, World! + 1 2.0 three True -- multiple args + *args-and-a-custom-separator + no new line here -- next print + flush + py::print + str.format = this + """ + assert capture.stderr == "this goes to stderr" + + +def test_str_api(): + from pybind11_tests import test_str_format + + s1, s2 = test_str_format() + assert s1 == "1 + 2 = 3" + assert s1 == s2 + + +def test_dict_api(): + from pybind11_tests import test_dict_keyword_constructor + + assert test_dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3} + + +def test_accessors(): + from pybind11_tests import test_accessor_api, test_tuple_accessor, test_accessor_assignment + + class SubTestObject: + attr_obj = 1 + attr_char = 2 + + class TestObject: + basic_attr = 1 + begin_end = [1, 2, 3] + d = {"operator[object]": 1, "operator[char *]": 2} + sub = SubTestObject() + + def func(self, x, *args): + return self.basic_attr + x + sum(args) + + d = test_accessor_api(TestObject()) + assert d["basic_attr"] == 1 + assert d["begin_end"] == [1, 2, 3] + assert d["operator[object]"] == 1 + assert d["operator[char *]"] == 2 + assert d["attr(object)"] == 1 + assert d["attr(char *)"] == 2 + assert d["missing_attr_ptr"] == "raised" + assert d["missing_attr_chain"] == "raised" + assert d["is_none"] is False + assert d["operator()"] == 2 + assert d["operator*"] == 7 + + assert test_tuple_accessor(tuple()) == (0, 1, 2) + + d = test_accessor_assignment() + assert d["get"] == 0 + assert d["deferred_get"] == 0 + assert d["set"] == 1 + assert d["deferred_set"] == 1 + assert d["var"] == 99 + + +@pytest.mark.skipif(not has_optional, reason='no ') +def test_optional(): + from pybind11_tests import double_or_zero, half_or_none, test_nullopt + + assert double_or_zero(None) == 0 + assert double_or_zero(42) == 84 + pytest.raises(TypeError, double_or_zero, 'foo') + + assert half_or_none(0) is None + assert half_or_none(42) == 21 + pytest.raises(TypeError, half_or_none, 'foo') + + assert test_nullopt() == 42 + assert test_nullopt(None) == 42 + assert test_nullopt(42) == 42 + assert test_nullopt(43) == 43 + + +@pytest.mark.skipif(not has_exp_optional, reason='no ') +def test_exp_optional(): + from pybind11_tests import double_or_zero_exp, half_or_none_exp, test_nullopt_exp + + assert double_or_zero_exp(None) == 0 + assert double_or_zero_exp(42) == 84 + pytest.raises(TypeError, double_or_zero_exp, 'foo') + + assert half_or_none_exp(0) is None + assert half_or_none_exp(42) == 21 + pytest.raises(TypeError, half_or_none_exp, 'foo') + + assert test_nullopt_exp() == 42 + assert test_nullopt_exp(None) == 42 + assert test_nullopt_exp(42) == 42 + assert test_nullopt_exp(43) == 43 + + +def test_constructors(): + """C++ default and converting constructors are equivalent to type calls in Python""" + from pybind11_tests import (test_default_constructors, test_converting_constructors, + test_cast_functions) + + types = [str, bool, int, float, tuple, list, dict, set] + expected = {t.__name__: t() for t in types} + assert test_default_constructors() == expected + + data = { + str: 42, + bool: "Not empty", + int: "42", + float: "+1e3", + tuple: range(3), + list: range(3), + dict: [("two", 2), ("one", 1), ("three", 3)], + set: [4, 4, 5, 6, 6, 6], + memoryview: b'abc' + } + inputs = {k.__name__: v for k, v in data.items()} + expected = {k.__name__: k(v) for k, v in data.items()} + assert test_converting_constructors(inputs) == expected + assert test_cast_functions(inputs) == expected + + +def test_move_out_container(): + """Properties use the `reference_internal` policy by default. If the underlying function + returns an rvalue, the policy is automatically changed to `move` to avoid referencing + a temporary. In case the return value is a container of user-defined types, the policy + also needs to be applied to the elements, not just the container.""" + from pybind11_tests import MoveOutContainer + + c = MoveOutContainer() + moved_out_list = c.move_list + assert [x.value for x in moved_out_list] == [0, 1, 2] diff --git a/resources/pybind11/tests/test_sequences_and_iterators.cpp b/resources/pybind11/tests/test_sequences_and_iterators.cpp new file mode 100755 index 0000000..323b4bf --- /dev/null +++ b/resources/pybind11/tests/test_sequences_and_iterators.cpp @@ -0,0 +1,275 @@ +/* + tests/test_sequences_and_iterators.cpp -- supporting Pythons' sequence protocol, iterators, + etc. + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include +#include + +class Sequence { +public: + Sequence(size_t size) : m_size(size) { + print_created(this, "of size", m_size); + m_data = new float[size]; + memset(m_data, 0, sizeof(float) * size); + } + + Sequence(const std::vector &value) : m_size(value.size()) { + print_created(this, "of size", m_size, "from std::vector"); + m_data = new float[m_size]; + memcpy(m_data, &value[0], sizeof(float) * m_size); + } + + Sequence(const Sequence &s) : m_size(s.m_size) { + print_copy_created(this); + m_data = new float[m_size]; + memcpy(m_data, s.m_data, sizeof(float)*m_size); + } + + Sequence(Sequence &&s) : m_size(s.m_size), m_data(s.m_data) { + print_move_created(this); + s.m_size = 0; + s.m_data = nullptr; + } + + ~Sequence() { + print_destroyed(this); + delete[] m_data; + } + + Sequence &operator=(const Sequence &s) { + if (&s != this) { + delete[] m_data; + m_size = s.m_size; + m_data = new float[m_size]; + memcpy(m_data, s.m_data, sizeof(float)*m_size); + } + + print_copy_assigned(this); + + return *this; + } + + Sequence &operator=(Sequence &&s) { + if (&s != this) { + delete[] m_data; + m_size = s.m_size; + m_data = s.m_data; + s.m_size = 0; + s.m_data = nullptr; + } + + print_move_assigned(this); + + return *this; + } + + bool operator==(const Sequence &s) const { + if (m_size != s.size()) + return false; + for (size_t i=0; i> data) : data_(std::move(data)) {} + const std::pair* begin() const { return data_.data(); } + +private: + std::vector> data_; +}; + +// Interface of a map-like object that isn't (directly) an unordered_map, but provides some basic +// map-like functionality. +class StringMap { +public: + StringMap() = default; + StringMap(std::unordered_map init) + : map(std::move(init)) {} + + void set(std::string key, std::string val) { + map[key] = val; + } + + std::string get(std::string key) const { + return map.at(key); + } + + size_t size() const { + return map.size(); + } + +private: + std::unordered_map map; + +public: + decltype(map.cbegin()) begin() const { return map.cbegin(); } + decltype(map.cend()) end() const { return map.cend(); } +}; + +template +class NonZeroIterator { + const T* ptr_; +public: + NonZeroIterator(const T* ptr) : ptr_(ptr) {} + const T& operator*() const { return *ptr_; } + NonZeroIterator& operator++() { ++ptr_; return *this; } +}; + +class NonZeroSentinel {}; + +template +bool operator==(const NonZeroIterator>& it, const NonZeroSentinel&) { + return !(*it).first || !(*it).second; +} + +test_initializer sequences_and_iterators([](py::module &m) { + + py::class_ seq(m, "Sequence"); + + seq.def(py::init()) + .def(py::init&>()) + /// Bare bones interface + .def("__getitem__", [](const Sequence &s, size_t i) { + if (i >= s.size()) + throw py::index_error(); + return s[i]; + }) + .def("__setitem__", [](Sequence &s, size_t i, float v) { + if (i >= s.size()) + throw py::index_error(); + s[i] = v; + }) + .def("__len__", &Sequence::size) + /// Optional sequence protocol operations + .def("__iter__", [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); }, + py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */) + .def("__contains__", [](const Sequence &s, float v) { return s.contains(v); }) + .def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); }) + /// Slicing protocol (optional) + .def("__getitem__", [](const Sequence &s, py::slice slice) -> Sequence* { + size_t start, stop, step, slicelength; + if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) + throw py::error_already_set(); + Sequence *seq = new Sequence(slicelength); + for (size_t i=0; i map(m, "StringMap"); + + map .def(py::init<>()) + .def(py::init>()) + .def("__getitem__", [](const StringMap &map, std::string key) { + try { return map.get(key); } + catch (const std::out_of_range&) { + throw py::key_error("key '" + key + "' does not exist"); + } + }) + .def("__setitem__", &StringMap::set) + .def("__len__", &StringMap::size) + .def("__iter__", [](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); }, + py::keep_alive<0, 1>()) + .def("items", [](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); }, + py::keep_alive<0, 1>()) + ; + + py::class_(m, "IntPairs") + .def(py::init>>()) + .def("nonzero", [](const IntPairs& s) { + return py::make_iterator(NonZeroIterator>(s.begin()), NonZeroSentinel()); + }, py::keep_alive<0, 1>()) + .def("nonzero_keys", [](const IntPairs& s) { + return py::make_key_iterator(NonZeroIterator>(s.begin()), NonZeroSentinel()); + }, py::keep_alive<0, 1>()); + + +#if 0 + // Obsolete: special data structure for exposing custom iterator types to python + // kept here for illustrative purposes because there might be some use cases which + // are not covered by the much simpler py::make_iterator + + struct PySequenceIterator { + PySequenceIterator(const Sequence &seq, py::object ref) : seq(seq), ref(ref) { } + + float next() { + if (index == seq.size()) + throw py::stop_iteration(); + return seq[index++]; + } + + const Sequence &seq; + py::object ref; // keep a reference + size_t index = 0; + }; + + py::class_(seq, "Iterator") + .def("__iter__", [](PySequenceIterator &it) -> PySequenceIterator& { return it; }) + .def("__next__", &PySequenceIterator::next); + + On the actual Sequence object, the iterator would be constructed as follows: + .def("__iter__", [](py::object s) { return PySequenceIterator(s.cast(), s); }) +#endif +}); diff --git a/resources/pybind11/tests/test_sequences_and_iterators.py b/resources/pybind11/tests/test_sequences_and_iterators.py new file mode 100755 index 0000000..76b9f43 --- /dev/null +++ b/resources/pybind11/tests/test_sequences_and_iterators.py @@ -0,0 +1,90 @@ +import pytest + + +def isclose(a, b, rel_tol=1e-05, abs_tol=0.0): + """Like math.isclose() from Python 3.5""" + return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol) + + +def allclose(a_list, b_list, rel_tol=1e-05, abs_tol=0.0): + return all(isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol) for a, b in zip(a_list, b_list)) + + +def test_generalized_iterators(): + from pybind11_tests import IntPairs + + assert list(IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero()) == [(1, 2), (3, 4)] + assert list(IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero()) == [(1, 2)] + assert list(IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero()) == [] + + assert list(IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero_keys()) == [1, 3] + assert list(IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero_keys()) == [1] + assert list(IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero_keys()) == [] + + +def test_sequence(): + from pybind11_tests import Sequence, ConstructorStats + + cstats = ConstructorStats.get(Sequence) + + s = Sequence(5) + assert cstats.values() == ['of size', '5'] + + assert "Sequence" in repr(s) + assert len(s) == 5 + assert s[0] == 0 and s[3] == 0 + assert 12.34 not in s + s[0], s[3] = 12.34, 56.78 + assert 12.34 in s + assert isclose(s[0], 12.34) and isclose(s[3], 56.78) + + rev = reversed(s) + assert cstats.values() == ['of size', '5'] + + rev2 = s[::-1] + assert cstats.values() == ['of size', '5'] + + expected = [0, 56.78, 0, 0, 12.34] + assert allclose(rev, expected) + assert allclose(rev2, expected) + assert rev == rev2 + + rev[0::2] = Sequence([2.0, 2.0, 2.0]) + assert cstats.values() == ['of size', '3', 'from std::vector'] + + assert allclose(rev, [2, 56.78, 2, 0, 2]) + + assert cstats.alive() == 3 + del s + assert cstats.alive() == 2 + del rev + assert cstats.alive() == 1 + del rev2 + assert cstats.alive() == 0 + + assert cstats.values() == [] + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + assert cstats.move_constructions >= 1 + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + +def test_map_iterator(): + from pybind11_tests import StringMap + + m = StringMap({'hi': 'bye', 'black': 'white'}) + assert m['hi'] == 'bye' + assert len(m) == 2 + assert m['black'] == 'white' + + with pytest.raises(KeyError): + assert m['orange'] + m['orange'] = 'banana' + assert m['orange'] == 'banana' + + expected = {'hi': 'bye', 'black': 'white', 'orange': 'banana'} + for k in m: + assert m[k] == expected[k] + for k, v in m.items(): + assert v == expected[k] diff --git a/resources/pybind11/tests/test_smart_ptr.cpp b/resources/pybind11/tests/test_smart_ptr.cpp new file mode 100755 index 0000000..07c3cb0 --- /dev/null +++ b/resources/pybind11/tests/test_smart_ptr.cpp @@ -0,0 +1,224 @@ +/* + tests/test_smart_ptr.cpp -- binding classes with custom reference counting, + implicit conversions between types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "object.h" + +/// Custom object with builtin reference counting (see 'object.h' for the implementation) +class MyObject1 : public Object { +public: + MyObject1(int value) : value(value) { + print_created(this, toString()); + } + + std::string toString() const { + return "MyObject1[" + std::to_string(value) + "]"; + } + +protected: + virtual ~MyObject1() { + print_destroyed(this); + } + +private: + int value; +}; + +/// Object managed by a std::shared_ptr<> +class MyObject2 { +public: + MyObject2(int value) : value(value) { + print_created(this, toString()); + } + + std::string toString() const { + return "MyObject2[" + std::to_string(value) + "]"; + } + + virtual ~MyObject2() { + print_destroyed(this); + } + +private: + int value; +}; + +/// Object managed by a std::shared_ptr<>, additionally derives from std::enable_shared_from_this<> +class MyObject3 : public std::enable_shared_from_this { +public: + MyObject3(int value) : value(value) { + print_created(this, toString()); + } + + std::string toString() const { + return "MyObject3[" + std::to_string(value) + "]"; + } + + virtual ~MyObject3() { + print_destroyed(this); + } + +private: + int value; +}; + +class MyObject4 { +public: + MyObject4(int value) : value{value} { + print_created(this); + } + int value; +private: + ~MyObject4() { + print_destroyed(this); + } +}; + +/// Make pybind aware of the ref-counted wrapper type (s) +PYBIND11_DECLARE_HOLDER_TYPE(T, ref); // Required for custom holder type +PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); // Not required any more for std::shared_ptr, + // but it should compile without error + +Object *make_object_1() { return new MyObject1(1); } +ref make_object_2() { return new MyObject1(2); } + +MyObject1 *make_myobject1_1() { return new MyObject1(4); } +ref make_myobject1_2() { return new MyObject1(5); } + +MyObject2 *make_myobject2_1() { return new MyObject2(6); } +std::shared_ptr make_myobject2_2() { return std::make_shared(7); } + +MyObject3 *make_myobject3_1() { return new MyObject3(8); } +std::shared_ptr make_myobject3_2() { return std::make_shared(9); } + +void print_object_1(const Object *obj) { py::print(obj->toString()); } +void print_object_2(ref obj) { py::print(obj->toString()); } +void print_object_3(const ref &obj) { py::print(obj->toString()); } +void print_object_4(const ref *obj) { py::print((*obj)->toString()); } + +void print_myobject1_1(const MyObject1 *obj) { py::print(obj->toString()); } +void print_myobject1_2(ref obj) { py::print(obj->toString()); } +void print_myobject1_3(const ref &obj) { py::print(obj->toString()); } +void print_myobject1_4(const ref *obj) { py::print((*obj)->toString()); } + +void print_myobject2_1(const MyObject2 *obj) { py::print(obj->toString()); } +void print_myobject2_2(std::shared_ptr obj) { py::print(obj->toString()); } +void print_myobject2_3(const std::shared_ptr &obj) { py::print(obj->toString()); } +void print_myobject2_4(const std::shared_ptr *obj) { py::print((*obj)->toString()); } + +void print_myobject3_1(const MyObject3 *obj) { py::print(obj->toString()); } +void print_myobject3_2(std::shared_ptr obj) { py::print(obj->toString()); } +void print_myobject3_3(const std::shared_ptr &obj) { py::print(obj->toString()); } +void print_myobject3_4(const std::shared_ptr *obj) { py::print((*obj)->toString()); } + +test_initializer smart_ptr([](py::module &m) { + py::class_> obj(m, "Object"); + obj.def("getRefCount", &Object::getRefCount); + + py::class_>(m, "MyObject1", obj) + .def(py::init()); + + m.def("make_object_1", &make_object_1); + m.def("make_object_2", &make_object_2); + m.def("make_myobject1_1", &make_myobject1_1); + m.def("make_myobject1_2", &make_myobject1_2); + m.def("print_object_1", &print_object_1); + m.def("print_object_2", &print_object_2); + m.def("print_object_3", &print_object_3); + m.def("print_object_4", &print_object_4); + m.def("print_myobject1_1", &print_myobject1_1); + m.def("print_myobject1_2", &print_myobject1_2); + m.def("print_myobject1_3", &print_myobject1_3); + m.def("print_myobject1_4", &print_myobject1_4); + + py::class_>(m, "MyObject2") + .def(py::init()); + m.def("make_myobject2_1", &make_myobject2_1); + m.def("make_myobject2_2", &make_myobject2_2); + m.def("print_myobject2_1", &print_myobject2_1); + m.def("print_myobject2_2", &print_myobject2_2); + m.def("print_myobject2_3", &print_myobject2_3); + m.def("print_myobject2_4", &print_myobject2_4); + + py::class_>(m, "MyObject3") + .def(py::init()); + m.def("make_myobject3_1", &make_myobject3_1); + m.def("make_myobject3_2", &make_myobject3_2); + m.def("print_myobject3_1", &print_myobject3_1); + m.def("print_myobject3_2", &print_myobject3_2); + m.def("print_myobject3_3", &print_myobject3_3); + m.def("print_myobject3_4", &print_myobject3_4); + + py::class_>(m, "MyObject4") + .def(py::init()) + .def_readwrite("value", &MyObject4::value); + + py::implicitly_convertible(); + + // Expose constructor stats for the ref type + m.def("cstats_ref", &ConstructorStats::get); +}); + +struct SharedPtrRef { + struct A { + A() { print_created(this); } + A(const A &) { print_copy_created(this); } + A(A &&) { print_move_created(this); } + ~A() { print_destroyed(this); } + }; + + A value = {}; + std::shared_ptr shared = std::make_shared(); +}; + +struct SharedFromThisRef { + struct B : std::enable_shared_from_this { + B() { print_created(this); } + B(const B &) : std::enable_shared_from_this() { print_copy_created(this); } + B(B &&) : std::enable_shared_from_this() { print_move_created(this); } + ~B() { print_destroyed(this); } + }; + + B value = {}; + std::shared_ptr shared = std::make_shared(); +}; + +test_initializer smart_ptr_and_references([](py::module &pm) { + auto m = pm.def_submodule("smart_ptr"); + + using A = SharedPtrRef::A; + py::class_>(m, "A"); + + py::class_(m, "SharedPtrRef") + .def(py::init<>()) + .def_readonly("ref", &SharedPtrRef::value) + .def_property_readonly("copy", [](const SharedPtrRef &s) { return s.value; }, + py::return_value_policy::copy) + .def_readonly("holder_ref", &SharedPtrRef::shared) + .def_property_readonly("holder_copy", [](const SharedPtrRef &s) { return s.shared; }, + py::return_value_policy::copy) + .def("set_ref", [](SharedPtrRef &, const A &) { return true; }) + .def("set_holder", [](SharedPtrRef &, std::shared_ptr) { return true; }); + + using B = SharedFromThisRef::B; + py::class_>(m, "B"); + + py::class_(m, "SharedFromThisRef") + .def(py::init<>()) + .def_readonly("bad_wp", &SharedFromThisRef::value) + .def_property_readonly("ref", [](const SharedFromThisRef &s) -> const B & { return *s.shared; }) + .def_property_readonly("copy", [](const SharedFromThisRef &s) { return s.value; }, + py::return_value_policy::copy) + .def_readonly("holder_ref", &SharedFromThisRef::shared) + .def_property_readonly("holder_copy", [](const SharedFromThisRef &s) { return s.shared; }, + py::return_value_policy::copy) + .def("set_ref", [](SharedFromThisRef &, const B &) { return true; }) + .def("set_holder", [](SharedFromThisRef &, std::shared_ptr) { return true; }); +}); diff --git a/resources/pybind11/tests/test_smart_ptr.py b/resources/pybind11/tests/test_smart_ptr.py new file mode 100755 index 0000000..3a33e17 --- /dev/null +++ b/resources/pybind11/tests/test_smart_ptr.py @@ -0,0 +1,198 @@ +import pytest +from pybind11_tests import ConstructorStats + + +def test_smart_ptr(capture): + # Object1 + from pybind11_tests import (MyObject1, make_object_1, make_object_2, + print_object_1, print_object_2, print_object_3, print_object_4) + + for i, o in enumerate([make_object_1(), make_object_2(), MyObject1(3)], start=1): + assert o.getRefCount() == 1 + with capture: + print_object_1(o) + print_object_2(o) + print_object_3(o) + print_object_4(o) + assert capture == "MyObject1[{i}]\n".format(i=i) * 4 + + from pybind11_tests import (make_myobject1_1, make_myobject1_2, + print_myobject1_1, print_myobject1_2, + print_myobject1_3, print_myobject1_4) + + for i, o in enumerate([make_myobject1_1(), make_myobject1_2(), MyObject1(6), 7], start=4): + print(o) + with capture: + if not isinstance(o, int): + print_object_1(o) + print_object_2(o) + print_object_3(o) + print_object_4(o) + print_myobject1_1(o) + print_myobject1_2(o) + print_myobject1_3(o) + print_myobject1_4(o) + assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8) + + cstats = ConstructorStats.get(MyObject1) + assert cstats.alive() == 0 + expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4 + assert cstats.values() == expected_values + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + # Object2 + from pybind11_tests import (MyObject2, make_myobject2_1, make_myobject2_2, + make_myobject3_1, make_myobject3_2, + print_myobject2_1, print_myobject2_2, + print_myobject2_3, print_myobject2_4) + + for i, o in zip([8, 6, 7], [MyObject2(8), make_myobject2_1(), make_myobject2_2()]): + print(o) + with capture: + print_myobject2_1(o) + print_myobject2_2(o) + print_myobject2_3(o) + print_myobject2_4(o) + assert capture == "MyObject2[{i}]\n".format(i=i) * 4 + + cstats = ConstructorStats.get(MyObject2) + assert cstats.alive() == 1 + o = None + assert cstats.alive() == 0 + assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]'] + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + # Object3 + from pybind11_tests import (MyObject3, print_myobject3_1, print_myobject3_2, + print_myobject3_3, print_myobject3_4) + + for i, o in zip([9, 8, 9], [MyObject3(9), make_myobject3_1(), make_myobject3_2()]): + print(o) + with capture: + print_myobject3_1(o) + print_myobject3_2(o) + print_myobject3_3(o) + print_myobject3_4(o) + assert capture == "MyObject3[{i}]\n".format(i=i) * 4 + + cstats = ConstructorStats.get(MyObject3) + assert cstats.alive() == 1 + o = None + assert cstats.alive() == 0 + assert cstats.values() == ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]'] + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + # Object and ref + from pybind11_tests import Object, cstats_ref + + cstats = ConstructorStats.get(Object) + assert cstats.alive() == 0 + assert cstats.values() == [] + assert cstats.default_constructions == 10 + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + cstats = cstats_ref() + assert cstats.alive() == 0 + assert cstats.values() == ['from pointer'] * 10 + assert cstats.default_constructions == 30 + assert cstats.copy_constructions == 12 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 30 + assert cstats.move_assignments == 0 + + +def test_unique_nodelete(): + from pybind11_tests import MyObject4 + o = MyObject4(23) + assert o.value == 23 + cstats = ConstructorStats.get(MyObject4) + assert cstats.alive() == 1 + del o + cstats = ConstructorStats.get(MyObject4) + assert cstats.alive() == 1 # Leak, but that's intentional + + +def test_shared_ptr_and_references(): + from pybind11_tests.smart_ptr import SharedPtrRef, A + + s = SharedPtrRef() + stats = ConstructorStats.get(A) + assert stats.alive() == 2 + + ref = s.ref # init_holder_helper(holder_ptr=false, owned=false) + assert stats.alive() == 2 + assert s.set_ref(ref) + with pytest.raises(RuntimeError) as excinfo: + assert s.set_holder(ref) + assert "Unable to cast from non-held to held instance" in str(excinfo.value) + + copy = s.copy # init_holder_helper(holder_ptr=false, owned=true) + assert stats.alive() == 3 + assert s.set_ref(copy) + assert s.set_holder(copy) + + holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false) + assert stats.alive() == 3 + assert s.set_ref(holder_ref) + assert s.set_holder(holder_ref) + + holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true) + assert stats.alive() == 3 + assert s.set_ref(holder_copy) + assert s.set_holder(holder_copy) + + del ref, copy, holder_ref, holder_copy, s + assert stats.alive() == 0 + + +def test_shared_ptr_from_this_and_references(): + from pybind11_tests.smart_ptr import SharedFromThisRef, B + + s = SharedFromThisRef() + stats = ConstructorStats.get(B) + assert stats.alive() == 2 + + ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false) + assert stats.alive() == 2 + assert s.set_ref(ref) + assert s.set_holder(ref) # std::enable_shared_from_this can create a holder from a reference + + bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true) + assert stats.alive() == 2 + assert s.set_ref(bad_wp) + with pytest.raises(RuntimeError) as excinfo: + assert s.set_holder(bad_wp) + assert "Unable to cast from non-held to held instance" in str(excinfo.value) + + copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false) + assert stats.alive() == 3 + assert s.set_ref(copy) + assert s.set_holder(copy) + + holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false) + assert stats.alive() == 3 + assert s.set_ref(holder_ref) + assert s.set_holder(holder_ref) + + holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false) + assert stats.alive() == 3 + assert s.set_ref(holder_copy) + assert s.set_holder(holder_copy) + + del ref, bad_wp, copy, holder_ref, holder_copy, s + assert stats.alive() == 0 diff --git a/resources/pybind11/tests/test_stl_binders.cpp b/resources/pybind11/tests/test_stl_binders.cpp new file mode 100755 index 0000000..b9b56c1 --- /dev/null +++ b/resources/pybind11/tests/test_stl_binders.cpp @@ -0,0 +1,95 @@ +/* + tests/test_stl_binders.cpp -- Usage of stl_binders functions + + Copyright (c) 2016 Sergey Lyskov + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +#include +#include +#include +#include + +class El { +public: + El() = delete; + El(int v) : a(v) { } + + int a; +}; + +std::ostream & operator<<(std::ostream &s, El const&v) { + s << "El{" << v.a << '}'; + return s; +} + +/// Issue #487: binding std::vector with E non-copyable +class E_nc { +public: + explicit E_nc(int i) : value{i} {} + E_nc(const E_nc &) = delete; + E_nc &operator=(const E_nc &) = delete; + E_nc(E_nc &&) = default; + E_nc &operator=(E_nc &&) = default; + + int value; +}; + +template Container *one_to_n(int n) { + auto v = new Container(); + for (int i = 1; i <= n; i++) + v->emplace_back(i); + return v; +} + +template Map *times_ten(int n) { + auto m = new Map(); + for (int i = 1; i <= n; i++) + m->emplace(int(i), E_nc(10*i)); + return m; +} + +test_initializer stl_binder_vector([](py::module &m) { + py::class_(m, "El") + .def(py::init()); + + py::bind_vector>(m, "VectorInt"); + py::bind_vector>(m, "VectorBool"); + + py::bind_vector>(m, "VectorEl"); + + py::bind_vector>>(m, "VectorVectorEl"); + +}); + +test_initializer stl_binder_map([](py::module &m) { + py::bind_map>(m, "MapStringDouble"); + py::bind_map>(m, "UnorderedMapStringDouble"); + + py::bind_map>(m, "MapStringDoubleConst"); + py::bind_map>(m, "UnorderedMapStringDoubleConst"); + +}); + +test_initializer stl_binder_noncopyable([](py::module &m) { + py::class_(m, "ENC") + .def(py::init()) + .def_readwrite("value", &E_nc::value); + + py::bind_vector>(m, "VectorENC"); + m.def("get_vnc", &one_to_n>, py::return_value_policy::reference); + + py::bind_vector>(m, "DequeENC"); + m.def("get_dnc", &one_to_n>, py::return_value_policy::reference); + + py::bind_map>(m, "MapENC"); + m.def("get_mnc", ×_ten>, py::return_value_policy::reference); + + py::bind_map>(m, "UmapENC"); + m.def("get_umnc", ×_ten>, py::return_value_policy::reference); +}); + diff --git a/resources/pybind11/tests/test_stl_binders.py b/resources/pybind11/tests/test_stl_binders.py new file mode 100755 index 0000000..c9bcc79 --- /dev/null +++ b/resources/pybind11/tests/test_stl_binders.py @@ -0,0 +1,140 @@ +def test_vector_int(): + from pybind11_tests import VectorInt + + v_int = VectorInt([0, 0]) + assert len(v_int) == 2 + assert bool(v_int) is True + + v_int2 = VectorInt([0, 0]) + assert v_int == v_int2 + v_int2[1] = 1 + assert v_int != v_int2 + + v_int2.append(2) + v_int2.append(3) + v_int2.insert(0, 1) + v_int2.insert(0, 2) + v_int2.insert(0, 3) + assert str(v_int2) == "VectorInt[3, 2, 1, 0, 1, 2, 3]" + + v_int.append(99) + v_int2[2:-2] = v_int + assert v_int2 == VectorInt([3, 2, 0, 0, 99, 2, 3]) + del v_int2[1:3] + assert v_int2 == VectorInt([3, 0, 99, 2, 3]) + del v_int2[0] + assert v_int2 == VectorInt([0, 99, 2, 3]) + + +def test_vector_custom(): + from pybind11_tests import El, VectorEl, VectorVectorEl + + v_a = VectorEl() + v_a.append(El(1)) + v_a.append(El(2)) + assert str(v_a) == "VectorEl[El{1}, El{2}]" + + vv_a = VectorVectorEl() + vv_a.append(v_a) + vv_b = vv_a[0] + assert str(vv_b) == "VectorEl[El{1}, El{2}]" + + +def test_vector_bool(): + from pybind11_tests import VectorBool + + vv_c = VectorBool() + for i in range(10): + vv_c.append(i % 2 == 0) + for i in range(10): + assert vv_c[i] == (i % 2 == 0) + assert str(vv_c) == "VectorBool[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]" + + +def test_map_string_double(): + from pybind11_tests import MapStringDouble, UnorderedMapStringDouble + + m = MapStringDouble() + m['a'] = 1 + m['b'] = 2.5 + + assert list(m) == ['a', 'b'] + assert list(m.items()) == [('a', 1), ('b', 2.5)] + assert str(m) == "MapStringDouble{a: 1, b: 2.5}" + + um = UnorderedMapStringDouble() + um['ua'] = 1.1 + um['ub'] = 2.6 + + assert sorted(list(um)) == ['ua', 'ub'] + assert sorted(list(um.items())) == [('ua', 1.1), ('ub', 2.6)] + assert "UnorderedMapStringDouble" in str(um) + + +def test_map_string_double_const(): + from pybind11_tests import MapStringDoubleConst, UnorderedMapStringDoubleConst + + mc = MapStringDoubleConst() + mc['a'] = 10 + mc['b'] = 20.5 + assert str(mc) == "MapStringDoubleConst{a: 10, b: 20.5}" + + umc = UnorderedMapStringDoubleConst() + umc['a'] = 11 + umc['b'] = 21.5 + + str(umc) + + +def test_noncopyable_vector(): + from pybind11_tests import get_vnc + + vnc = get_vnc(5) + for i in range(0, 5): + assert vnc[i].value == i + 1 + + for i, j in enumerate(vnc, start=1): + assert j.value == i + + +def test_noncopyable_deque(): + from pybind11_tests import get_dnc + + dnc = get_dnc(5) + for i in range(0, 5): + assert dnc[i].value == i + 1 + + i = 1 + for j in dnc: + assert(j.value == i) + i += 1 + + +def test_noncopyable_map(): + from pybind11_tests import get_mnc + + mnc = get_mnc(5) + for i in range(1, 6): + assert mnc[i].value == 10 * i + + vsum = 0 + for k, v in mnc.items(): + assert v.value == 10 * k + vsum += v.value + + assert vsum == 150 + + +def test_noncopyable_unordered_map(): + from pybind11_tests import get_umnc + + mnc = get_umnc(5) + for i in range(1, 6): + assert mnc[i].value == 10 * i + + vsum = 0 + for k, v in mnc.items(): + assert v.value == 10 * k + vsum += v.value + + assert vsum == 150 diff --git a/resources/pybind11/tests/test_virtual_functions.cpp b/resources/pybind11/tests/test_virtual_functions.cpp new file mode 100755 index 0000000..0f8ed2a --- /dev/null +++ b/resources/pybind11/tests/test_virtual_functions.cpp @@ -0,0 +1,347 @@ +/* + tests/test_virtual_functions.cpp -- overriding virtual functions from Python + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" +#include "constructor_stats.h" +#include + +/* This is an example class that we'll want to be able to extend from Python */ +class ExampleVirt { +public: + ExampleVirt(int state) : state(state) { print_created(this, state); } + ExampleVirt(const ExampleVirt &e) : state(e.state) { print_copy_created(this); } + ExampleVirt(ExampleVirt &&e) : state(e.state) { print_move_created(this); e.state = 0; } + ~ExampleVirt() { print_destroyed(this); } + + virtual int run(int value) { + py::print("Original implementation of " + "ExampleVirt::run(state={}, value={}, str1={}, str2={})"_s.format(state, value, get_string1(), *get_string2())); + return state + value; + } + + virtual bool run_bool() = 0; + virtual void pure_virtual() = 0; + + // Returning a reference/pointer to a type converted from python (numbers, strings, etc.) is a + // bit trickier, because the actual int& or std::string& or whatever only exists temporarily, so + // we have to handle it specially in the trampoline class (see below). + virtual const std::string &get_string1() { return str1; } + virtual const std::string *get_string2() { return &str2; } + +private: + int state; + const std::string str1{"default1"}, str2{"default2"}; +}; + +/* This is a wrapper class that must be generated */ +class PyExampleVirt : public ExampleVirt { +public: + using ExampleVirt::ExampleVirt; /* Inherit constructors */ + + int run(int value) override { + /* Generate wrapping code that enables native function overloading */ + PYBIND11_OVERLOAD( + int, /* Return type */ + ExampleVirt, /* Parent class */ + run, /* Name of function */ + value /* Argument(s) */ + ); + } + + bool run_bool() override { + PYBIND11_OVERLOAD_PURE( + bool, /* Return type */ + ExampleVirt, /* Parent class */ + run_bool, /* Name of function */ + /* This function has no arguments. The trailing comma + in the previous line is needed for some compilers */ + ); + } + + void pure_virtual() override { + PYBIND11_OVERLOAD_PURE( + void, /* Return type */ + ExampleVirt, /* Parent class */ + pure_virtual, /* Name of function */ + /* This function has no arguments. The trailing comma + in the previous line is needed for some compilers */ + ); + } + + // We can return reference types for compatibility with C++ virtual interfaces that do so, but + // note they have some significant limitations (see the documentation). + const std::string &get_string1() override { + PYBIND11_OVERLOAD( + const std::string &, /* Return type */ + ExampleVirt, /* Parent class */ + get_string1, /* Name of function */ + /* (no arguments) */ + ); + } + + const std::string *get_string2() override { + PYBIND11_OVERLOAD( + const std::string *, /* Return type */ + ExampleVirt, /* Parent class */ + get_string2, /* Name of function */ + /* (no arguments) */ + ); + } + +}; + +class NonCopyable { +public: + NonCopyable(int a, int b) : value{new int(a*b)} { print_created(this, a, b); } + NonCopyable(NonCopyable &&o) { value = std::move(o.value); print_move_created(this); } + NonCopyable(const NonCopyable &) = delete; + NonCopyable() = delete; + void operator=(const NonCopyable &) = delete; + void operator=(NonCopyable &&) = delete; + std::string get_value() const { + if (value) return std::to_string(*value); else return "(null)"; + } + ~NonCopyable() { print_destroyed(this); } + +private: + std::unique_ptr value; +}; + +// This is like the above, but is both copy and movable. In effect this means it should get moved +// when it is not referenced elsewhere, but copied if it is still referenced. +class Movable { +public: + Movable(int a, int b) : value{a+b} { print_created(this, a, b); } + Movable(const Movable &m) { value = m.value; print_copy_created(this); } + Movable(Movable &&m) { value = std::move(m.value); print_move_created(this); } + std::string get_value() const { return std::to_string(value); } + ~Movable() { print_destroyed(this); } +private: + int value; +}; + +class NCVirt { +public: + virtual NonCopyable get_noncopyable(int a, int b) { return NonCopyable(a, b); } + virtual Movable get_movable(int a, int b) = 0; + + std::string print_nc(int a, int b) { return get_noncopyable(a, b).get_value(); } + std::string print_movable(int a, int b) { return get_movable(a, b).get_value(); } +}; +class NCVirtTrampoline : public NCVirt { +#if !defined(__INTEL_COMPILER) + NonCopyable get_noncopyable(int a, int b) override { + PYBIND11_OVERLOAD(NonCopyable, NCVirt, get_noncopyable, a, b); + } +#endif + Movable get_movable(int a, int b) override { + PYBIND11_OVERLOAD_PURE(Movable, NCVirt, get_movable, a, b); + } +}; + +int runExampleVirt(ExampleVirt *ex, int value) { + return ex->run(value); +} + +bool runExampleVirtBool(ExampleVirt* ex) { + return ex->run_bool(); +} + +void runExampleVirtVirtual(ExampleVirt *ex) { + ex->pure_virtual(); +} + + +// Inheriting virtual methods. We do two versions here: the repeat-everything version and the +// templated trampoline versions mentioned in docs/advanced.rst. +// +// These base classes are exactly the same, but we technically need distinct +// classes for this example code because we need to be able to bind them +// properly (pybind11, sensibly, doesn't allow us to bind the same C++ class to +// multiple python classes). +class A_Repeat { +#define A_METHODS \ +public: \ + virtual int unlucky_number() = 0; \ + virtual std::string say_something(unsigned times) { \ + std::string s = ""; \ + for (unsigned i = 0; i < times; ++i) \ + s += "hi"; \ + return s; \ + } \ + std::string say_everything() { \ + return say_something(1) + " " + std::to_string(unlucky_number()); \ + } +A_METHODS +}; +class B_Repeat : public A_Repeat { +#define B_METHODS \ +public: \ + int unlucky_number() override { return 13; } \ + std::string say_something(unsigned times) override { \ + return "B says hi " + std::to_string(times) + " times"; \ + } \ + virtual double lucky_number() { return 7.0; } +B_METHODS +}; +class C_Repeat : public B_Repeat { +#define C_METHODS \ +public: \ + int unlucky_number() override { return 4444; } \ + double lucky_number() override { return 888; } +C_METHODS +}; +class D_Repeat : public C_Repeat { +#define D_METHODS // Nothing overridden. +D_METHODS +}; + +// Base classes for templated inheritance trampolines. Identical to the repeat-everything version: +class A_Tpl { A_METHODS }; +class B_Tpl : public A_Tpl { B_METHODS }; +class C_Tpl : public B_Tpl { C_METHODS }; +class D_Tpl : public C_Tpl { D_METHODS }; + + +// Inheritance approach 1: each trampoline gets every virtual method (11 in total) +class PyA_Repeat : public A_Repeat { +public: + using A_Repeat::A_Repeat; + int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, A_Repeat, unlucky_number, ); } + std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, A_Repeat, say_something, times); } +}; +class PyB_Repeat : public B_Repeat { +public: + using B_Repeat::B_Repeat; + int unlucky_number() override { PYBIND11_OVERLOAD(int, B_Repeat, unlucky_number, ); } + std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, B_Repeat, say_something, times); } + double lucky_number() override { PYBIND11_OVERLOAD(double, B_Repeat, lucky_number, ); } +}; +class PyC_Repeat : public C_Repeat { +public: + using C_Repeat::C_Repeat; + int unlucky_number() override { PYBIND11_OVERLOAD(int, C_Repeat, unlucky_number, ); } + std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, C_Repeat, say_something, times); } + double lucky_number() override { PYBIND11_OVERLOAD(double, C_Repeat, lucky_number, ); } +}; +class PyD_Repeat : public D_Repeat { +public: + using D_Repeat::D_Repeat; + int unlucky_number() override { PYBIND11_OVERLOAD(int, D_Repeat, unlucky_number, ); } + std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, D_Repeat, say_something, times); } + double lucky_number() override { PYBIND11_OVERLOAD(double, D_Repeat, lucky_number, ); } +}; + +// Inheritance approach 2: templated trampoline classes. +// +// Advantages: +// - we have only 2 (template) class and 4 method declarations (one per virtual method, plus one for +// any override of a pure virtual method), versus 4 classes and 6 methods (MI) or 4 classes and 11 +// methods (repeat). +// - Compared to MI, we also don't have to change the non-trampoline inheritance to virtual, and can +// properly inherit constructors. +// +// Disadvantage: +// - the compiler must still generate and compile 14 different methods (more, even, than the 11 +// required for the repeat approach) instead of the 6 required for MI. (If there was no pure +// method (or no pure method override), the number would drop down to the same 11 as the repeat +// approach). +template +class PyA_Tpl : public Base { +public: + using Base::Base; // Inherit constructors + int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, Base, unlucky_number, ); } + std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, Base, say_something, times); } +}; +template +class PyB_Tpl : public PyA_Tpl { +public: + using PyA_Tpl::PyA_Tpl; // Inherit constructors (via PyA_Tpl's inherited constructors) + int unlucky_number() override { PYBIND11_OVERLOAD(int, Base, unlucky_number, ); } + double lucky_number() override { PYBIND11_OVERLOAD(double, Base, lucky_number, ); } +}; +// Since C_Tpl and D_Tpl don't declare any new virtual methods, we don't actually need these (we can +// use PyB_Tpl and PyB_Tpl for the trampoline classes instead): +/* +template class PyC_Tpl : public PyB_Tpl { +public: + using PyB_Tpl::PyB_Tpl; +}; +template class PyD_Tpl : public PyC_Tpl { +public: + using PyC_Tpl::PyC_Tpl; +}; +*/ + + +void initialize_inherited_virtuals(py::module &m) { + // Method 1: repeat + py::class_(m, "A_Repeat") + .def(py::init<>()) + .def("unlucky_number", &A_Repeat::unlucky_number) + .def("say_something", &A_Repeat::say_something) + .def("say_everything", &A_Repeat::say_everything); + py::class_(m, "B_Repeat") + .def(py::init<>()) + .def("lucky_number", &B_Repeat::lucky_number); + py::class_(m, "C_Repeat") + .def(py::init<>()); + py::class_(m, "D_Repeat") + .def(py::init<>()); + + // Method 2: Templated trampolines + py::class_>(m, "A_Tpl") + .def(py::init<>()) + .def("unlucky_number", &A_Tpl::unlucky_number) + .def("say_something", &A_Tpl::say_something) + .def("say_everything", &A_Tpl::say_everything); + py::class_>(m, "B_Tpl") + .def(py::init<>()) + .def("lucky_number", &B_Tpl::lucky_number); + py::class_>(m, "C_Tpl") + .def(py::init<>()); + py::class_>(m, "D_Tpl") + .def(py::init<>()); + +}; + + +test_initializer virtual_functions([](py::module &m) { + /* Important: indicate the trampoline class PyExampleVirt using the third + argument to py::class_. The second argument with the unique pointer + is simply the default holder type used by pybind11. */ + py::class_(m, "ExampleVirt") + .def(py::init()) + /* Reference original class in function definitions */ + .def("run", &ExampleVirt::run) + .def("run_bool", &ExampleVirt::run_bool) + .def("pure_virtual", &ExampleVirt::pure_virtual); + + py::class_(m, "NonCopyable") + .def(py::init()); + + py::class_(m, "Movable") + .def(py::init()); + +#if !defined(__INTEL_COMPILER) + py::class_(m, "NCVirt") + .def(py::init<>()) + .def("get_noncopyable", &NCVirt::get_noncopyable) + .def("get_movable", &NCVirt::get_movable) + .def("print_nc", &NCVirt::print_nc) + .def("print_movable", &NCVirt::print_movable); +#endif + + m.def("runExampleVirt", &runExampleVirt); + m.def("runExampleVirtBool", &runExampleVirtBool); + m.def("runExampleVirtVirtual", &runExampleVirtVirtual); + + m.def("cstats_debug", &ConstructorStats::get); + initialize_inherited_virtuals(m); +}); diff --git a/resources/pybind11/tests/test_virtual_functions.py b/resources/pybind11/tests/test_virtual_functions.py new file mode 100755 index 0000000..eeecc23 --- /dev/null +++ b/resources/pybind11/tests/test_virtual_functions.py @@ -0,0 +1,254 @@ +import pytest +import pybind11_tests +from pybind11_tests import ConstructorStats + + +def test_override(capture, msg): + from pybind11_tests import (ExampleVirt, runExampleVirt, runExampleVirtVirtual, + runExampleVirtBool) + + class ExtendedExampleVirt(ExampleVirt): + def __init__(self, state): + super(ExtendedExampleVirt, self).__init__(state + 1) + self.data = "Hello world" + + def run(self, value): + print('ExtendedExampleVirt::run(%i), calling parent..' % value) + return super(ExtendedExampleVirt, self).run(value + 1) + + def run_bool(self): + print('ExtendedExampleVirt::run_bool()') + return False + + def get_string1(self): + return "override1" + + def pure_virtual(self): + print('ExtendedExampleVirt::pure_virtual(): %s' % self.data) + + class ExtendedExampleVirt2(ExtendedExampleVirt): + def __init__(self, state): + super(ExtendedExampleVirt2, self).__init__(state + 1) + + def get_string2(self): + return "override2" + + ex12 = ExampleVirt(10) + with capture: + assert runExampleVirt(ex12, 20) == 30 + assert capture == "Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2)" + + with pytest.raises(RuntimeError) as excinfo: + runExampleVirtVirtual(ex12) + assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"' + + ex12p = ExtendedExampleVirt(10) + with capture: + assert runExampleVirt(ex12p, 20) == 32 + assert capture == """ + ExtendedExampleVirt::run(20), calling parent.. + Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2) + """ + with capture: + assert runExampleVirtBool(ex12p) is False + assert capture == "ExtendedExampleVirt::run_bool()" + with capture: + runExampleVirtVirtual(ex12p) + assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world" + + ex12p2 = ExtendedExampleVirt2(15) + with capture: + assert runExampleVirt(ex12p2, 50) == 68 + assert capture == """ + ExtendedExampleVirt::run(50), calling parent.. + Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2) + """ + + cstats = ConstructorStats.get(ExampleVirt) + assert cstats.alive() == 3 + del ex12, ex12p, ex12p2 + assert cstats.alive() == 0 + assert cstats.values() == ['10', '11', '17'] + assert cstats.copy_constructions == 0 + assert cstats.move_constructions >= 0 + + +def test_inheriting_repeat(): + from pybind11_tests import A_Repeat, B_Repeat, C_Repeat, D_Repeat, A_Tpl, B_Tpl, C_Tpl, D_Tpl + + class AR(A_Repeat): + def unlucky_number(self): + return 99 + + class AT(A_Tpl): + def unlucky_number(self): + return 999 + + obj = AR() + assert obj.say_something(3) == "hihihi" + assert obj.unlucky_number() == 99 + assert obj.say_everything() == "hi 99" + + obj = AT() + assert obj.say_something(3) == "hihihi" + assert obj.unlucky_number() == 999 + assert obj.say_everything() == "hi 999" + + for obj in [B_Repeat(), B_Tpl()]: + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 13 + assert obj.lucky_number() == 7.0 + assert obj.say_everything() == "B says hi 1 times 13" + + for obj in [C_Repeat(), C_Tpl()]: + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 888.0 + assert obj.say_everything() == "B says hi 1 times 4444" + + class CR(C_Repeat): + def lucky_number(self): + return C_Repeat.lucky_number(self) + 1.25 + + obj = CR() + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 889.25 + assert obj.say_everything() == "B says hi 1 times 4444" + + class CT(C_Tpl): + pass + + obj = CT() + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 888.0 + assert obj.say_everything() == "B says hi 1 times 4444" + + class CCR(CR): + def lucky_number(self): + return CR.lucky_number(self) * 10 + + obj = CCR() + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 8892.5 + assert obj.say_everything() == "B says hi 1 times 4444" + + class CCT(CT): + def lucky_number(self): + return CT.lucky_number(self) * 1000 + + obj = CCT() + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 888000.0 + assert obj.say_everything() == "B says hi 1 times 4444" + + class DR(D_Repeat): + def unlucky_number(self): + return 123 + + def lucky_number(self): + return 42.0 + + for obj in [D_Repeat(), D_Tpl()]: + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 888.0 + assert obj.say_everything() == "B says hi 1 times 4444" + + obj = DR() + assert obj.say_something(3) == "B says hi 3 times" + assert obj.unlucky_number() == 123 + assert obj.lucky_number() == 42.0 + assert obj.say_everything() == "B says hi 1 times 123" + + class DT(D_Tpl): + def say_something(self, times): + return "DT says:" + (' quack' * times) + + def unlucky_number(self): + return 1234 + + def lucky_number(self): + return -4.25 + + obj = DT() + assert obj.say_something(3) == "DT says: quack quack quack" + assert obj.unlucky_number() == 1234 + assert obj.lucky_number() == -4.25 + assert obj.say_everything() == "DT says: quack 1234" + + class DT2(DT): + def say_something(self, times): + return "DT2: " + ('QUACK' * times) + + def unlucky_number(self): + return -3 + + class BT(B_Tpl): + def say_something(self, times): + return "BT" * times + + def unlucky_number(self): + return -7 + + def lucky_number(self): + return -1.375 + + obj = BT() + assert obj.say_something(3) == "BTBTBT" + assert obj.unlucky_number() == -7 + assert obj.lucky_number() == -1.375 + assert obj.say_everything() == "BT -7" + + +@pytest.mark.skipif(not hasattr(pybind11_tests, 'NCVirt'), + reason="NCVirt test broken on ICPC") +def test_move_support(): + from pybind11_tests import NCVirt, NonCopyable, Movable + + class NCVirtExt(NCVirt): + def get_noncopyable(self, a, b): + # Constructs and returns a new instance: + nc = NonCopyable(a * a, b * b) + return nc + + def get_movable(self, a, b): + # Return a referenced copy + self.movable = Movable(a, b) + return self.movable + + class NCVirtExt2(NCVirt): + def get_noncopyable(self, a, b): + # Keep a reference: this is going to throw an exception + self.nc = NonCopyable(a, b) + return self.nc + + def get_movable(self, a, b): + # Return a new instance without storing it + return Movable(a, b) + + ncv1 = NCVirtExt() + assert ncv1.print_nc(2, 3) == "36" + assert ncv1.print_movable(4, 5) == "9" + ncv2 = NCVirtExt2() + assert ncv2.print_movable(7, 7) == "14" + # Don't check the exception message here because it differs under debug/non-debug mode + with pytest.raises(RuntimeError): + ncv2.print_nc(9, 9) + + nc_stats = ConstructorStats.get(NonCopyable) + mv_stats = ConstructorStats.get(Movable) + assert nc_stats.alive() == 1 + assert mv_stats.alive() == 1 + del ncv1, ncv2 + assert nc_stats.alive() == 0 + assert mv_stats.alive() == 0 + assert nc_stats.values() == ['4', '9', '9', '9'] + assert mv_stats.values() == ['4', '5', '7', '7'] + assert nc_stats.copy_constructions == 0 + assert mv_stats.copy_constructions == 1 + assert nc_stats.move_constructions >= 0 + assert mv_stats.move_constructions >= 0 diff --git a/resources/pybind11/tools/FindEigen3.cmake b/resources/pybind11/tools/FindEigen3.cmake new file mode 100755 index 0000000..9c546a0 --- /dev/null +++ b/resources/pybind11/tools/FindEigen3.cmake @@ -0,0 +1,81 @@ +# - Try to find Eigen3 lib +# +# This module supports requiring a minimum version, e.g. you can do +# find_package(Eigen3 3.1.2) +# to require version 3.1.2 or newer of Eigen3. +# +# Once done this will define +# +# EIGEN3_FOUND - system has eigen lib with correct version +# EIGEN3_INCLUDE_DIR - the eigen include directory +# EIGEN3_VERSION - eigen version + +# Copyright (c) 2006, 2007 Montel Laurent, +# Copyright (c) 2008, 2009 Gael Guennebaud, +# Copyright (c) 2009 Benoit Jacob +# Redistribution and use is allowed according to the terms of the 2-clause BSD license. + +if(NOT Eigen3_FIND_VERSION) + if(NOT Eigen3_FIND_VERSION_MAJOR) + set(Eigen3_FIND_VERSION_MAJOR 2) + endif(NOT Eigen3_FIND_VERSION_MAJOR) + if(NOT Eigen3_FIND_VERSION_MINOR) + set(Eigen3_FIND_VERSION_MINOR 91) + endif(NOT Eigen3_FIND_VERSION_MINOR) + if(NOT Eigen3_FIND_VERSION_PATCH) + set(Eigen3_FIND_VERSION_PATCH 0) + endif(NOT Eigen3_FIND_VERSION_PATCH) + + set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") +endif(NOT Eigen3_FIND_VERSION) + +macro(_eigen3_check_version) + file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) + + string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}") + set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}") + set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}") + set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") + + set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) + if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK FALSE) + else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK TRUE) + endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + + if(NOT EIGEN3_VERSION_OK) + + message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, " + "but at least version ${Eigen3_FIND_VERSION} is required") + endif(NOT EIGEN3_VERSION_OK) +endmacro(_eigen3_check_version) + +if (EIGEN3_INCLUDE_DIR) + + # in cache already + _eigen3_check_version() + set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) + +else (EIGEN3_INCLUDE_DIR) + + find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library + PATHS + ${CMAKE_INSTALL_PREFIX}/include + ${KDE4_INCLUDE_DIR} + PATH_SUFFIXES eigen3 eigen + ) + + if(EIGEN3_INCLUDE_DIR) + _eigen3_check_version() + endif(EIGEN3_INCLUDE_DIR) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK) + + mark_as_advanced(EIGEN3_INCLUDE_DIR) + +endif(EIGEN3_INCLUDE_DIR) + diff --git a/resources/pybind11/tools/FindPythonLibsNew.cmake b/resources/pybind11/tools/FindPythonLibsNew.cmake new file mode 100755 index 0000000..dc44a9d --- /dev/null +++ b/resources/pybind11/tools/FindPythonLibsNew.cmake @@ -0,0 +1,194 @@ +# - 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_MODULE_EXTENSION - lib extension, e.g. '.so' or '.pyd' +# PYTHON_MODULE_PREFIX - lib name prefix: usually an empty string +# PYTHON_SITE_PACKAGES - path to installation site-packages +# PYTHON_IS_DEBUG - whether the Python interpreter is a debug build +# +# Thanks to talljimbo for the patch adding the 'LDVERSION' config +# variable usage. + +#============================================================================= +# 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. +#============================================================================= + +if(PYTHONLIBS_FOUND) + return() +endif() + +# Use the Python interpreter to find the libs. +if(PythonLibsNew_FIND_REQUIRED) + find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} REQUIRED) +else() + find_package(PythonInterp ${PythonLibsNew_FIND_VERSION}) +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. +# +# The library suffix is from the config var LDVERSION sometimes, otherwise +# VERSION. VERSION will typically be like "2.7" on unix, and "27" on windows. +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(sys.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')); +print(s.get_config_var('LDVERSION') or s.get_config_var('VERSION')); +print(s.get_config_var('LIBDIR') or ''); +print(s.get_config_var('MULTIARCH') or ''); +" + RESULT_VARIABLE _PYTHON_SUCCESS + OUTPUT_VARIABLE _PYTHON_VALUES + ERROR_VARIABLE _PYTHON_ERROR_VALUE) + +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) +list(GET _PYTHON_VALUES 7 PYTHON_LIBRARY_SUFFIX) +list(GET _PYTHON_VALUES 8 PYTHON_LIBDIR) +list(GET _PYTHON_VALUES 9 PYTHON_MULTIARCH) + +# Make sure the Python has the same pointer-size as the chosen compiler +# Skip if CMAKE_SIZEOF_VOID_P is not defined +if(CMAKE_SIZEOF_VOID_P AND (NOT "${PYTHON_SIZEOF_VOID_P}" STREQUAL "${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}) + +if(CMAKE_HOST_WIN32) + set(PYTHON_LIBRARY + "${PYTHON_PREFIX}/libs/Python${PYTHON_LIBRARY_SUFFIX}.lib") + + # when run in a venv, PYTHON_PREFIX points to it. But the libraries remain in the + # original python installation. They may be found relative to PYTHON_INCLUDE_DIR. + if(NOT EXISTS "${PYTHON_LIBRARY}") + get_filename_component(_PYTHON_ROOT ${PYTHON_INCLUDE_DIR} DIRECTORY) + set(PYTHON_LIBRARY + "${_PYTHON_ROOT}/libs/Python${PYTHON_LIBRARY_SUFFIX}.lib") + endif() + + # raise an error if the python libs are still not found. + if(NOT EXISTS "${PYTHON_LIBRARY}") + message(FATAL_ERROR "Python libraries not found") + endif() + +else() + if(PYTHON_MULTIARCH) + set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}/${PYTHON_MULTIARCH}" "${PYTHON_LIBDIR}") + else() + set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}") + endif() + #message(STATUS "Searching for Python libs in ${_PYTHON_LIBS_SEARCH}") + # 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_LIBRARY_SUFFIX}" + PATHS ${_PYTHON_LIBS_SEARCH} + NO_DEFAULT_PATH) + + # If all else fails, just set the name/version and let the linker figure out the path. + if(NOT PYTHON_LIBRARY) + set(PYTHON_LIBRARY python${PYTHON_LIBRARY_SUFFIX}) + endif() +endif() + +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}") + +find_package_message(PYTHON + "Found PythonLibs: ${PYTHON_LIBRARY}" + "${PYTHON_EXECUTABLE}${PYTHON_VERSION}") + +set(PYTHONLIBS_FOUND TRUE) diff --git a/resources/pybind11/tools/check-style.sh b/resources/pybind11/tools/check-style.sh new file mode 100755 index 0000000..44f4a0c --- /dev/null +++ b/resources/pybind11/tools/check-style.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# +# Script to check include/test code for common pybind11 code style errors. +# +# This script currently checks for +# +# 1. use of tabs instead of spaces +# 2. trailing spaces +# 3. missing space between keyword and parenthesis, e.g.: for(, if(, while( +# 4. opening brace on its own line. It should always be on the same line as the +# if/while/for/do statment. +# 5. Missing space between right parenthesis and brace, e.g. 'for (...){' +# +# Invoke as: tools/check-style.sh +# + +errors=0 +IFS=$'\n' +found= +# The mt=41 sets a red background for matched tabs: +exec 3< <(GREP_COLORS='mt=41' grep $'\t' include/ tests/*.{cpp,py,h} docs/*.rst -rn --color=always) +while read -u 3 f; do + if [ -z "$found" ]; then + echo -e '\e[31m\e[01mError: found tabs instead of spaces in the following files:\e[0m' + found=1 + errors=1 + fi + + echo " $f" +done + +found= +# The mt=41 sets a red background for matched trailing spaces +exec 3< <(GREP_COLORS='mt=41' grep '\s\+$' include/ tests/*.{cpp,py,h} docs/*.rst -rn --color=always) +while read -u 3 f; do + if [ -z "$found" ]; then + echo -e '\e[31m\e[01mError: found trailing spaces in the following files:\e[0m' + found=1 + errors=1 + fi + + echo " $f" +done + +found= +exec 3< <(GREP_COLORS='mt=41' grep '^\s*{\s*$' include/ docs/*.rst -rn --color=always) +while read -u 3 f; do + if [ -z "$found" ]; then + echo -e '\e[31m\e[01mError: braces should occur on the same line as the if/while/.. statement. Found issues in the following files: \e[0m' + found=1 + errors=1 + fi + + echo " $f" +done + +found= +exec 3< <(grep '\<\(if\|for\|while\)(\|){' include/ tests/*.{cpp,py,h} -rn --color=always) +while read -u 3 line; do + if [ -z "$found" ]; then + echo -e '\e[31m\e[01mError: found the following coding style problems:\e[0m' + found=1 + errors=1 + fi + + echo " $line" +done + +exit $errors diff --git a/resources/pybind11/tools/libsize.py b/resources/pybind11/tools/libsize.py new file mode 100755 index 0000000..5dcb8b0 --- /dev/null +++ b/resources/pybind11/tools/libsize.py @@ -0,0 +1,38 @@ +from __future__ import print_function, division +import os +import sys + +# Internal build script for generating debugging test .so size. +# Usage: +# python libsize.py file.so save.txt -- displays the size of file.so and, if save.txt exists, compares it to the +# size in it, then overwrites save.txt with the new size for future runs. + +if len(sys.argv) != 3: + sys.exit("Invalid arguments: usage: python libsize.py file.so save.txt") + +lib = sys.argv[1] +save = sys.argv[2] + +if not os.path.exists(lib): + sys.exit("Error: requested file ({}) does not exist".format(lib)) + +libsize = os.path.getsize(lib) + +print("------", os.path.basename(lib), "file size:", libsize, end='') + +if os.path.exists(save): + with open(save) as sf: + oldsize = int(sf.readline()) + + if oldsize > 0: + change = libsize - oldsize + if change == 0: + print(" (no change)") + else: + print(" (change of {:+} bytes = {:+.2%})".format(change, change / oldsize)) +else: + print() + +with open(save, 'w') as sf: + sf.write(str(libsize)) + diff --git a/resources/pybind11/tools/mkdoc.py b/resources/pybind11/tools/mkdoc.py new file mode 100755 index 0000000..400fb05 --- /dev/null +++ b/resources/pybind11/tools/mkdoc.py @@ -0,0 +1,309 @@ +#!/usr/bin/env python3 +# +# Syntax: mkdoc.py [-I ..] [.. a list of header files ..] +# +# Extract documentation from C++ header files to use it in Python bindings +# + +import os +import sys +import platform +import re +import textwrap + +from clang import cindex +from clang.cindex import CursorKind +from collections import OrderedDict +from threading import Thread, Semaphore +from multiprocessing import cpu_count + +RECURSE_LIST = [ + CursorKind.TRANSLATION_UNIT, + CursorKind.NAMESPACE, + CursorKind.CLASS_DECL, + CursorKind.STRUCT_DECL, + CursorKind.ENUM_DECL, + CursorKind.CLASS_TEMPLATE +] + +PRINT_LIST = [ + CursorKind.CLASS_DECL, + CursorKind.STRUCT_DECL, + CursorKind.ENUM_DECL, + CursorKind.ENUM_CONSTANT_DECL, + CursorKind.CLASS_TEMPLATE, + CursorKind.FUNCTION_DECL, + CursorKind.FUNCTION_TEMPLATE, + CursorKind.CONVERSION_FUNCTION, + CursorKind.CXX_METHOD, + CursorKind.CONSTRUCTOR, + CursorKind.FIELD_DECL +] + +CPP_OPERATORS = { + '<=': 'le', '>=': 'ge', '==': 'eq', '!=': 'ne', '[]': 'array', + '+=': 'iadd', '-=': 'isub', '*=': 'imul', '/=': 'idiv', '%=': + 'imod', '&=': 'iand', '|=': 'ior', '^=': 'ixor', '<<=': 'ilshift', + '>>=': 'irshift', '++': 'inc', '--': 'dec', '<<': 'lshift', '>>': + 'rshift', '&&': 'land', '||': 'lor', '!': 'lnot', '~': 'bnot', + '&': 'band', '|': 'bor', '+': 'add', '-': 'sub', '*': 'mul', '/': + 'div', '%': 'mod', '<': 'lt', '>': 'gt', '=': 'assign', '()': 'call' +} + +CPP_OPERATORS = OrderedDict( + sorted(CPP_OPERATORS.items(), key=lambda t: -len(t[0]))) + +job_count = cpu_count() +job_semaphore = Semaphore(job_count) + +registered_names = dict() + + +def d(s): + return s.decode('utf8') + + +def sanitize_name(name): + global registered_names + name = re.sub(r'type-parameter-0-([0-9]+)', r'T\1', name) + for k, v in CPP_OPERATORS.items(): + name = name.replace('operator%s' % k, 'operator_%s' % v) + name = re.sub('<.*>', '', name) + name = ''.join([ch if ch.isalnum() else '_' for ch in name]) + name = re.sub('_$', '', re.sub('_+', '_', name)) + if name in registered_names: + registered_names[name] += 1 + name += '_' + str(registered_names[name]) + else: + registered_names[name] = 1 + return '__doc_' + name + + +def process_comment(comment): + result = '' + + # Remove C++ comment syntax + leading_spaces = float('inf') + for s in comment.expandtabs(tabsize=4).splitlines(): + s = s.strip() + if s.startswith('/*'): + s = s[2:].lstrip('*') + elif s.endswith('*/'): + s = s[:-2].rstrip('*') + elif s.startswith('///'): + s = s[3:] + if s.startswith('*'): + s = s[1:] + if len(s) > 0: + leading_spaces = min(leading_spaces, len(s) - len(s.lstrip())) + result += s + '\n' + + if leading_spaces != float('inf'): + result2 = "" + for s in result.splitlines(): + result2 += s[leading_spaces:] + '\n' + result = result2 + + # Doxygen tags + cpp_group = '([\w:]+)' + param_group = '([\[\w:\]]+)' + + s = result + s = re.sub(r'\\c\s+%s' % cpp_group, r'``\1``', s) + s = re.sub(r'\\a\s+%s' % cpp_group, r'*\1*', s) + s = re.sub(r'\\e\s+%s' % cpp_group, r'*\1*', s) + s = re.sub(r'\\em\s+%s' % cpp_group, r'*\1*', s) + s = re.sub(r'\\b\s+%s' % cpp_group, r'**\1**', s) + s = re.sub(r'\\ingroup\s+%s' % cpp_group, r'', s) + s = re.sub(r'\\param%s?\s+%s' % (param_group, cpp_group), + r'\n\n$Parameter ``\2``:\n\n', s) + s = re.sub(r'\\tparam%s?\s+%s' % (param_group, cpp_group), + r'\n\n$Template parameter ``\2``:\n\n', s) + + for in_, out_ in { + 'return': 'Returns', + 'author': 'Author', + 'authors': 'Authors', + 'copyright': 'Copyright', + 'date': 'Date', + 'remark': 'Remark', + 'sa': 'See also', + 'see': 'See also', + 'extends': 'Extends', + 'throw': 'Throws', + 'throws': 'Throws' + }.items(): + s = re.sub(r'\\%s\s*' % in_, r'\n\n$%s:\n\n' % out_, s) + + s = re.sub(r'\\details\s*', r'\n\n', s) + s = re.sub(r'\\brief\s*', r'', s) + s = re.sub(r'\\short\s*', r'', s) + s = re.sub(r'\\ref\s*', r'', s) + + s = re.sub(r'\\code\s?(.*?)\s?\\endcode', + r"```\n\1\n```\n", s, flags=re.DOTALL) + + # HTML/TeX tags + s = re.sub(r'(.*?)', r'``\1``', s, flags=re.DOTALL) + s = re.sub(r'
(.*?)
', r"```\n\1\n```\n", s, flags=re.DOTALL) + s = re.sub(r'(.*?)', r'*\1*', s, flags=re.DOTALL) + s = re.sub(r'(.*?)', r'**\1**', s, flags=re.DOTALL) + s = re.sub(r'\\f\$(.*?)\\f\$', r'$\1$', s, flags=re.DOTALL) + s = re.sub(r'
  • ', r'\n\n* ', s) + s = re.sub(r'', r'', s) + s = re.sub(r'
  • ', r'\n\n', s) + + s = s.replace('``true``', '``True``') + s = s.replace('``false``', '``False``') + + # Re-flow text + wrapper = textwrap.TextWrapper() + wrapper.expand_tabs = True + wrapper.replace_whitespace = True + wrapper.drop_whitespace = True + wrapper.width = 70 + wrapper.initial_indent = wrapper.subsequent_indent = '' + + result = '' + in_code_segment = False + for x in re.split(r'(```)', s): + if x == '```': + if not in_code_segment: + result += '```\n' + else: + result += '\n```\n\n' + in_code_segment = not in_code_segment + elif in_code_segment: + result += x.strip() + else: + for y in re.split(r'(?: *\n *){2,}', x): + wrapped = wrapper.fill(re.sub(r'\s+', ' ', y).strip()) + if len(wrapped) > 0 and wrapped[0] == '$': + result += wrapped[1:] + '\n' + wrapper.initial_indent = \ + wrapper.subsequent_indent = ' ' * 4 + else: + if len(wrapped) > 0: + result += wrapped + '\n\n' + wrapper.initial_indent = wrapper.subsequent_indent = '' + return result.rstrip().lstrip('\n') + + +def extract(filename, node, prefix, output): + num_extracted = 0 + if not (node.location.file is None or + os.path.samefile(d(node.location.file.name), filename)): + return 0 + if node.kind in RECURSE_LIST: + sub_prefix = prefix + if node.kind != CursorKind.TRANSLATION_UNIT: + if len(sub_prefix) > 0: + sub_prefix += '_' + sub_prefix += d(node.spelling) + for i in node.get_children(): + num_extracted += extract(filename, i, sub_prefix, output) + if num_extracted == 0: + return 0 + if node.kind in PRINT_LIST: + comment = d(node.raw_comment) if node.raw_comment is not None else '' + comment = process_comment(comment) + sub_prefix = prefix + if len(sub_prefix) > 0: + sub_prefix += '_' + if len(node.spelling) > 0: + name = sanitize_name(sub_prefix + d(node.spelling)) + output.append('\nstatic const char *%s =%sR"doc(%s)doc";' % + (name, '\n' if '\n' in comment else ' ', comment)) + num_extracted += 1 + return num_extracted + + +class ExtractionThread(Thread): + def __init__(self, filename, parameters, output): + Thread.__init__(self) + self.filename = filename + self.parameters = parameters + self.output = output + job_semaphore.acquire() + + def run(self): + print('Processing "%s" ..' % self.filename, file=sys.stderr) + try: + index = cindex.Index( + cindex.conf.lib.clang_createIndex(False, True)) + tu = index.parse(self.filename, self.parameters) + extract(self.filename, tu.cursor, '', self.output) + finally: + job_semaphore.release() + +if __name__ == '__main__': + parameters = ['-x', 'c++', '-std=c++11'] + filenames = [] + + if platform.system() == 'Darwin': + dev_path = '/Applications/Xcode.app/Contents/Developer/' + lib_dir = dev_path + 'Toolchains/XcodeDefault.xctoolchain/usr/lib/' + sdk_dir = dev_path + 'Platforms/MacOSX.platform/Developer/SDKs' + libclang = lib_dir + 'libclang.dylib' + + if os.path.exists(libclang): + cindex.Config.set_library_path(os.path.dirname(libclang)) + + if os.path.exists(sdk_dir): + sysroot_dir = os.path.join(sdk_dir, next(os.walk(sdk_dir))[1][0]) + parameters.append('-isysroot') + parameters.append(sysroot_dir) + + for item in sys.argv[1:]: + if item.startswith('-'): + parameters.append(item) + else: + filenames.append(item) + + if len(filenames) == 0: + print('Syntax: %s [.. a list of header files ..]' % sys.argv[0]) + exit(-1) + + print('''/* + This file contains docstrings for the Python bindings. + Do not edit! These were automatically extracted by mkdoc.py + */ + +#define __EXPAND(x) x +#define __COUNT(_1, _2, _3, _4, _5, _6, _7, COUNT, ...) COUNT +#define __VA_SIZE(...) __EXPAND(__COUNT(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1)) +#define __CAT1(a, b) a ## b +#define __CAT2(a, b) __CAT1(a, b) +#define __DOC1(n1) __doc_##n1 +#define __DOC2(n1, n2) __doc_##n1##_##n2 +#define __DOC3(n1, n2, n3) __doc_##n1##_##n2##_##n3 +#define __DOC4(n1, n2, n3, n4) __doc_##n1##_##n2##_##n3##_##n4 +#define __DOC5(n1, n2, n3, n4, n5) __doc_##n1##_##n2##_##n3##_##n4##_##n5 +#define __DOC6(n1, n2, n3, n4, n5, n6) __doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6 +#define __DOC7(n1, n2, n3, n4, n5, n6, n7) __doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6##_##n7 +#define DOC(...) __EXPAND(__EXPAND(__CAT2(__DOC, __VA_SIZE(__VA_ARGS__)))(__VA_ARGS__)) + +#if defined(__GNUG__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif +''') + + output = [] + for filename in filenames: + thr = ExtractionThread(filename, parameters, output) + thr.start() + + print('Waiting for jobs to finish ..', file=sys.stderr) + for i in range(job_count): + job_semaphore.acquire() + + output.sort() + for l in output: + print(l) + + print(''' +#if defined(__GNUG__) +#pragma GCC diagnostic pop +#endif +''') diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..3dbd08a --- /dev/null +++ b/setup.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +import os +import re +import sys +import platform +import subprocess + +from setuptools import setup, Extension +from setuptools.command.build_ext import build_ext +from distutils.version import LooseVersion + + +class CMakeExtension(Extension): + def __init__(self, name, sourcedir=''): + Extension.__init__(self, name, sources=[]) + self.sourcedir = os.path.abspath(sourcedir) + + +class CMakeBuild(build_ext): + + user_options = build_ext.user_options + [ + ('storm-dir', None, 'Path to storm root (binary) location') + ] + + def run(self): + try: + out = subprocess.check_output(['cmake', '--version']) + except OSError: + raise RuntimeError("CMake must be installed to build the following extensions: " + + ", ".join(e.name for e in self.extensions)) + + for ext in self.extensions: + self.build_extension(ext) + + + def initialize_options(self): + build_ext.initialize_options(self) + self.storm_dir = None + + def finalize_options(self): + build_ext.finalize_options(self) + + + def build_extension(self, ext): + extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name))) + cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir, + '-DPYTHON_EXECUTABLE=' + sys.executable] + + cfg = 'Debug' if self.debug else 'Release' + build_args = ['--config', cfg] + + + cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg] + build_args += ['--', '-j2'] + if self.storm_dir: + cmake_args += ['-Dstorm_DIR=' + self.storm_dir] + + env = os.environ.copy() + env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(env.get('CXXFLAGS', ''), + self.distribution.get_version()) + if not os.path.exists(self.build_temp): + os.makedirs(self.build_temp) + subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=self.build_temp, env=env) + try: + subprocess.check_call(['cmake', '--build', '.', '--target', ext.name] + build_args, cwd=self.build_temp) + except subprocess.CalledProcessError as e: + if e.output: + raise RuntimeError("CMake build returned with an error: " + e.output) + + print(e.stdout) + +setup( + name="stormpy", + version="0.9", + author="M. Volk", + author_email="matthias.volk@cs.rwth-aachen.de", + maintainer="S. Junges", + maintainer_email="sebastian.junges@cs.rwth-aachen.de", + url="http://moves.rwth-aachen.de", + description="stormpy - Python Bindings for Storm", + packages=['stormpy', 'stormpy.info', 'stormpy.expressions', 'stormpy.logic', 'stormpy.storage'], + package_dir={'':'lib'}, + ext_package='stormpy', + ext_modules=[CMakeExtension('stormpy.core'), CMakeExtension('stormpy.info'),CMakeExtension('stormpy.expressions'), CMakeExtension('stormpy.logic'), CMakeExtension('stormpy.storage')], + cmdclass=dict(build_ext=CMakeBuild), + zip_safe=False +) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..9882d8a --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,56 @@ +# This is a CMake example for Python + +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src ${stormpy_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(${pybind11_incdir}) + +FILE(GLOB core_files "core/*.cpp") +#FILE(GLOB info_files "info/*.cpp") +#FILE(GLOB expressions_files "expressions/*.cpp") +FILE(GLOB storage_files "storage/*.cpp") +FILE(GLOB logic_files "logic/*.cpp") +ADD_LIBRARY(stormpy_core SHARED mod_core.cpp ${core_files}) +ADD_LIBRARY(stormpy_info SHARED mod_info.cpp) +ADD_LIBRARY(stormpy_expressions SHARED mod_expressions.cpp) +ADD_LIBRARY(stormpy_storage SHARED mod_storage.cpp ${storage_files}) +ADD_LIBRARY(stormpy_logic SHARED mod_logic.cpp ${logic_files}) + +SET_TARGET_PROPERTIES(stormpy_core PROPERTIES + OUTPUT_NAME core + PREFIX "" + SUFFIX ".so" + LIBRARY_OUTPUT_DIRECTORY ${STORMPY_OUTPUT_DIR}/ +) + +SET_TARGET_PROPERTIES(stormpy_info PROPERTIES + OUTPUT_NAME info + PREFIX "" + SUFFIX ".so" + LIBRARY_OUTPUT_DIRECTORY ${STORMPY_OUTPUT_DIR}/info +) + +SET_TARGET_PROPERTIES(stormpy_expressions PROPERTIES + OUTPUT_NAME expressions + PREFIX "" + SUFFIX ".so" + LIBRARY_OUTPUT_DIRECTORY ${STORMPY_OUTPUT_DIR}/expressions +) + +SET_TARGET_PROPERTIES(stormpy_storage PROPERTIES + OUTPUT_NAME storage + PREFIX "" + SUFFIX ".so" + LIBRARY_OUTPUT_DIRECTORY ${STORMPY_OUTPUT_DIR}/storage +) + +SET_TARGET_PROPERTIES(stormpy_logic PROPERTIES + OUTPUT_NAME logic + PREFIX "" + SUFFIX ".so" + LIBRARY_OUTPUT_DIRECTORY ${STORMPY_OUTPUT_DIR}/logic +) + +TARGET_LINK_LIBRARIES(stormpy_core storm ${PYTHON_LIBRARIES}) +TARGET_LINK_LIBRARIES(stormpy_info storm ${PYTHON_LIBRARIES}) +TARGET_LINK_LIBRARIES(stormpy_expressions storm ${PYTHON_LIBRARIES}) +TARGET_LINK_LIBRARIES(stormpy_storage storm ${PYTHON_LIBRARIES}) +TARGET_LINK_LIBRARIES(stormpy_logic storm ${PYTHON_LIBRARIES}) diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..e81b417 --- /dev/null +++ b/src/common.h @@ -0,0 +1,127 @@ +/* + * common.h + * + * Created on: 15 Apr 2016 + * Author: hbruintjes + */ + +#pragma once + +#include +#include +#include +#include + +namespace py = pybind11; + +#if PY_MAJOR_VERSION >= 3 +#define PY_DIV "__truediv__" +#define PY_RDIV "__rtruediv__" +#else +#define PY_DIV "__div__" +#define PY_RDIV "__rdiv__" +#endif + +PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr) +PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr) + +namespace pybind11 { +namespace detail { +/** + * Dummy type caster for handle, so functions can return pybind11 handles directly + */ +/*template <> class type_caster { +public: + bool load(handle src, bool) { + value = handle(src).inc_ref(); + return true; + } + + static handle cast(handle src, return_value_policy policy, handle parent) { + switch(policy) { + case return_value_policy::automatic: + case return_value_policy::copy: + case return_value_policy::take_ownership: + return handle(src); + case return_value_policy::reference: + return handle(src).inc_ref(); + case return_value_policy::reference_internal: + parent.inc_ref(); + return handle(src); + } + return handle(src); + } + PYBIND11_TYPE_CASTER(handle, _("handle")); +};*/ +/* +template struct tuple_caster { + typedef TupleType type; + template + using type_conv = type_caster::type>; + + bool load(handle src, bool convert) { + pybind11::tuple tup(src, true); + if (!tup.check()) + return false; + + return loadItem<0, Keys...>(tup, convert); + } + + static handle cast(const type &src, return_value_policy policy, handle parent) { + pybind11::tuple tup(sizeof...(Keys)); + if (!castItem<0, Keys...>(tup, src, policy, parent)) { + return handle(); + } + + return tup.release(); + } + +private: + template + bool loadItem(pybind11::tuple& tup, bool convert) { + type_conv conv; + if (!conv.load(tup[N], convert)) + return false; + std::get(value) = static_cast(conv); + return loadItem(tup, convert); + } + + template + bool loadItem(pybind11::tuple& tup, bool convert) { + type_conv conv; + if (!conv.load(tup[N], convert)) + return false; + std::get(value) = static_cast(conv); + return true; + } + + template + static bool castItem(pybind11::tuple& tup, const type &src, return_value_policy policy, handle parent) { + auto obj = type_conv::cast(std::get(src), policy, parent); + object value_ = object(obj, false); + if (!obj) { + return false; + } + return castItem(tup, src, policy, parent); + } + + template + static bool castItem(pybind11::tuple& tu, const type &src, return_value_policy policy, handle parent) { + auto obj = type_conv::cast(std::get(src), policy, parent); + object value_ = object(obj, false); + if (!obj) { + return false; + } + return true; + } +}; + +template struct type_caster> + : tuple_caster, Types...> { }; + +template struct type_caster> + : tuple_caster, Type1, Type2> { }; +*/ + +} +} diff --git a/src/core/bisimulation.cpp b/src/core/bisimulation.cpp new file mode 100644 index 0000000..3eafc80 --- /dev/null +++ b/src/core/bisimulation.cpp @@ -0,0 +1,22 @@ +#include "bisimulation.h" + +// Thin wrapper for bisimulation +template +std::shared_ptr> performBisimulation(std::shared_ptr> const& model, std::shared_ptr const& formula, storm::storage::BisimulationType bisimulationType) { + return storm::performBisimulationMinimization>(model, formula, bisimulationType); +} + +// Define python bindings +void define_bisimulation(py::module& m) { + + // Bisimulation + m.def("_perform_bisimulation", &performBisimulation, "Perform bisimulation", py::arg("model"), py::arg("formula"), py::arg("bisimulation_type")); + m.def("_perform_parametric_bisimulation", &performBisimulation, "Perform bisimulation on parametric model", py::arg("model"), py::arg("formula"), py::arg("bisimulation_type")); + + // BisimulationType + py::enum_(m, "BisimulationType", "Types of bisimulation") + .value("STRONG", storm::storage::BisimulationType::Strong) + .value("WEAK", storm::storage::BisimulationType::Weak) + ; + +} diff --git a/src/core/bisimulation.h b/src/core/bisimulation.h new file mode 100644 index 0000000..d444f40 --- /dev/null +++ b/src/core/bisimulation.h @@ -0,0 +1,8 @@ +#ifndef PYTHON_CORE_BISIMULATION_H_ +#define PYTHON_CORE_BISIMULATION_H_ + +#include "common.h" + +void define_bisimulation(py::module& m); + +#endif /* PYTHON_CORE_BISIMULATION_H_ */ diff --git a/src/core/common.h b/src/core/common.h new file mode 100644 index 0000000..e8466b2 --- /dev/null +++ b/src/core/common.h @@ -0,0 +1,3 @@ +#include "src/common.h" +#include "storm/utility/storm.h" +#include diff --git a/src/core/core.cpp b/src/core/core.cpp new file mode 100644 index 0000000..98d74dc --- /dev/null +++ b/src/core/core.cpp @@ -0,0 +1,49 @@ +#include "core.h" + +void define_core(py::module& m) { + // Init + m.def("set_up", [](std::string const& args) { + storm::utility::setUp(); + storm::settings::initializeAll("StoRM-Py", "stormpy"); + storm::settings::SettingsManager::manager().setFromString(args); + }, "Initialize Storm", py::arg("arguments")); +} + +void define_parse(py::module& m) { + // Parse formulas + m.def("parse_formulas", &storm::parseFormulasForExplicit, "Parse explicit formulas", py::arg("formula_string")); + m.def("parse_formulas_for_prism_program", &storm::parseFormulasForPrismProgram, "Parse formulas for prism program", py::arg("formula_string"), py::arg("prism_program")); + + // Pair + py::class_(m, "ModelFormulasPair", "Pair of model and formulas") + .def_property_readonly("model", [](storm::storage::ModelFormulasPair const& pair) { + return pair.model; + }, "The model") + .def_property_readonly("formulas", [](storm::storage::ModelFormulasPair const& pair) { + return pair.formulas; + }, "The formulas") + ; + + // Parse explicit models + m.def("parse_explicit_model", &storm::parser::AutoParser<>::parseModel, "Parse explicit model", py::arg("transition_file"), py::arg("labeling_file"), py::arg("state_reward_file") = "", py::arg("transition_reward_file") = "", py::arg("choice_labeling_file") = ""); +} + +// Thin wrapper for model building using one formula as argument +template +std::shared_ptr buildModel(storm::prism::Program const& program, std::shared_ptr const& formula) { + return storm::buildSymbolicModel(program, std::vector>(1,formula)); +} + +template +std::shared_ptr buildSparseModel(storm::prism::Program const& program, std::shared_ptr const& formula, bool onlyInitialStatesRelevant = false) { + return storm::buildSparseModel(program, std::vector>(1,formula), onlyInitialStatesRelevant); +} + +void define_build(py::module& m) { + // Build model + m.def("_build_model", &buildSparseModel, "Build the model", py::arg("program"), py::arg("formula"), py::arg("onlyInitialRelevant") = false); + m.def("_build_parametric_model", &buildSparseModel, "Build the parametric model", py::arg("program"), py::arg("formula"), py::arg("onlyInitialRelevant") = false); + m.def("build_model_from_prism_program", &storm::buildSparseModel, "Build the model", py::arg("program"), py::arg("formulas"), py::arg("onlyInitialRelevant") = false); + m.def("build_parametric_model_from_prism_program", &storm::buildSparseModel, "Build the parametric model", py::arg("program"), py::arg("formulas"), py::arg("onlyInitialRelevant") = false); + +} diff --git a/src/core/core.h b/src/core/core.h new file mode 100644 index 0000000..ee3b3be --- /dev/null +++ b/src/core/core.h @@ -0,0 +1,10 @@ +#ifndef PYTHON_CORE_CORE_H_ +#define PYTHON_CORE_CORE_H_ + +#include "common.h" + +void define_core(py::module& m); +void define_parse(py::module& m); +void define_build(py::module& m); + +#endif /* PYTHON_CORE_CORE_H_ */ diff --git a/src/core/input.cpp b/src/core/input.cpp new file mode 100644 index 0000000..8c9f915 --- /dev/null +++ b/src/core/input.cpp @@ -0,0 +1,34 @@ +#include "input.h" + +// Define python bindings +void define_input(py::module& m) { + + // Parse prism program + m.def("parse_prism_program", &storm::parseProgram, "Parse prism program", py::arg("path")); + + // PrismType + py::enum_(m, "PrismModelType", "Type of the prism model") + .value("DTMC", storm::prism::Program::ModelType::DTMC) + .value("CTMC", storm::prism::Program::ModelType::CTMC) + .value("MDP", storm::prism::Program::ModelType::MDP) + .value("CTMDP", storm::prism::Program::ModelType::CTMDP) + .value("MA", storm::prism::Program::ModelType::MA) + .value("UNDEFINED", storm::prism::Program::ModelType::UNDEFINED) + ; + + // PrismProgram + py::class_(m, "PrismProgram", "Prism program") + .def_property_readonly("nr_modules", &storm::prism::Program::getNumberOfModules, "Number of modules") + .def_property_readonly("model_type", &storm::prism::Program::getModelType, "Model type") + .def_property_readonly("has_undefined_constants", &storm::prism::Program::hasUndefinedConstants, "Flag if program has undefined constants") + ; + + // SymbolicModelDescription + py::class_(m, "SymbolicModelDescription", "Symbolic description of model") + .def(py::init(), "Construct from Prism program", py::arg("prism_program")) + .def_property_readonly("is_prism_program", &storm::storage::SymbolicModelDescription::isPrismProgram, "Flag if program is in Prism format") + ; + + // PrismProgram can be converted into SymbolicModelDescription + py::implicitly_convertible(); +} diff --git a/src/core/input.h b/src/core/input.h new file mode 100644 index 0000000..304dc9a --- /dev/null +++ b/src/core/input.h @@ -0,0 +1,8 @@ +#ifndef PYTHON_CORE_INPUT_H_ +#define PYTHON_CORE_INPUT_H_ + +#include "common.h" + +void define_input(py::module& m); + +#endif /* PYTHON_CORE_INPUT_H_ */ diff --git a/src/core/modelchecking.cpp b/src/core/modelchecking.cpp new file mode 100644 index 0000000..dd00a28 --- /dev/null +++ b/src/core/modelchecking.cpp @@ -0,0 +1,76 @@ +#include "modelchecking.h" + +// Class holding the model checking result +class PmcResult { + public: + storm::RationalFunction resultFunction; + std::unordered_set> constraintsWellFormed; + std::unordered_set> constraintsGraphPreserving; + + storm::RationalFunction getResultFunction() const { + return resultFunction; + } + + std::unordered_set> getConstraintsWellFormed() const { + return constraintsWellFormed; + } + + std::unordered_set> getConstraintsGraphPreserving() const { + return constraintsGraphPreserving; + } + + std::string toString() { + std::stringstream stream; + stream << resultFunction << std::endl; + stream << "Well formed constraints:" << std::endl; + for (auto constraint : constraintsWellFormed) { + stream << constraint << std::endl; + } + stream << "Graph preserving constraints:" << std::endl; + for (auto constraint : constraintsGraphPreserving) { + stream << constraint << std::endl; + } + return stream.str(); + } +}; + +// Thin wrapper for model checking +double modelChecking(std::shared_ptr> model, std::shared_ptr const& formula) { + std::unique_ptr checkResult = storm::verifySparseModel(model, formula); + return checkResult->asExplicitQuantitativeCheckResult()[*model->getInitialStates().begin()]; +} + +// Thin wrapper for model checking for all states +std::vector modelCheckingAll(std::shared_ptr> model, std::shared_ptr const& formula) { + std::unique_ptr checkResult = storm::verifySparseModel(model, formula); + return checkResult->asExplicitQuantitativeCheckResult().getValueVector(); +} + +// Thin wrapper for parametric model checking +std::shared_ptr parametricModelChecking(std::shared_ptr> model, std::shared_ptr const& formula) { + std::unique_ptr checkResult = storm::verifySparseModel(model, formula); + std::shared_ptr result = std::make_shared(); + result->resultFunction = checkResult->asExplicitQuantitativeCheckResult()[*model->getInitialStates().begin()]; + storm::models::sparse::Dtmc::ConstraintCollector constraintCollector(*(model->template as>())); + result->constraintsWellFormed = constraintCollector.getWellformedConstraints(); + result->constraintsGraphPreserving = constraintCollector.getGraphPreservingConstraints(); + return result; +} + +// Define python bindings +void define_modelchecking(py::module& m) { + + // Model checking + m.def("_model_checking", &modelChecking, "Perform model checking", py::arg("model"), py::arg("formula")); + m.def("model_checking_all", &modelCheckingAll, "Perform model checking for all states", py::arg("model"), py::arg("formula")); + m.def("_parametric_model_checking", ¶metricModelChecking, "Perform parametric model checking", py::arg("model"), py::arg("formula")); + + // PmcResult + py::class_>(m, "PmcResult", "Holds the results after parametric model checking") + .def("__str__", &PmcResult::toString) + .def_property_readonly("result_function", &PmcResult::getResultFunction, "Result as rational function") + .def_property_readonly("constraints_well_formed", &PmcResult::getConstraintsWellFormed, "Constraints ensuring well-formed probabilities") + .def_property_readonly("constraints_graph_preserving", &PmcResult::getConstraintsGraphPreserving, "Constraints ensuring graph preservation") + ; + +} diff --git a/src/core/modelchecking.h b/src/core/modelchecking.h new file mode 100644 index 0000000..06b1aad --- /dev/null +++ b/src/core/modelchecking.h @@ -0,0 +1,8 @@ +#ifndef PYTHON_CORE_MODELCHECKING_H_ +#define PYTHON_CORE_MODELCHECKING_H_ + +#include "common.h" + +void define_modelchecking(py::module& m); + +#endif /* PYTHON_CORE_MODELCHECKING_H_ */ diff --git a/src/helpers.h b/src/helpers.h new file mode 100644 index 0000000..ffda72c --- /dev/null +++ b/src/helpers.h @@ -0,0 +1,29 @@ +/* + * helpers.h + * + * Created on: 16 Apr 2016 + * Author: harold + */ + +#ifndef PYTHON_HELPERS_H_ +#define PYTHON_HELPERS_H_ + +#include +#include + +/** + * Helper function to get a string out of the stream operator. + * Used for __str__ functions. + */ +template +std::string streamToString(T const & t) { + std::stringstream ss; + ss << t; + return ss.str(); +} + +// Be warned: Enabling something like this will break everything about Monomial, +// as to Python the shared_ptr (Arg) IS the Monomial +// //PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); + +#endif /* PYTHON_HELPERS_H_ */ diff --git a/src/logic/formulae.cpp b/src/logic/formulae.cpp new file mode 100644 index 0000000..ac469ca --- /dev/null +++ b/src/logic/formulae.cpp @@ -0,0 +1,59 @@ +#include "formulae.h" +#include "storm/logic/Formulas.h" + + +void define_formulae(py::module& m) { + + py::enum_(m, "ComparisonType") + .value("LESS", storm::logic::ComparisonType::Less) + .value("LEQ", storm::logic::ComparisonType::LessEqual) + .value("GREATER", storm::logic::ComparisonType::Greater) + .value("GEQ", storm::logic::ComparisonType::GreaterEqual) + ; + + /*py::class_>, void, void>("FormulaVec", "Vector of formulas") + .def(vector_indexing_suite>, true>()) + ;*/ + + + py::class_> formula(m, "Formula", "Generic Storm Formula"); + formula.def("__str__", &storm::logic::Formula::toString) + ; + + // Path Formulae + py::class_> pathFormula(m, "PathFormula", "Formula about the probability of a set of paths in an automaton", formula); + py::class_> unaryPathFormula(m, "UnaryPathFormula", "Path formula with one operand", pathFormula); + py::class_>(m, "EventuallyFormula", "Formula for eventually", unaryPathFormula); + py::class_>(m, "GloballyFormula", "Formula for globally", unaryPathFormula); + py::class_> binaryPathFormula(m, "BinaryPathFormula", "Path formula with two operands", pathFormula); + py::class_>(m, "BoundedUntilFormula", "Until Formula with either a step or a time bound.", binaryPathFormula); + py::class_>(m, "ConditionalFormula", "Formula with the right hand side being a condition.", formula); + py::class_>(m, "UntilFormula", "Path Formula for unbounded until", binaryPathFormula); + + // Reward Path Formulae + //py::class_(m, "RewardPathFormula", "Formula about the rewards of a set of paths in an automaton", py::base()); + py::class_>(m, "CumulativeRewardFormula", "Summed rewards over a the paths", pathFormula); + py::class_>(m ,"InstantaneousRewardFormula", "Instantaneous reward", pathFormula); + py::class_>(m, "LongRunAverageRewardFormula", "Long run average reward", pathFormula); + //py::class_>(m, "ReachabilityRewardFormula", "Reachability reward", py::base()); + + + // State Formulae + py::class_> stateFormula(m, "StateFormula", "Formula about a state of an automaton", formula); + py::class_>(m, "AtomicExpressionFormula", "Formula with an atomic expression", stateFormula); + py::class_>(m, "AtomicLabelFormula", "Formula with an atomic label", stateFormula); + py::class_>(m, "BooleanLiteralFormula", "Formula with a boolean literal", stateFormula); + py::class_> unaryStateFormula(m, "UnaryStateFormula", "State formula with one operand", stateFormula); + py::class_>(m, "UnaryBooleanStateFormula", "Unary boolean state formula", unaryStateFormula); + py::class_> operatorFormula(m, "OperatorFormula", "Operator formula",unaryStateFormula); + operatorFormula.def_property_readonly("has_bound", &storm::logic::OperatorFormula::hasBound, "Flag if formula is bounded") + .def_property("threshold", &storm::logic::OperatorFormula::getThreshold, &storm::logic::OperatorFormula::setThreshold, "Threshold of bound") + .def_property("comparison_type", &storm::logic::OperatorFormula::getComparisonType, &storm::logic::OperatorFormula::setComparisonType, "Comparison type of bound") + ; + py::class_>(m, "TimeOperator", "The time operator", operatorFormula); + py::class_>(m, "LongRunAvarageOperator", "Long run average operator", operatorFormula); + py::class_>(m, "ProbabilityOperator", "Probability operator", operatorFormula); + py::class_>(m, "RewardOperator", "Reward operator", operatorFormula); + py::class_> binaryStateFormula(m, "BinaryStateFormula", "State formula with two operands", stateFormula); + py::class_>(m, "BooleanBinaryStateFormula", "Boolean binary state formula", binaryStateFormula); +} diff --git a/src/logic/formulae.h b/src/logic/formulae.h new file mode 100644 index 0000000..d499685 --- /dev/null +++ b/src/logic/formulae.h @@ -0,0 +1,8 @@ +#ifndef PYTHON_LOGIC_FORMULAE_H_ +#define PYTHON_LOGIC_FORMULAE_H_ + +#include "src/common.h" + +void define_formulae(py::module& m); + +#endif /* PYTHON_LOGIC_FORMULAE_H_ */ diff --git a/src/mod_core.cpp b/src/mod_core.cpp new file mode 100644 index 0000000..b008e40 --- /dev/null +++ b/src/mod_core.cpp @@ -0,0 +1,17 @@ +#include "common.h" + +#include "core/core.h" +#include "core/modelchecking.h" +#include "core/bisimulation.h" +#include "core/input.h" + +PYBIND11_PLUGIN(core) { + py::module m("core"); + define_core(m); + define_parse(m); + define_build(m); + define_modelchecking(m); + define_bisimulation(m); + define_input(m); + return m.ptr(); +} diff --git a/src/mod_expressions.cpp b/src/mod_expressions.cpp new file mode 100644 index 0000000..ef89106 --- /dev/null +++ b/src/mod_expressions.cpp @@ -0,0 +1,21 @@ +#include "common.h" +#include "helpers.h" +#include "storm/storage/expressions/ExpressionManager.h" + +PYBIND11_PLUGIN(expressions) { + py::module m("expressions", "Storm expressions"); + + py::class_>(m, "ExpressionManager", "Manages variables for expressions") + ; + + py::class_(m, "Expression", "Holds an expression") + .def("__str__", &storm::expressions::Expression::toString) + .def_property_readonly("contains_variables", &storm::expressions::Expression::containsVariables) + .def_property_readonly("has_boolean_type", &storm::expressions::Expression::hasBooleanType) + .def_property_readonly("has_integer_type", &storm::expressions::Expression::hasIntegerType) + .def_property_readonly("has_rational_type", &storm::expressions::Expression::hasRationalType) + + ; + + return m.ptr(); +} diff --git a/src/mod_info.cpp b/src/mod_info.cpp new file mode 100644 index 0000000..427b1f8 --- /dev/null +++ b/src/mod_info.cpp @@ -0,0 +1,13 @@ +#include "common.h" +#include "helpers.h" +#include "storm/utility/storm-version.h" + +PYBIND11_PLUGIN(info) { + py::module m("info", "Storm information"); + py::class_(m, "Version", "Version information for Storm") + .def_property_readonly("short", &storm::utility::StormVersion::shortVersionString, "Storm version in short representation") + .def_property_readonly("long", &storm::utility::StormVersion::longVersionString, "Storm version in long representation") + .def_property_readonly("build_info", &storm::utility::StormVersion::buildInfo, "Build info for Storm") + ; + return m.ptr(); +} diff --git a/src/mod_logic.cpp b/src/mod_logic.cpp new file mode 100644 index 0000000..98fcad1 --- /dev/null +++ b/src/mod_logic.cpp @@ -0,0 +1,9 @@ +#include "common.h" + +#include "logic/formulae.h" + +PYBIND11_PLUGIN(logic) { + py::module m("logic", "Logic module for Storm"); + define_formulae(m); + return m.ptr(); +} diff --git a/src/mod_storage.cpp b/src/mod_storage.cpp new file mode 100644 index 0000000..835f1e7 --- /dev/null +++ b/src/mod_storage.cpp @@ -0,0 +1,11 @@ +#include "common.h" + +#include "storage/model.h" +#include "storage/matrix.h" + +PYBIND11_PLUGIN(storage) { + py::module m("storage"); + define_model(m); + define_sparse_matrix(m); + return m.ptr(); +} diff --git a/src/storage/common.h b/src/storage/common.h new file mode 100644 index 0000000..c9b9b0c --- /dev/null +++ b/src/storage/common.h @@ -0,0 +1 @@ +#include "src/common.h" diff --git a/src/storage/matrix.cpp b/src/storage/matrix.cpp new file mode 100644 index 0000000..887a866 --- /dev/null +++ b/src/storage/matrix.cpp @@ -0,0 +1,129 @@ +#include "matrix.h" +#include "storm/storage/SparseMatrix.h" + +typedef storm::storage::SparseMatrix::index_type entry_index; +typedef unsigned int row_index; +typedef storm::storage::SparseMatrix::index_type parametric_entry_index; +typedef unsigned int parametric_row_index; + +void define_sparse_matrix(py::module& m) { + + // MatrixEntry + py::class_>(m, "SparseMatrixEntry", "Entry of sparse matrix") + .def("__str__", [](storm::storage::MatrixEntry const& entry) { + std::stringstream stream; + stream << entry; + return stream.str(); + }) + //def_property threw "pointer being freed not allocated" after exiting + .def("value", &storm::storage::MatrixEntry::getValue, "Value") + .def("set_value", &storm::storage::MatrixEntry::setValue, py::arg("value"), "Set value") + .def_property_readonly("column", &storm::storage::MatrixEntry::getColumn, "Column") + ; + + py::class_>(m, "ParametricSparseMatrixEntry", "Entry of parametric sparse matrix") + .def("__str__", [](storm::storage::MatrixEntry const& entry) { + std::stringstream stream; + stream << entry; + return stream.str(); + }) + //def_property threw "pointer being freed not allocated" after exiting + .def("value", &storm::storage::MatrixEntry::getValue, "Value") + .def("set_value", &storm::storage::MatrixEntry::setValue, py::arg("value"), "Set value") + .def_property_readonly("column", &storm::storage::MatrixEntry::getColumn, "Column") + ; + + // SparseMatrix + py::class_>(m, "SparseMatrix", "Sparse matrix") + .def("__iter__", [](storm::storage::SparseMatrix& matrix) { + return py::make_iterator(matrix.begin(), matrix.end()); + }, py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */) + .def("__str__", [](storm::storage::SparseMatrix const& matrix) { + std::stringstream stream; + stream << matrix; + return stream.str(); + }) + .def_property_readonly("nr_rows", &storm::storage::SparseMatrix::getRowCount, "Number of rows") + .def_property_readonly("nr_columns", &storm::storage::SparseMatrix::getColumnCount, "Number of columns") + .def_property_readonly("nr_entries", &storm::storage::SparseMatrix::getEntryCount, "Number of non-zero entries") + .def_property_readonly("_row_group_indices", &storm::storage::SparseMatrix::getRowGroupIndices, "Starting rows of row groups") + .def("get_row", [](storm::storage::SparseMatrix& matrix, entry_index row) { + return matrix.getRows(row, row+1); + }, py::return_value_policy::reference, py::keep_alive<1, 0>(), py::arg("row"), "Get row") + .def("get_rows", [](storm::storage::SparseMatrix& matrix, entry_index start, entry_index end) { + return matrix.getRows(start, end); + }, py::return_value_policy::reference, py::keep_alive<1, 0>(), py::arg("row_start"), py::arg("row_end"), "Get rows from start to end") + .def("print_row", [](storm::storage::SparseMatrix const& matrix, entry_index row) { + std::stringstream stream; + auto rows = matrix.getRows(row, row+1); + for (auto transition : rows) { + stream << transition << ", "; + } + return stream.str(); + }, py::arg("row"), "Print row") + // Entry_index lead to problems + .def("row_iter", [](storm::storage::SparseMatrix& matrix, row_index start, row_index end) { + return py::make_iterator(matrix.begin(start), matrix.end(end)); + }, py::keep_alive<0, 1>() /* keep object alive while iterator exists */, py::arg("row_start"), py::arg("row_end"), "Get iterator from start to end") + ; + + py::class_>(m, "ParametricSparseMatrix", "Parametric sparse matrix") + .def("__iter__", [](storm::storage::SparseMatrix& matrix) { + return py::make_iterator(matrix.begin(), matrix.end()); + }, py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */) + .def("__str__", [](storm::storage::SparseMatrix const& matrix) { + std::stringstream stream; + stream << matrix; + return stream.str(); + }) + .def_property_readonly("nr_rows", &storm::storage::SparseMatrix::getRowCount, "Number of rows") + .def_property_readonly("nr_columns", &storm::storage::SparseMatrix::getColumnCount, "Number of columns") + .def_property_readonly("nr_entries", &storm::storage::SparseMatrix::getEntryCount, "Number of non-zero entries") + .def_property_readonly("_row_group_indices", &storm::storage::SparseMatrix::getRowGroupIndices, "Starting rows of row groups") + .def("get_row", [](storm::storage::SparseMatrix& matrix, parametric_entry_index row) { + return matrix.getRows(row, row+1); + }, py::return_value_policy::reference, py::keep_alive<1, 0>(), py::arg("row"), "Get row") + .def("get_rows", [](storm::storage::SparseMatrix& matrix, parametric_entry_index start, parametric_entry_index end) { + return matrix.getRows(start, end); + }, py::return_value_policy::reference, py::keep_alive<1, 0>(), py::arg("row_start"), py::arg("row_end"), "Get rows from start to end") + .def("print_row", [](storm::storage::SparseMatrix const& matrix, parametric_entry_index row) { + std::stringstream stream; + auto rows = matrix.getRows(row, row+1); + for (auto transition : rows) { + stream << transition << ", "; + } + return stream.str(); + }, py::arg("row"), "Print row") + // Entry_index lead to problems + .def("row_iter", [](storm::storage::SparseMatrix& matrix, parametric_row_index start, parametric_row_index end) { + return py::make_iterator(matrix.begin(start), matrix.end(end)); + }, py::keep_alive<0, 1>() /* keep object alive while iterator exists */, py::arg("row_start"), py::arg("row_end"), "Get iterator from start to end") + ; + + // Rows + py::class_::rows>(m, "SparseMatrixRows", "Set of rows in a sparse matrix") + .def("__iter__", [](storm::storage::SparseMatrix::rows& rows) { + return py::make_iterator(rows.begin(), rows.end()); + }, py::keep_alive<0, 1>()) + .def("__str__", [](storm::storage::SparseMatrix::const_rows& rows) { + std::stringstream stream; + for (auto transition : rows) { + stream << transition << ", "; + } + return stream.str(); + }) + ; + + py::class_::rows>(m, "ParametricSparseMatrixRows", "Set of rows in a parametric sparse matrix") + .def("__iter__", [](storm::storage::SparseMatrix::rows& rows) { + return py::make_iterator(rows.begin(), rows.end()); + }, py::keep_alive<0, 1>()) + .def("__str__", [](storm::storage::SparseMatrix::const_rows& rows) { + std::stringstream stream; + for (auto transition : rows) { + stream << transition << ", "; + } + return stream.str(); + }) + ; +} diff --git a/src/storage/matrix.h b/src/storage/matrix.h new file mode 100644 index 0000000..96e3df6 --- /dev/null +++ b/src/storage/matrix.h @@ -0,0 +1,8 @@ +#ifndef PYTHON_STORAGE_MATRIX_H_ +#define PYTHON_STORAGE_MATRIX_H_ + +#include "common.h" + +void define_sparse_matrix(py::module& m); + +#endif /* PYTHON_STORAGE_MATRIX_H_ */ diff --git a/src/storage/model.cpp b/src/storage/model.cpp new file mode 100644 index 0000000..02f32a5 --- /dev/null +++ b/src/storage/model.cpp @@ -0,0 +1,77 @@ +#include "model.h" +#include "storm/models/ModelBase.h" +#include "storm/models/sparse/Model.h" +#include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/Mdp.h" +#include "storm/models/sparse/StandardRewardModel.h" + +// Thin wrapper for getting initial states +template +std::vector getInitialStates(storm::models::sparse::Model const& model) { + std::vector initialStates; + for (auto entry : model.getInitialStates()) { + initialStates.push_back(entry); + } + return initialStates; +} + +// Thin wrapper for getting transition matrix +template +storm::storage::SparseMatrix& getTransitionMatrix(storm::models::sparse::Model& model) { + return model.getTransitionMatrix(); +} + +// Define python bindings +void define_model(py::module& m) { + + // ModelType + py::enum_(m, "ModelType", "Type of the model") + .value("DTMC", storm::models::ModelType::Dtmc) + .value("MDP", storm::models::ModelType::Mdp) + .value("CTMC", storm::models::ModelType::Ctmc) + .value("MA", storm::models::ModelType::MarkovAutomaton) + ; + + // ModelBase + py::class_>(m, "ModelBase", "Base class for all models") + .def_property_readonly("nr_states", &storm::models::ModelBase::getNumberOfStates, "Number of states") + .def_property_readonly("nr_transitions", &storm::models::ModelBase::getNumberOfTransitions, "Number of transitions") + .def_property_readonly("model_type", &storm::models::ModelBase::getType, "Model type") + .def_property_readonly("supports_parameters", &storm::models::ModelBase::supportsParameters, "Flag whether model supports parameters") + .def_property_readonly("has_parameters", &storm::models::ModelBase::hasParameters, "Flag whether model has parameters") + .def_property_readonly("is_exact", &storm::models::ModelBase::isExact, "Flag whether model is exact") + .def("as_dtmc", &storm::models::ModelBase::as>, "Get model as DTMC") + .def("as_pdtmc", &storm::models::ModelBase::as>, "Get model as pDTMC") + .def("as_mdp", &storm::models::ModelBase::as>, "Get model as MDP") + .def("as_pmdp", &storm::models::ModelBase::as>, "Get model as pMDP") + ; + + // Models + py::class_, std::shared_ptr>>(m, "SparseModel", "A probabilistic model where transitions are represented by doubles and saved in a sparse matrix", py::base()) + .def_property_readonly("labels", [](storm::models::sparse::Model& model) { + return model.getStateLabeling().getLabels(); + }, "Labels") + .def("labels_state", &storm::models::sparse::Model::getLabelsOfState, py::arg("state"), "Get labels of state") + .def_property_readonly("initial_states", &getInitialStates, "Initial states") + .def_property_readonly("transition_matrix", &getTransitionMatrix, py::return_value_policy::reference, py::keep_alive<1, 0>(), "Transition matrix") + ; + py::class_, std::shared_ptr>>(m, "SparseDtmc", "DTMC in sparse representation", py::base>()) + ; + py::class_, std::shared_ptr>>(m, "SparseMdp", "MDP in sparse representation", py::base>()) + ; + + py::class_, std::shared_ptr>>(m, "SparseParametricModel", "A probabilistic model where transitions are represented by rational functions and saved in a sparse matrix", py::base()) + .def("collect_probability_parameters", &storm::models::sparse::getProbabilityParameters, "Collect parameters") + .def_property_readonly("labels", [](storm::models::sparse::Model& model) { + return model.getStateLabeling().getLabels(); + }, "Labels") + .def("labels_state", &storm::models::sparse::Model::getLabelsOfState, py::arg("state"), "Get labels of state") + .def_property_readonly("initial_states", &getInitialStates, "Initial states") + .def_property_readonly("transition_matrix", &getTransitionMatrix, py::return_value_policy::reference, py::keep_alive<1, 0>(), "Transition matrix") + ; + py::class_, std::shared_ptr>>(m, "SparseParametricDtmc", "pDTMC in sparse representation", py::base>()) + ; + py::class_, std::shared_ptr>>(m, "SparseParametricMdp", "pMDP in sparse representation", py::base>()) + ; + +} diff --git a/src/storage/model.h b/src/storage/model.h new file mode 100644 index 0000000..c779f26 --- /dev/null +++ b/src/storage/model.h @@ -0,0 +1,8 @@ +#ifndef PYTHON_STORAGE_MODEL_H_ +#define PYTHON_STORAGE_MODEL_H_ + +#include "common.h" + +void define_model(py::module& m); + +#endif /* PYTHON_STORAGE_MODEL_H_ */ diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..5e85fe6 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,3 @@ +import sys +import os +sys.path.append(os.path.join(os.path.dirname(__file__), 'helpers')) diff --git a/tests/core/test_bisimulation.py b/tests/core/test_bisimulation.py new file mode 100644 index 0000000..3776f54 --- /dev/null +++ b/tests/core/test_bisimulation.py @@ -0,0 +1,39 @@ +import stormpy +import stormpy.logic +from helpers.helper import get_example_path + +class TestBisimulation: + def test_bisimulation(self): + program = stormpy.parse_prism_program(get_example_path("dtmc", "crowds5_5.pm")) + assert program.nr_modules == 1 + assert program.model_type == stormpy.PrismModelType.DTMC + prop = "P=? [F \"observe0Greater1\"]" + formulas = stormpy.parse_formulas_for_prism_program(prop, program) + model = stormpy.build_model_from_prism_program(program, formulas) + assert model.nr_states == 7403 + assert model.nr_transitions == 13041 + assert model.model_type == stormpy.ModelType.DTMC + assert not model.supports_parameters + model_bisim = stormpy.perform_bisimulation(model, formulas[0], stormpy.BisimulationType.STRONG) + assert model_bisim.nr_states == 64 + assert model_bisim.nr_transitions == 104 + assert model_bisim.model_type == stormpy.ModelType.DTMC + assert not model_bisim.supports_parameters + + def test_parametric_bisimulation(self): + program = stormpy.parse_prism_program(get_example_path("pdtmc", "crowds3_5.pm")) + assert program.nr_modules == 1 + assert program.model_type == stormpy.PrismModelType.DTMC + assert program.has_undefined_constants + prop = "P=? [F \"observe0Greater1\"]" + formulas = stormpy.parse_formulas_for_prism_program(prop, program) + model = stormpy.build_parametric_model_from_prism_program(program, formulas) + assert model.nr_states == 1367 + assert model.nr_transitions == 2027 + assert model.model_type == stormpy.ModelType.DTMC + assert model.has_parameters + model_bisim = stormpy.perform_bisimulation(model, formulas[0], stormpy.BisimulationType.STRONG) + assert model_bisim.nr_states == 80 + assert model_bisim.nr_transitions == 120 + assert model_bisim.model_type == stormpy.ModelType.DTMC + assert model_bisim.has_parameters diff --git a/tests/core/test_core.py b/tests/core/test_core.py new file mode 100644 index 0000000..cedd750 --- /dev/null +++ b/tests/core/test_core.py @@ -0,0 +1,14 @@ + +class TestCore: + def test_init(self): + import stormpy + + def test_pycarl(self): + import stormpy + import pycarl + import pycarl.formula + import pycarl.parse + pol1 = pycarl.FactorizedPolynomial(32) + pol2 = pycarl.FactorizedPolynomial(2) + rat = pycarl.FactorizedRationalFunction(pol1, pol2) + assert str(rat) == "16" diff --git a/tests/core/test_modelchecking.py b/tests/core/test_modelchecking.py new file mode 100644 index 0000000..56ccdc9 --- /dev/null +++ b/tests/core/test_modelchecking.py @@ -0,0 +1,45 @@ +import stormpy +import stormpy.logic +from helpers.helper import get_example_path + +class TestModelChecking: + def test_model_checking_dtmc(self): + program = stormpy.parse_prism_program(get_example_path("dtmc", "die.pm")) + formulas = stormpy.parse_formulas_for_prism_program("P=? [ F \"one\" ]", program) + model = stormpy.build_model(program, formulas[0]) + assert model.nr_states == 13 + assert model.nr_transitions == 20 + result = stormpy.model_checking(model, formulas[0]) + assert result == 0.16666666666666663 + + def test_model_checking_all_dtmc(self): + program = stormpy.parse_prism_program(get_example_path("dtmc", "die.pm")) + formulas = stormpy.parse_formulas_for_prism_program("P=? [ F \"one\" ]", program) + model = stormpy.build_model(program, formulas[0]) + assert model.nr_states == 13 + assert model.nr_transitions == 20 + results = stormpy.model_checking_all(model, formulas[0]) + results_orig = [0.16666666666666663, 0.3333333333333333, 0, 0.6666666666666666, 0, 0, 0, 1, 0, 0, 0, 0, 0] + assert results == results_orig + + def test_parametric_state_elimination(self): + import pycarl + import pycarl.formula + program = stormpy.parse_prism_program(get_example_path("pdtmc", "brp16_2.pm")) + prop = "P=? [F s=5]" + formulas = stormpy.parse_formulas_for_prism_program(prop, program) + model = stormpy.build_parametric_model_from_prism_program(program, formulas) + assert model.nr_states == 613 + assert model.nr_transitions == 803 + assert model.model_type == stormpy.ModelType.DTMC + assert model.has_parameters + result = stormpy.model_checking(model, formulas[0]) + func = result.result_function + one = pycarl.FactorizedPolynomial(pycarl.Rational(1)) + assert func.denominator == one + constraints_well_formed = result.constraints_well_formed + for constraint in constraints_well_formed: + assert constraint.rel() == pycarl.formula.Relation.GEQ or constraint.rel() == pycarl.formula.Relation.LEQ + constraints_graph_preserving = result.constraints_graph_preserving + for constraint in constraints_graph_preserving: + assert constraint.rel() == pycarl.formula.Relation.GREATER diff --git a/tests/core/test_parse.py b/tests/core/test_parse.py new file mode 100644 index 0000000..83aff42 --- /dev/null +++ b/tests/core/test_parse.py @@ -0,0 +1,32 @@ +import stormpy +import stormpy.logic +from helpers.helper import get_example_path + +class TestParse: + def test_parse_prism_program(self): + program = stormpy.parse_prism_program(get_example_path("dtmc", "die.pm")) + assert program.nr_modules == 1 + assert program.model_type == stormpy.PrismModelType.DTMC + assert not program.has_undefined_constants + + def test_parse_formula(self): + prop = "P=? [F \"one\"]" + formulas = stormpy.parse_formulas(prop) + assert len(formulas) == 1 + assert str(formulas[0]) == prop + + def test_parse_explicit_dtmc(self): + model = stormpy.parse_explicit_model(get_example_path("dtmc", "die.tra"), get_example_path("dtmc", "die.lab")) + assert model.nr_states == 13 + assert model.nr_transitions == 20 + assert model.model_type == stormpy.ModelType.DTMC + assert not model.supports_parameters + assert type(model) is stormpy.SparseDtmc + + def test_parse_explicit_mdp(self): + model = stormpy.parse_explicit_model(get_example_path("mdp", "two_dice.tra"), get_example_path("mdp", "two_dice.lab")) + assert model.nr_states == 169 + assert model.nr_transitions == 436 + assert model.model_type == stormpy.ModelType.MDP + assert not model.supports_parameters + assert type(model) is stormpy.SparseMdp diff --git a/tests/expressions/test_expressions.py b/tests/expressions/test_expressions.py new file mode 100644 index 0000000..823186d --- /dev/null +++ b/tests/expressions/test_expressions.py @@ -0,0 +1,9 @@ +import stormpy +from stormpy.expressions import expressions + +class TestExpressions: + def test_expression_manager(self): + manager = expressions.ExpressionManager + + def test_expression(self): + expression = expressions.Expression diff --git a/tests/helpers/helper.py b/tests/helpers/helper.py new file mode 100644 index 0000000..a7c2d29 --- /dev/null +++ b/tests/helpers/helper.py @@ -0,0 +1,5 @@ +import os +example_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, "resources", "examples", "testfiles")) + +def get_example_path(*paths): + return os.path.join(example_dir, *paths) diff --git a/tests/info/test_info.py b/tests/info/test_info.py new file mode 100644 index 0000000..fd91d68 --- /dev/null +++ b/tests/info/test_info.py @@ -0,0 +1,8 @@ +import stormpy +from stormpy.info import info + +class TestInfo: + def test_version(self): + s = info.Version.short + s = info.Version.long + s = info.Version.build_info diff --git a/tests/logic/test_formulas.py b/tests/logic/test_formulas.py new file mode 100644 index 0000000..1bb697c --- /dev/null +++ b/tests/logic/test_formulas.py @@ -0,0 +1,51 @@ +import pycarl +import stormpy +import stormpy.logic + +class TestFormulas: + + def test_probability_formula(self): + prop = "P=? [F \"one\"]" + formulas = stormpy.parse_formulas(prop) + formula = formulas[0] + assert type(formula) == stormpy.logic.ProbabilityOperator + assert len(formulas) == 1 + assert str(formula) == prop + + def test_reward_formula(self): + prop = "R=? [F \"one\"]" + formulas = stormpy.parse_formulas(prop) + formula = formulas[0] + assert type(formula) == stormpy.logic.RewardOperator + assert len(formulas) == 1 + assert str(formula) == "R[exp]=? [F \"one\"]" + + def test_formula_list(self): + formulas = [] + prop = "=? [F \"one\"]" + forms = stormpy.parse_formulas("P" + prop) + formulas.append(forms[0]) + forms = stormpy.parse_formulas("R" + prop) + formulas.append(forms[0]) + assert len(formulas) == 2 + assert str(formulas[0]) == "P" + prop + assert str(formulas[1]) == "R[exp]" + prop + + def test_bounds(self): + prop = "P=? [F \"one\"]" + formula = stormpy.parse_formulas(prop)[0] + assert not formula.has_bound + prop = "P<0.4 [F \"one\"]" + formula = stormpy.parse_formulas(prop)[0] + assert formula.has_bound + assert formula.threshold == pycarl.Rational("0.4") + assert formula.comparison_type == stormpy.logic.ComparisonType.LESS + + def test_set_bounds(self): + prop = "P<0.4 [F \"one\"]" + formula = stormpy.parse_formulas(prop)[0] + formula.threshold = pycarl.Rational("0.2") + formula.comparison_type = stormpy.logic.ComparisonType.GEQ + assert formula.threshold == pycarl.Rational("0.2") + assert formula.comparison_type == stormpy.logic.ComparisonType.GEQ + assert str(formula) == "P>=1/5 [F \"one\"]" diff --git a/tests/storage/test_matrix.py b/tests/storage/test_matrix.py new file mode 100644 index 0000000..e6e2e63 --- /dev/null +++ b/tests/storage/test_matrix.py @@ -0,0 +1,96 @@ +import stormpy +from helpers.helper import get_example_path + +class TestMatrix: + def test_sparse_matrix(self): + model = stormpy.parse_explicit_model(get_example_path("dtmc", "die.tra"), get_example_path("dtmc", "die.lab")) + matrix = model.transition_matrix + assert type(matrix) is stormpy.storage.SparseMatrix + assert matrix.nr_rows == model.nr_states + assert matrix.nr_columns == model.nr_states + assert matrix.nr_entries == 27 #model.nr_transitions + for e in matrix: + assert e.value() == 0.5 or e.value() == 0 or (e.value() == 1 and e.column > 6) + + def test_change_sparse_matrix(self): + model = stormpy.parse_explicit_model(get_example_path("dtmc", "die.tra"), get_example_path("dtmc", "die.lab")) + matrix = model.transition_matrix + for e in matrix: + assert e.value() == 0.5 or e.value() == 0 or e.value() == 1 + i = 0 + for e in matrix: + e.set_value(i) + i += 0.1 + i = 0 + for e in matrix: + assert e.value() == i + i += 0.1 + + def test_change_sparse_matrix_modelchecking(self): + import stormpy.logic + model = stormpy.parse_explicit_model(get_example_path("dtmc", "die.tra"), get_example_path("dtmc", "die.lab")) + matrix = model.transition_matrix + # Check matrix + for e in matrix: + assert e.value() == 0.5 or e.value() == 0 or e.value() == 1 + # First model checking + formulas = stormpy.parse_formulas("P=? [ F \"one\" ]") + result = stormpy.model_checking(model, formulas[0]) + assert result == 0.16666666666666663 + + # Change probabilities + i = 0 + for e in matrix: + if e.value() == 0.5: + if i % 2 == 0: + e.set_value(0.3) + else: + e.set_value(0.7) + i += 1 + for e in matrix: + assert e.value() == 0.3 or e.value() == 0.7 or e.value() == 1 or e.value() == 0 + # Second model checking + result = stormpy.model_checking(model, formulas[0]) + assert result == 0.06923076923076932 + + # Change probabilities again + for state in stormpy.state.State(0, model): + for action in state.actions(): + for transition in action.transitions(): + if transition.value() == 0.3: + transition.set_value(0.8) + elif transition.value() == 0.7: + transition.set_value(0.2) + # Third model checking + result = stormpy.model_checking(model, formulas[0]) + assert result == 0.3555555555555556 or result == 0.3555555555555557 + + def test_change_parametric_sparse_matrix_modelchecking(self): + import stormpy.logic + import pycarl + program = stormpy.parse_prism_program(get_example_path("pdtmc", "brp16_2.pm")) + formulas = stormpy.parse_formulas_for_prism_program("P=? [ F s=5 ]", program) + model = stormpy.build_parametric_model(program, formulas[0]) + matrix = model.transition_matrix + # Check matrix + one_pol = pycarl.Rational(1) + one_pol = pycarl.FactorizedPolynomial(one_pol) + one = pycarl.FactorizedRationalFunction(one_pol, one_pol) + for e in matrix: + assert e.value() == one or len(e.value().gather_variables()) > 0 + # First model checking + result = stormpy.model_checking(model, formulas[0]) + assert len(result.result_function.gather_variables()) > 0 + + # Change probabilities + two_pol = pycarl.Rational(2) + two_pol = pycarl.FactorizedPolynomial(two_pol) + new_val = pycarl.FactorizedRationalFunction(one_pol, two_pol) + for e in matrix: + if len(e.value().gather_variables()) > 0: + e.set_value(new_val) + for e in matrix: + assert e.value() == new_val or e.value() == one + # Second model checking + result = stormpy.model_checking(model, formulas[0]) + assert len(result.result_function.gather_variables()) == 0 diff --git a/tests/storage/test_model.py b/tests/storage/test_model.py new file mode 100644 index 0000000..44a4c9c --- /dev/null +++ b/tests/storage/test_model.py @@ -0,0 +1,96 @@ +import stormpy +import stormpy.logic +from helpers.helper import get_example_path + +class TestModel: + def test_build_dtmc_from_prism_program(self): + program = stormpy.parse_prism_program(get_example_path("dtmc", "die.pm")) + prop = "P=? [F \"one\"]" + formulas = stormpy.parse_formulas_for_prism_program(prop, program) + model = stormpy.build_model_from_prism_program(program, formulas) + assert model.nr_states == 13 + assert model.nr_transitions == 20 + assert model.model_type == stormpy.ModelType.DTMC + assert not model.supports_parameters + assert type(model) is stormpy.SparseDtmc + + def test_build_parametric_dtmc_from_prism_program(self): + program = stormpy.parse_prism_program(get_example_path("pdtmc", "brp16_2.pm")) + assert program.nr_modules == 5 + assert program.model_type == stormpy.PrismModelType.DTMC + assert program.has_undefined_constants + prop = "P=? [F s=5]" + formulas = stormpy.parse_formulas_for_prism_program(prop, program) + model = stormpy.build_parametric_model_from_prism_program(program, formulas) + assert model.nr_states == 613 + assert model.nr_transitions == 803 + assert model.model_type == stormpy.ModelType.DTMC + assert model.supports_parameters + assert model.has_parameters + assert type(model) is stormpy.SparseParametricDtmc + + def test_build_dtmc(self): + program = stormpy.parse_prism_program(get_example_path("dtmc", "die.pm")) + formulas = stormpy.parse_formulas_for_prism_program("P=? [ F \"one\" ]", program) + model = stormpy.build_model(program, formulas[0]) + assert model.nr_states == 13 + assert model.nr_transitions == 20 + assert model.model_type == stormpy.ModelType.DTMC + assert not model.supports_parameters + assert type(model) is stormpy.SparseDtmc + + def test_build_parametric_dtmc(self): + program = stormpy.parse_prism_program(get_example_path("pdtmc", "brp16_2.pm")) + formulas = stormpy.parse_formulas_for_prism_program("P=? [ F s=5 ]", program) + model = stormpy.build_parametric_model(program, formulas[0]) + assert model.nr_states == 613 + assert model.nr_transitions == 803 + assert model.model_type == stormpy.ModelType.DTMC + assert model.supports_parameters + assert model.has_parameters + assert type(model) is stormpy.SparseParametricDtmc + + def test_build_dtmc_supporting_parameters(self): + program = stormpy.parse_prism_program(get_example_path("dtmc", "die.pm")) + formulas = stormpy.parse_formulas_for_prism_program("P=? [ F \"one\" ]", program) + model = stormpy.build_parametric_model(program, formulas[0]) + assert model.nr_states == 13 + assert model.nr_transitions == 20 + assert model.model_type == stormpy.ModelType.DTMC + assert model.supports_parameters + assert not model.has_parameters + assert type(model) is stormpy.SparseParametricDtmc + + def test_label(self): + program = stormpy.parse_prism_program(get_example_path("dtmc", "die.pm")) + formulas = stormpy.parse_formulas_for_prism_program("P=? [ F \"one\" ]", program) + model = stormpy.build_model(program, formulas[0]) + labels = model.labels + assert len(labels) == 3 + assert "init" in labels + assert "one" in labels + assert "init" in model.labels_state(0) + assert "one" in model.labels_state(7) + + def test_initial_states(self): + program = stormpy.parse_prism_program(get_example_path("dtmc", "die.pm")) + formulas = stormpy.parse_formulas_for_prism_program("P=? [ F \"one\" ]", program) + model = stormpy.build_model(program, formulas[0]) + initial_states = model.initial_states + assert len(initial_states) == 1 + assert 0 in initial_states + + def test_label_parametric(self): + program = stormpy.parse_prism_program(get_example_path("pdtmc", "brp16_2.pm")) + formulas = stormpy.parse_formulas_for_prism_program("P=? [ F s=5 ]", program) + model = stormpy.build_parametric_model(program, formulas[0]) + labels = model.labels + assert len(labels) == 3 + assert "init" in labels + assert "(s = 5)" in labels + assert "init" in model.labels_state(0) + assert "(s = 5)" in model.labels_state(28) + assert "(s = 5)" in model.labels_state(611) + initial_states = model.initial_states + assert len(initial_states) == 1 + assert 0 in initial_states diff --git a/tests/storage/test_model_iterators.py b/tests/storage/test_model_iterators.py new file mode 100644 index 0000000..8023b86 --- /dev/null +++ b/tests/storage/test_model_iterators.py @@ -0,0 +1,82 @@ +import stormpy +from helpers.helper import get_example_path + +class TestModelIterators: + def test_states_dtmc(self): + model = stormpy.parse_explicit_model(get_example_path("dtmc", "die.tra"), get_example_path("dtmc", "die.lab")) + s = stormpy.state.State(0, model) + i = 0 + for state in stormpy.state.State(0, model): + assert state.id == i + i += 1 + assert i == model.nr_states + + def test_states_mdp(self): + model = stormpy.parse_explicit_model(get_example_path("mdp", "two_dice.tra"), get_example_path("mdp", "two_dice.lab")) + s = stormpy.state.State(0, model) + i = 0 + for state in stormpy.state.State(0, model): + assert state.id == i + i += 1 + assert i == model.nr_states + + def test_actions_dtmc(self): + model = stormpy.parse_explicit_model(get_example_path("dtmc", "die.tra"), get_example_path("dtmc", "die.lab")) + s = stormpy.state.State(0, model) + for state in stormpy.state.State(0, model): + for action in state.actions(): + assert action.row == 0 + + def test_actions_mdp(self): + model = stormpy.parse_explicit_model(get_example_path("mdp", "two_dice.tra"), get_example_path("mdp", "two_dice.lab")) + s = stormpy.state.State(0, model) + for state in stormpy.state.State(0, model): + for action in state.actions(): + assert action.row == 0 or action.row == 1 + + def test_transitions_dtmc(self): + transitions_orig = [(0, 0, 0), (0, 1, 0.5), (0, 2, 0.5), (1, 1, 0), (1, 3, 0.5), (1, 4, 0.5), + (2, 2, 0), (2, 5, 0.5), (2, 6, 0.5), (3, 1, 0.5), (3, 3, 0), (3, 7, 0.5), + (4, 4, 0), (4, 8, 0.5), (4, 9, 0.5), (5, 5, 0), (5, 10, 0.5), (5, 11, 0.5), + (6, 2, 0.5), (6, 6, 0), (6, 12, 0.5), (7, 7, 1), (8, 8, 1), + (9, 9, 1), (10, 10, 1), (11, 11, 1), (12, 12, 1) + ] + model = stormpy.parse_explicit_model(get_example_path("dtmc", "die.tra"), get_example_path("dtmc", "die.lab")) + s = stormpy.state.State(0, model) + i = 0 + for state in stormpy.state.State(0, model): + for action in state.actions(): + for transition in action.transitions(): + transition_orig = transitions_orig[i] + i += 1 + assert state.id == transition_orig[0] + assert transition.column == transition_orig[1] + assert transition.value() == transition_orig[2] + + def test_transitions_mdp(self): + model = stormpy.parse_explicit_model(get_example_path("mdp", "two_dice.tra"), get_example_path("mdp", "two_dice.lab")) + s = stormpy.state.State(0, model) + for state in stormpy.state.State(0, model): + i = 0 + for action in state.actions(): + i += 1 + for transition in action.transitions(): + assert transition.value() == 0.5 or transition.value() == 1 + assert i == 1 or i == 2 + + def test_row_iterator(self): + transitions_orig = [(0, 0, 0), (0, 1, 0.5), (0, 2, 0.5), (1, 1, 0), (1, 3, 0.5), (1, 4, 0.5), + (2, 2, 0), (2, 5, 0.5), (2, 6, 0.5), (3, 1, 0.5), (3, 3, 0), (3, 7, 0.5), + (4, 4, 0), (4, 8, 0.5), (4, 9, 0.5), (5, 5, 0), (5, 10, 0.5), (5, 11, 0.5), + (6, 2, 0.5), (6, 6, 0), (6, 12, 0.5), (7, 7, 1), (8, 8, 1), + (9, 9, 1), (10, 10, 1), (11, 11, 1), (12, 12, 1) + ] + model = stormpy.parse_explicit_model(get_example_path("dtmc", "die.tra"), get_example_path("dtmc", "die.lab")) + i = 0 + for state in stormpy.state.State(0, model): + for transition in model.transition_matrix.row_iter(state.id, state.id): + transition_orig = transitions_orig[i] + i += 1 + assert state.id == transition_orig[0] + assert transition.column == transition_orig[1] + assert transition.value() == transition_orig[2]