From b29aa5c67c891e51560418de68bd7cf53db95176 Mon Sep 17 00:00:00 2001 From: jingzhengli Date: Sat, 8 Oct 2022 19:18:02 +0800 Subject: [PATCH] first commit --- README.md | 41 + common/__init__.py | 1 + common/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 200 bytes common/modules/__init__.py | 3 + .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 245 bytes .../__pycache__/classifier.cpython-37.pyc | Bin 0 -> 4842 bytes common/modules/classifier.py | 125 + common/vision/__init__.py | 1 + .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 213 bytes common/vision/models/__init__.py | 3 + .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 266 bytes .../models/__pycache__/resnet.cpython-37.pyc | Bin 0 -> 7107 bytes common/vision/models/resnet.py | 180 ++ common/vision/transforms/__init__.py | 182 ++ .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 7188 bytes config/config.yml | 35 + data/__pycache__/dataset.cpython-37.pyc | Bin 0 -> 8004 bytes data/__pycache__/prepare_data.cpython-37.pyc | Bin 0 -> 9675 bytes data/__pycache__/randaugment.cpython-37.pyc | Bin 0 -> 5840 bytes data/dataset.py | 285 +++ data/prepare_data.py | 255 ++ data/randaugment.py | 222 ++ lr_schedule.py | 11 + main.py | 314 +++ main_covid.py | 274 +++ metric/__init__.py | 107 + metric/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 4188 bytes model/WideResNet.py | 240 ++ model/__pycache__/WideResNet.cpython-37.pyc | Bin 0 -> 6187 bytes .../contrastive_loss.cpython-37.pyc | Bin 0 -> 22714 bytes model/__pycache__/key_memory.cpython-37.pyc | Bin 0 -> 1701 bytes model/__pycache__/model_ljz.cpython-37.pyc | Bin 0 -> 6939 bytes model/__pycache__/resnet.cpython-37.pyc | Bin 0 -> 9433 bytes model/__pycache__/utils.cpython-37.pyc | Bin 0 -> 3210 bytes model/contrastive_loss.py | 375 +++ model/key_memory.py | 50 + model/model.py | 186 ++ model/resnet.py | 310 +++ model/utils.py | 89 + pseudo_labeler.py | 338 +++ pybind11/CMakeLists.txt | 157 ++ pybind11/CONTRIBUTING.md | 49 + pybind11/ISSUE_TEMPLATE.md | 17 + pybind11/LICENSE | 29 + pybind11/MANIFEST.in | 2 + pybind11/README.md | 127 + pybind11/docs/Doxyfile | 20 + pybind11/docs/_static/theme_overrides.css | 11 + pybind11/docs/advanced/cast/chrono.rst | 81 + pybind11/docs/advanced/cast/custom.rst | 91 + pybind11/docs/advanced/cast/eigen.rst | 310 +++ pybind11/docs/advanced/cast/functional.rst | 109 + pybind11/docs/advanced/cast/index.rst | 42 + pybind11/docs/advanced/cast/overview.rst | 165 ++ pybind11/docs/advanced/cast/stl.rst | 240 ++ pybind11/docs/advanced/cast/strings.rst | 305 +++ pybind11/docs/advanced/classes.rst | 1082 +++++++++ pybind11/docs/advanced/embedding.rst | 261 ++ pybind11/docs/advanced/exceptions.rst | 142 ++ pybind11/docs/advanced/functions.rst | 498 ++++ pybind11/docs/advanced/misc.rst | 306 +++ pybind11/docs/advanced/pycpp/index.rst | 13 + pybind11/docs/advanced/pycpp/numpy.rst | 386 +++ pybind11/docs/advanced/pycpp/object.rst | 170 ++ pybind11/docs/advanced/pycpp/utilities.rst | 144 ++ pybind11/docs/advanced/smart_ptrs.rst | 173 ++ pybind11/docs/basics.rst | 293 +++ pybind11/docs/benchmark.py | 88 + pybind11/docs/benchmark.rst | 97 + pybind11/docs/changelog.rst | 1094 +++++++++ pybind11/docs/classes.rst | 521 ++++ pybind11/docs/compiling.rst | 277 +++ pybind11/docs/conf.py | 332 +++ pybind11/docs/faq.rst | 295 +++ pybind11/docs/index.rst | 47 + pybind11/docs/intro.rst | 93 + pybind11/docs/limitations.rst | 20 + pybind11/docs/pybind11-logo.png | Bin 0 -> 58510 bytes pybind11/docs/pybind11_vs_boost_python1.png | Bin 0 -> 44653 bytes pybind11/docs/pybind11_vs_boost_python1.svg | 427 ++++ pybind11/docs/pybind11_vs_boost_python2.png | Bin 0 -> 41121 bytes pybind11/docs/pybind11_vs_boost_python2.svg | 427 ++++ pybind11/docs/reference.rst | 102 + pybind11/docs/release.rst | 25 + pybind11/docs/requirements.txt | 1 + pybind11/docs/upgrade.rst | 404 ++++ pybind11/include/pybind11/attr.h | 492 ++++ pybind11/include/pybind11/buffer_info.h | 108 + pybind11/include/pybind11/cast.h | 2128 +++++++++++++++++ pybind11/include/pybind11/chrono.h | 162 ++ pybind11/include/pybind11/common.h | 2 + pybind11/include/pybind11/complex.h | 65 + pybind11/include/pybind11/detail/class.h | 622 +++++ pybind11/include/pybind11/detail/common.h | 807 +++++++ pybind11/include/pybind11/detail/descr.h | 100 + pybind11/include/pybind11/detail/init.h | 335 +++ pybind11/include/pybind11/detail/internals.h | 291 +++ pybind11/include/pybind11/detail/typeid.h | 53 + pybind11/include/pybind11/eigen.h | 607 +++++ pybind11/include/pybind11/embed.h | 200 ++ pybind11/include/pybind11/eval.h | 117 + pybind11/include/pybind11/functional.h | 83 + pybind11/include/pybind11/iostream.h | 200 ++ pybind11/include/pybind11/numpy.h | 1607 +++++++++++++ pybind11/include/pybind11/operators.h | 168 ++ pybind11/include/pybind11/options.h | 65 + pybind11/include/pybind11/pybind11.h | 2094 ++++++++++++++++ pybind11/include/pybind11/pytypes.h | 1431 +++++++++++ pybind11/include/pybind11/stl.h | 386 +++ pybind11/include/pybind11/stl_bind.h | 599 +++++ pybind11/pybind11/__init__.py | 28 + pybind11/pybind11/__main__.py | 37 + pybind11/pybind11/_version.py | 2 + pybind11/setup.cfg | 10 + pybind11/setup.py | 108 + pybind11/tests/CMakeLists.txt | 238 ++ pybind11/tests/conftest.py | 241 ++ pybind11/tests/constructor_stats.h | 276 +++ pybind11/tests/local_bindings.h | 64 + pybind11/tests/object.h | 175 ++ .../tests/pybind11_cross_module_tests.cpp | 123 + pybind11/tests/pybind11_tests.cpp | 93 + pybind11/tests/pybind11_tests.h | 65 + pybind11/tests/pytest.ini | 15 + pybind11/tests/test_buffers.cpp | 169 ++ pybind11/tests/test_buffers.py | 87 + pybind11/tests/test_builtin_casters.cpp | 170 ++ pybind11/tests/test_builtin_casters.py | 342 +++ pybind11/tests/test_call_policies.cpp | 100 + pybind11/tests/test_call_policies.py | 187 ++ pybind11/tests/test_callbacks.cpp | 149 ++ pybind11/tests/test_callbacks.py | 107 + pybind11/tests/test_chrono.cpp | 47 + pybind11/tests/test_chrono.py | 101 + pybind11/tests/test_class.cpp | 422 ++++ pybind11/tests/test_class.py | 281 +++ .../tests/test_cmake_build/CMakeLists.txt | 58 + pybind11/tests/test_cmake_build/embed.cpp | 21 + .../installed_embed/CMakeLists.txt | 15 + .../installed_function/CMakeLists.txt | 12 + .../installed_target/CMakeLists.txt | 22 + pybind11/tests/test_cmake_build/main.cpp | 6 + .../subdirectory_embed/CMakeLists.txt | 25 + .../subdirectory_function/CMakeLists.txt | 8 + .../subdirectory_target/CMakeLists.txt | 15 + pybind11/tests/test_cmake_build/test.py | 5 + .../tests/test_constants_and_functions.cpp | 127 + .../tests/test_constants_and_functions.py | 39 + pybind11/tests/test_copy_move.cpp | 213 ++ pybind11/tests/test_copy_move.py | 112 + pybind11/tests/test_docstring_options.cpp | 61 + pybind11/tests/test_docstring_options.py | 38 + pybind11/tests/test_eigen.cpp | 329 +++ pybind11/tests/test_eigen.py | 694 ++++++ pybind11/tests/test_embed/CMakeLists.txt | 41 + pybind11/tests/test_embed/catch.cpp | 22 + pybind11/tests/test_embed/external_module.cpp | 23 + .../tests/test_embed/test_interpreter.cpp | 284 +++ pybind11/tests/test_embed/test_interpreter.py | 9 + pybind11/tests/test_enum.cpp | 85 + pybind11/tests/test_enum.py | 167 ++ pybind11/tests/test_eval.cpp | 91 + pybind11/tests/test_eval.py | 17 + pybind11/tests/test_eval_call.py | 4 + pybind11/tests/test_exceptions.cpp | 168 ++ pybind11/tests/test_exceptions.py | 144 ++ pybind11/tests/test_factory_constructors.cpp | 338 +++ pybind11/tests/test_factory_constructors.py | 459 ++++ pybind11/tests/test_gil_scoped.cpp | 43 + pybind11/tests/test_gil_scoped.py | 80 + pybind11/tests/test_iostream.cpp | 73 + pybind11/tests/test_iostream.py | 214 ++ pybind11/tests/test_kwargs_and_defaults.cpp | 100 + pybind11/tests/test_kwargs_and_defaults.py | 147 ++ pybind11/tests/test_local_bindings.cpp | 101 + pybind11/tests/test_local_bindings.py | 226 ++ .../tests/test_methods_and_attributes.cpp | 454 ++++ pybind11/tests/test_methods_and_attributes.py | 512 ++++ pybind11/tests/test_modules.cpp | 98 + pybind11/tests/test_modules.py | 72 + pybind11/tests/test_multiple_inheritance.cpp | 220 ++ pybind11/tests/test_multiple_inheritance.py | 349 +++ pybind11/tests/test_numpy_array.cpp | 304 +++ pybind11/tests/test_numpy_array.py | 416 ++++ pybind11/tests/test_numpy_dtypes.cpp | 466 ++++ pybind11/tests/test_numpy_dtypes.py | 310 +++ pybind11/tests/test_numpy_vectorize.cpp | 89 + pybind11/tests/test_numpy_vectorize.py | 196 ++ pybind11/tests/test_opaque_types.cpp | 67 + pybind11/tests/test_opaque_types.py | 46 + pybind11/tests/test_operator_overloading.cpp | 146 ++ pybind11/tests/test_operator_overloading.py | 106 + pybind11/tests/test_pickling.cpp | 130 + pybind11/tests/test_pickling.py | 42 + pybind11/tests/test_pytypes.cpp | 296 +++ pybind11/tests/test_pytypes.py | 253 ++ .../tests/test_sequences_and_iterators.cpp | 334 +++ .../tests/test_sequences_and_iterators.py | 158 ++ pybind11/tests/test_smart_ptr.cpp | 364 +++ pybind11/tests/test_smart_ptr.py | 285 +++ pybind11/tests/test_stl.cpp | 284 +++ pybind11/tests/test_stl.py | 239 ++ pybind11/tests/test_stl_binders.cpp | 107 + pybind11/tests/test_stl_binders.py | 205 ++ pybind11/tests/test_tagbased_polymorphic.cpp | 136 ++ pybind11/tests/test_tagbased_polymorphic.py | 20 + pybind11/tests/test_virtual_functions.cpp | 478 ++++ pybind11/tests/test_virtual_functions.py | 377 +++ pybind11/tools/FindCatch.cmake | 57 + pybind11/tools/FindEigen3.cmake | 81 + pybind11/tools/FindPythonLibsNew.cmake | 198 ++ pybind11/tools/check-style.sh | 70 + pybind11/tools/libsize.py | 38 + pybind11/tools/mkdoc.py | 304 +++ pybind11/tools/pybind11Config.cmake.in | 100 + pybind11/tools/pybind11Tools.cmake | 223 ++ ref/PythonGraphPers_withCompInfo.so | Bin 0 -> 4463808 bytes ref/compile_pers_lib.sh | 3 + ref/pythonGraphTopoFix_withCompInfo.cpp | 1547 ++++++++++++ runSSDA.sh | 7 + runUDA.sh | 47 + train_covid.py | 512 ++++ train_target.py | 443 ++++ utils.py | 547 +++++ 224 files changed, 45831 insertions(+) create mode 100644 README.md create mode 100644 common/__init__.py create mode 100644 common/__pycache__/__init__.cpython-37.pyc create mode 100644 common/modules/__init__.py create mode 100644 common/modules/__pycache__/__init__.cpython-37.pyc create mode 100644 common/modules/__pycache__/classifier.cpython-37.pyc create mode 100644 common/modules/classifier.py create mode 100644 common/vision/__init__.py create mode 100644 common/vision/__pycache__/__init__.cpython-37.pyc create mode 100644 common/vision/models/__init__.py create mode 100644 common/vision/models/__pycache__/__init__.cpython-37.pyc create mode 100644 common/vision/models/__pycache__/resnet.cpython-37.pyc create mode 100644 common/vision/models/resnet.py create mode 100644 common/vision/transforms/__init__.py create mode 100644 common/vision/transforms/__pycache__/__init__.cpython-37.pyc create mode 100644 config/config.yml create mode 100644 data/__pycache__/dataset.cpython-37.pyc create mode 100644 data/__pycache__/prepare_data.cpython-37.pyc create mode 100644 data/__pycache__/randaugment.cpython-37.pyc create mode 100644 data/dataset.py create mode 100644 data/prepare_data.py create mode 100644 data/randaugment.py create mode 100644 lr_schedule.py create mode 100644 main.py create mode 100644 main_covid.py create mode 100644 metric/__init__.py create mode 100644 metric/__pycache__/__init__.cpython-37.pyc create mode 100644 model/WideResNet.py create mode 100644 model/__pycache__/WideResNet.cpython-37.pyc create mode 100644 model/__pycache__/contrastive_loss.cpython-37.pyc create mode 100644 model/__pycache__/key_memory.cpython-37.pyc create mode 100644 model/__pycache__/model_ljz.cpython-37.pyc create mode 100644 model/__pycache__/resnet.cpython-37.pyc create mode 100644 model/__pycache__/utils.cpython-37.pyc create mode 100644 model/contrastive_loss.py create mode 100644 model/key_memory.py create mode 100644 model/model.py create mode 100644 model/resnet.py create mode 100644 model/utils.py create mode 100644 pseudo_labeler.py create mode 100644 pybind11/CMakeLists.txt create mode 100644 pybind11/CONTRIBUTING.md create mode 100644 pybind11/ISSUE_TEMPLATE.md create mode 100644 pybind11/LICENSE create mode 100644 pybind11/MANIFEST.in create mode 100644 pybind11/README.md create mode 100644 pybind11/docs/Doxyfile create mode 100644 pybind11/docs/_static/theme_overrides.css create mode 100644 pybind11/docs/advanced/cast/chrono.rst create mode 100644 pybind11/docs/advanced/cast/custom.rst create mode 100644 pybind11/docs/advanced/cast/eigen.rst create mode 100644 pybind11/docs/advanced/cast/functional.rst create mode 100644 pybind11/docs/advanced/cast/index.rst create mode 100644 pybind11/docs/advanced/cast/overview.rst create mode 100644 pybind11/docs/advanced/cast/stl.rst create mode 100644 pybind11/docs/advanced/cast/strings.rst create mode 100644 pybind11/docs/advanced/classes.rst create mode 100644 pybind11/docs/advanced/embedding.rst create mode 100644 pybind11/docs/advanced/exceptions.rst create mode 100644 pybind11/docs/advanced/functions.rst create mode 100644 pybind11/docs/advanced/misc.rst create mode 100644 pybind11/docs/advanced/pycpp/index.rst create mode 100644 pybind11/docs/advanced/pycpp/numpy.rst create mode 100644 pybind11/docs/advanced/pycpp/object.rst create mode 100644 pybind11/docs/advanced/pycpp/utilities.rst create mode 100644 pybind11/docs/advanced/smart_ptrs.rst create mode 100644 pybind11/docs/basics.rst create mode 100644 pybind11/docs/benchmark.py create mode 100644 pybind11/docs/benchmark.rst create mode 100644 pybind11/docs/changelog.rst create mode 100644 pybind11/docs/classes.rst create mode 100644 pybind11/docs/compiling.rst create mode 100644 pybind11/docs/conf.py create mode 100644 pybind11/docs/faq.rst create mode 100644 pybind11/docs/index.rst create mode 100644 pybind11/docs/intro.rst create mode 100644 pybind11/docs/limitations.rst create mode 100644 pybind11/docs/pybind11-logo.png create mode 100644 pybind11/docs/pybind11_vs_boost_python1.png create mode 100644 pybind11/docs/pybind11_vs_boost_python1.svg create mode 100644 pybind11/docs/pybind11_vs_boost_python2.png create mode 100644 pybind11/docs/pybind11_vs_boost_python2.svg create mode 100644 pybind11/docs/reference.rst create mode 100644 pybind11/docs/release.rst create mode 100644 pybind11/docs/requirements.txt create mode 100644 pybind11/docs/upgrade.rst create mode 100644 pybind11/include/pybind11/attr.h create mode 100644 pybind11/include/pybind11/buffer_info.h create mode 100644 pybind11/include/pybind11/cast.h create mode 100644 pybind11/include/pybind11/chrono.h create mode 100644 pybind11/include/pybind11/common.h create mode 100644 pybind11/include/pybind11/complex.h create mode 100644 pybind11/include/pybind11/detail/class.h create mode 100644 pybind11/include/pybind11/detail/common.h create mode 100644 pybind11/include/pybind11/detail/descr.h create mode 100644 pybind11/include/pybind11/detail/init.h create mode 100644 pybind11/include/pybind11/detail/internals.h create mode 100644 pybind11/include/pybind11/detail/typeid.h create mode 100644 pybind11/include/pybind11/eigen.h create mode 100644 pybind11/include/pybind11/embed.h create mode 100644 pybind11/include/pybind11/eval.h create mode 100644 pybind11/include/pybind11/functional.h create mode 100644 pybind11/include/pybind11/iostream.h create mode 100644 pybind11/include/pybind11/numpy.h create mode 100644 pybind11/include/pybind11/operators.h create mode 100644 pybind11/include/pybind11/options.h create mode 100644 pybind11/include/pybind11/pybind11.h create mode 100644 pybind11/include/pybind11/pytypes.h create mode 100644 pybind11/include/pybind11/stl.h create mode 100644 pybind11/include/pybind11/stl_bind.h create mode 100644 pybind11/pybind11/__init__.py create mode 100644 pybind11/pybind11/__main__.py create mode 100644 pybind11/pybind11/_version.py create mode 100644 pybind11/setup.cfg create mode 100644 pybind11/setup.py create mode 100644 pybind11/tests/CMakeLists.txt create mode 100644 pybind11/tests/conftest.py create mode 100644 pybind11/tests/constructor_stats.h create mode 100644 pybind11/tests/local_bindings.h create mode 100644 pybind11/tests/object.h create mode 100644 pybind11/tests/pybind11_cross_module_tests.cpp create mode 100644 pybind11/tests/pybind11_tests.cpp create mode 100644 pybind11/tests/pybind11_tests.h create mode 100644 pybind11/tests/pytest.ini create mode 100644 pybind11/tests/test_buffers.cpp create mode 100644 pybind11/tests/test_buffers.py create mode 100644 pybind11/tests/test_builtin_casters.cpp create mode 100644 pybind11/tests/test_builtin_casters.py create mode 100644 pybind11/tests/test_call_policies.cpp create mode 100644 pybind11/tests/test_call_policies.py create mode 100644 pybind11/tests/test_callbacks.cpp create mode 100644 pybind11/tests/test_callbacks.py create mode 100644 pybind11/tests/test_chrono.cpp create mode 100644 pybind11/tests/test_chrono.py create mode 100644 pybind11/tests/test_class.cpp create mode 100644 pybind11/tests/test_class.py create mode 100644 pybind11/tests/test_cmake_build/CMakeLists.txt create mode 100644 pybind11/tests/test_cmake_build/embed.cpp create mode 100644 pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt create mode 100644 pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt create mode 100644 pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt create mode 100644 pybind11/tests/test_cmake_build/main.cpp create mode 100644 pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt create mode 100644 pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt create mode 100644 pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt create mode 100644 pybind11/tests/test_cmake_build/test.py create mode 100644 pybind11/tests/test_constants_and_functions.cpp create mode 100644 pybind11/tests/test_constants_and_functions.py create mode 100644 pybind11/tests/test_copy_move.cpp create mode 100644 pybind11/tests/test_copy_move.py create mode 100644 pybind11/tests/test_docstring_options.cpp create mode 100644 pybind11/tests/test_docstring_options.py create mode 100644 pybind11/tests/test_eigen.cpp create mode 100644 pybind11/tests/test_eigen.py create mode 100644 pybind11/tests/test_embed/CMakeLists.txt create mode 100644 pybind11/tests/test_embed/catch.cpp create mode 100644 pybind11/tests/test_embed/external_module.cpp create mode 100644 pybind11/tests/test_embed/test_interpreter.cpp create mode 100644 pybind11/tests/test_embed/test_interpreter.py create mode 100644 pybind11/tests/test_enum.cpp create mode 100644 pybind11/tests/test_enum.py create mode 100644 pybind11/tests/test_eval.cpp create mode 100644 pybind11/tests/test_eval.py create mode 100644 pybind11/tests/test_eval_call.py create mode 100644 pybind11/tests/test_exceptions.cpp create mode 100644 pybind11/tests/test_exceptions.py create mode 100644 pybind11/tests/test_factory_constructors.cpp create mode 100644 pybind11/tests/test_factory_constructors.py create mode 100644 pybind11/tests/test_gil_scoped.cpp create mode 100644 pybind11/tests/test_gil_scoped.py create mode 100644 pybind11/tests/test_iostream.cpp create mode 100644 pybind11/tests/test_iostream.py create mode 100644 pybind11/tests/test_kwargs_and_defaults.cpp create mode 100644 pybind11/tests/test_kwargs_and_defaults.py create mode 100644 pybind11/tests/test_local_bindings.cpp create mode 100644 pybind11/tests/test_local_bindings.py create mode 100644 pybind11/tests/test_methods_and_attributes.cpp create mode 100644 pybind11/tests/test_methods_and_attributes.py create mode 100644 pybind11/tests/test_modules.cpp create mode 100644 pybind11/tests/test_modules.py create mode 100644 pybind11/tests/test_multiple_inheritance.cpp create mode 100644 pybind11/tests/test_multiple_inheritance.py create mode 100644 pybind11/tests/test_numpy_array.cpp create mode 100644 pybind11/tests/test_numpy_array.py create mode 100644 pybind11/tests/test_numpy_dtypes.cpp create mode 100644 pybind11/tests/test_numpy_dtypes.py create mode 100644 pybind11/tests/test_numpy_vectorize.cpp create mode 100644 pybind11/tests/test_numpy_vectorize.py create mode 100644 pybind11/tests/test_opaque_types.cpp create mode 100644 pybind11/tests/test_opaque_types.py create mode 100644 pybind11/tests/test_operator_overloading.cpp create mode 100644 pybind11/tests/test_operator_overloading.py create mode 100644 pybind11/tests/test_pickling.cpp create mode 100644 pybind11/tests/test_pickling.py create mode 100644 pybind11/tests/test_pytypes.cpp create mode 100644 pybind11/tests/test_pytypes.py create mode 100644 pybind11/tests/test_sequences_and_iterators.cpp create mode 100644 pybind11/tests/test_sequences_and_iterators.py create mode 100644 pybind11/tests/test_smart_ptr.cpp create mode 100644 pybind11/tests/test_smart_ptr.py create mode 100644 pybind11/tests/test_stl.cpp create mode 100644 pybind11/tests/test_stl.py create mode 100644 pybind11/tests/test_stl_binders.cpp create mode 100644 pybind11/tests/test_stl_binders.py create mode 100644 pybind11/tests/test_tagbased_polymorphic.cpp create mode 100644 pybind11/tests/test_tagbased_polymorphic.py create mode 100644 pybind11/tests/test_virtual_functions.cpp create mode 100644 pybind11/tests/test_virtual_functions.py create mode 100644 pybind11/tools/FindCatch.cmake create mode 100644 pybind11/tools/FindEigen3.cmake create mode 100644 pybind11/tools/FindPythonLibsNew.cmake create mode 100644 pybind11/tools/check-style.sh create mode 100644 pybind11/tools/libsize.py create mode 100644 pybind11/tools/mkdoc.py create mode 100644 pybind11/tools/pybind11Config.cmake.in create mode 100644 pybind11/tools/pybind11Tools.cmake create mode 100644 ref/PythonGraphPers_withCompInfo.so create mode 100644 ref/compile_pers_lib.sh create mode 100644 ref/pythonGraphTopoFix_withCompInfo.cpp create mode 100644 runSSDA.sh create mode 100644 runUDA.sh create mode 100644 train_covid.py create mode 100644 train_target.py create mode 100644 utils.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..5154a27 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +## NaCL:Noise-Robust Cross-Domain Contrastive Learning for Unsupervised Domain Adaptation + +### Introduction +This is a PyTorch implementation of ["NaCL:Noise-Robust Cross-Domain Contrastive Learning for Unsupervised Domain Adaptation"]. + +### Requirements +* Python 3.7 +* torchvision 0.9.0 +* PyTorch 1.8.0 + + +### Train: + +- Unsupervised DA on `Office31`,`OfficeHome`, and `VisDA2017` datasets: + ```bash + sh runUDA.sh + ``` +- Semi-supervised DA on `COVID-19` dataset: + + ```bash + sh runSSDA.sh + ``` +### Log: + +- The training log will be generated in the folder with ``--log_dir``. We can visualize the training process through `tensorboard` as follows. + + ```bash + tensorboard --logdir=/log_dir/ --host= `host address` + ``` + +### Usage + +- We uploaded the file `PythonGraphPers_withCompInfo.so` for computing the `connected components`. If you need to generate it, you can compile the C++ code in folder `ref`, run `./compile_pers_lib.sh` (by default it requires Python 3.7. If you are using other Python versions, modify the command inside `compile_pers_lib.sh`). + +- `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. Our code will be further improved to make it cleaner and easier to use. + + +***Note***: Place the datasets in the corresponding data path. + + + diff --git a/common/__init__.py b/common/__init__.py new file mode 100644 index 0000000..5933f73 --- /dev/null +++ b/common/__init__.py @@ -0,0 +1 @@ +__all__ = ['modules', 'vision'] diff --git a/common/__pycache__/__init__.cpython-37.pyc b/common/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8fc0e64947479c4df95dd2bdb3714d2554826827 GIT binary patch literal 200 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 literal 0 HcmV?d00001 diff --git a/common/modules/classifier.py b/common/modules/classifier.py new file mode 100644 index 0000000..ef8a5a2 --- /dev/null +++ b/common/modules/classifier.py @@ -0,0 +1,125 @@ +from typing import Tuple, Optional, List, Dict +import torch.nn as nn +import torch +import torch.nn.functional as F +import math + +__all__ = ['Classifier'] +def initialize_layer(layer): + for m in layer.modules(): + if isinstance(m, (nn.BatchNorm2d, nn.BatchNorm1d)): + nn.init.constant_(m.weight, 1) + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.Linear): + nn.init.kaiming_normal_(m.weight) + nn.init.constant_(m.bias, 0) + +def initialize_layer2(layer): + for m in layer.modules(): + if isinstance(m, (nn.BatchNorm2d, nn.BatchNorm1d)): + nn.init.constant_(m.weight, 1) + # nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.Linear): + nn.init.kaiming_normal_(m.weight) + # nn.init.constant_(m.bias, 0) + +class Classifier(nn.Module): + """A generic Classifier class for domain adaptation. + + Args: + backbone (torch.nn.Module): Any backbone to extract 2-d features from data + num_classes (int): Number of classes + bottleneck (torch.nn.Module, optional): Any bottleneck layer. Use no bottleneck by default + bottleneck_dim (int, optional): Feature dimension of the bottleneck layer. Default: -1 + head (torch.nn.Module, optional): Any classifier head. Use :class:`torch.nn.Linear` by default + finetune (bool): Whether finetune the classifier or train from scratch. Default: True + + .. note:: + Different classifiers are used in different domain adaptation algorithms to achieve better accuracy + respectively, and we provide a suggested `Classifier` for different algorithms. + Remember they are not the core of algorithms. You can implement your own `Classifier` and combine it with + the domain adaptation algorithm in this algorithm library. + + .. note:: + The learning rate of this classifier is set 10 times to that of the feature extractor for better accuracy + by default. If you have other optimization strategies, please over-ride :meth:`~Classifier.get_parameters`. + + Inputs: + - x (tensor): input data fed to `backbone` + + Outputs: + - predictions: classifier's predictions + - features: features after `bottleneck` layer and before `head` layer + + Shape: + - Inputs: (minibatch, *) where * means, any number of additional dimensions + - predictions: (minibatch, `num_classes`) + - features: (minibatch, `features_dim`) + + """ + + def __init__(self, backbone: nn.Module, num_classes: int, + bottleneck_dim: Optional[int] = -1, head: Optional[nn.Module] = None, finetune=True, pool_layer=None): + super(Classifier, self).__init__() + self.backbone = backbone + self.bottleneck_dim = bottleneck_dim + self.parameter_list = [{"params": self.backbone.parameters(), "lr": 1}] + self.num_classes = num_classes + if pool_layer is None: + self.pool_layer = nn.Sequential( + nn.AdaptiveAvgPool2d(output_size=(1, 1)), + nn.Flatten() + ) + else: + self.pool_layer = pool_layer + self.bottleneck = nn.Sequential( + nn.Linear(self.backbone.out_features, 256), + nn.BatchNorm1d(256), + nn.ReLU() + ) + initialize_layer(self.bottleneck) + self.parameter_list += [{"params": self.bottleneck.parameters(), "lr": 10}] + self.contrast_layer = nn.Sequential( + nn.Dropout(0.5), + nn.Linear(256, self.bottleneck_dim), + ) + initialize_layer(self.contrast_layer) + self.parameter_list += [{"params": self.contrast_layer.parameters(), "lr": 10}] + + self.classifier = nn.Sequential( + nn.Dropout(0.5), + nn.Linear(256, num_classes) + ) + + initialize_layer(self.classifier) + self.parameter_list += [{"params": self.classifier.parameters(), "lr": 10}] + + @property + def features_dim(self) -> int: + """The dimension of features before the final `head` layer""" + return self._features_dim + + def forward(self, x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: + """""" + end_points = {} + features = self.pool_layer(self.backbone(x)) + end_points['features'] = features + features=self.bottleneck(features) + end_points['norm_features'] = features + + contrast_features = self.contrast_layer(features) + contrast_features = F.normalize(contrast_features, p=2, dim=1) + end_points['contrast_features'] = contrast_features + logits = self.classifier(features) + end_points['logits'] = logits + + return end_points + + def weight_norm(self): + w = self.classifier[1].weight.data + norm = w.norm(p=2, dim=1, keepdim=True) + self.classifier[1].weight.data = w.div(norm.expand_as(w)) + + + def get_parameter_list(self): + return self.parameter_list diff --git a/common/vision/__init__.py b/common/vision/__init__.py new file mode 100644 index 0000000..aec3629 --- /dev/null +++ b/common/vision/__init__.py @@ -0,0 +1 @@ +__all__ = ['models', 'transforms'] diff --git a/common/vision/__pycache__/__init__.cpython-37.pyc b/common/vision/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..da9358f89332906c0f0024bc46c20358272c1517 GIT binary patch literal 213 zcmXv|OA5j;5KXP0QmFTEV{j>m*y2(|5I1gyXre}vMmnjW*YFhH#&y7zw{Ybs_~5-a z12b=?$g-3X9=E69)Bc`q4ehAbwNvEcZ4`|LLCuk!d0#g`c$I%61Nq!afi%Rg7_$|zHB)sr%VJJB}Z zlABwZ<#}$RC2v!13~n(|R=D!FZ5_+rI4GzYc?i%s2kNXf3lGb=j$w761nb~a>?q;Uf(u04)%U^cBNDQDo^hlB&|?C)*uUh_l#2&v NuggEFVT>ea^$U-OMKb^Z literal 0 HcmV?d00001 diff --git a/common/vision/models/__pycache__/resnet.cpython-37.pyc b/common/vision/models/__pycache__/resnet.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cbdf96c810a06618433a5340d7e751d8c0822801 GIT binary patch literal 7107 zcmeHMTW{RP6(+e{?uxovj%7PeQ^t+mY-{aBmqc+5!*&d(c5M}K6f|A5U?>iEmlBuU z%y4zX3MgO!X$vGTdC5Z`?8o-^6evKTPkqu~$Wy;FzjW&zrUg=|DlKeMLl;=#6M9nrLHiQX@T0->Y7S)F37d@x-Mxw$hVEU zA?bWjXcz0n_E>$aZPrcMrUm2mab~arE3z?WvT-)SCfO95ZkqLpj}L|40h`X&V zU-(g2Zb!@uM45Xc^y0F4$LYqch~Kmxb;D-Y37gg(Q-Bo5{dED6RTdF6jL5+D}8ElsZT9eld-I~S{snd3(2%>-HDg0_Ts|M5=&;X zhFY~oEh{XU-u9Vir?W9^A(qK+^I~X2n$uL#A;7@rfq0FwWocps!C7U$ZhC7#m+MY z?@?DvMv@oZj>qL2lcH_=pJqBY!P+z;)B=fqtIB$>3q!Qc^a>B0*diSFX-cSUTII&nwD z{+4G4kq{WwZbxAy)yhh$Je3rca%Y#%;@d9JM@sptv+CY-DyedxeOE&_U34dze1sy_ zQ1z7ON>6>E?n5%q)d2+wWo@|ur4Ok5fHDSDA){21W1^IbNgm&^RZDW~VJ*?Q7j%lT?^$at&tiVt3&{akQNset9a6On_mav<)VL9c zN7?qz%az51gJ!;d!FfpFUCHOC?VKTE0*9!v79)Jz;62hD? zmzGFS3ldFH)wKz|curGibT^L%x{4^I`{O9$DXJJc-P0OcFaNc=Z}f6}wP!q6UnqZ3 zVlB?~l*>v_XX;nleqrdDdWGlu3+2A@Ox-W^jE#J+K%VL=>~=i^I&F~SrjKfJPly3_ zgd4q@L@nM%|M!Ra`_fE2PY7>%foRGNZ&=wF|TB#Ud$ZsFP!-0r1DAL zkG-}?rjP7EFkJXBx0U4A<<66usz}TZjEFma=rO)bi(Hb6NM}@^9(KxYOnw4D{E!Bw zhMTdxgcdP_N>Qg&T`kg2n*+`7qwT@kz*7;Udvymn7*y> zuUfZSaoiC%D;0vOvkGDU!O}YAAxcZxtqIV5NVZFBw zXIHvuJ#1KOyzAYtQa>atCu0y}=QE*F>>)Y9c0RIJs%|f@#C*|#6Q!m4I*AyDlgA=Q z!J_SufJHcCiI`zOlWTIalta=YxL6W6C*3XO_&uTrunr9|wLqG62PNHLigW4-P|Cr2 zv?D0xM^Rc_Iz#Cgl*Sh6%f>cH+Qm8p|Oyu%Eai^@+ zQQXIzl@Z*L2_fKD*ctFboFoi=3_$o3swh*$SE-t!YPg9$#N(-aGR^-h$_d~m_t7_V zn0F55jiVk+Tt8yo1?NKq%fCYsjLa4m2@{`xg_rJ+NKY3hu-xi$x%xqE>HY6nF6AE5 zgNrX@6fbb@wj7bY+wyi?uY*(s&MXw;uMbj!R@iN?douWUTMn{efso<;cFT8L7A>~z zyB^YGyopgrAb49I-?iicuPjp@FE2pDkgdS@+D=WbM(La==#sM%a#8R=9Nw_Jae9+Q4o~w$q>E*I-msjI(S*JT2SOgqt5p}4`24i#6DOCv4)KXu^80wL33$>mpc zLkJ=AT{@<7Iugj7886XlNOn3hT}kPwG>bwJ2B%Xur=uK~#|sKM)9^*^Y|;TpK@GB; s!$e;M1& literal 0 HcmV?d00001 diff --git a/common/vision/models/resnet.py b/common/vision/models/resnet.py new file mode 100644 index 0000000..59b15f7 --- /dev/null +++ b/common/vision/models/resnet.py @@ -0,0 +1,180 @@ + +import torch.nn as nn +from torchvision import models +from torchvision.models.utils import load_state_dict_from_url +from torchvision.models.resnet import BasicBlock, Bottleneck, model_urls +import copy + +__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', + 'resnet152', 'resnext50_32x4d', 'resnext101_32x8d', + 'wide_resnet50_2', 'wide_resnet101_2'] + + +class ResNet(models.ResNet): + """ResNets without fully connected layer""" + + def __init__(self, *args, **kwargs): + super(ResNet, self).__init__(*args, **kwargs) + self._out_features = self.fc.in_features + + def forward(self, x): + """""" + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + x = self.maxpool(x) + + x = self.layer1(x) + x = self.layer2(x) + x = self.layer3(x) + x = self.layer4(x) + + # x = self.avgpool(x) + # x = torch.flatten(x, 1) + # x = x.view(-1, self._out_features) + return x + + @property + def out_features(self) -> int: + """The dimension of output features""" + return self._out_features + + def copy_head(self) -> nn.Module: + """Copy the origin fully connected layer""" + return copy.deepcopy(self.fc) + + +def _resnet(arch, block, layers, pretrained, progress, **kwargs): + model = ResNet(block, layers, **kwargs) + if pretrained: + model_dict = model.state_dict() + pretrained_dict = load_state_dict_from_url(model_urls[arch], + progress=progress) + # remove keys from pretrained dict that doesn't appear in model dict + pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict} + model.load_state_dict(pretrained_dict, strict=False) + return model + + +def resnet18(pretrained=False, progress=True, **kwargs): + r"""ResNet-18 model from + `"Deep Residual Learning for Image Recognition" `_ + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], pretrained, progress, + **kwargs) + + +def resnet34(pretrained=False, progress=True, **kwargs): + r"""ResNet-34 model from + `"Deep Residual Learning for Image Recognition" `_ + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], pretrained, progress, + **kwargs) + + +def resnet50(pretrained=False, progress=True, **kwargs): + r"""ResNet-50 model from + `"Deep Residual Learning for Image Recognition" `_ + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, progress, + **kwargs) + + +def resnet101(pretrained=False, progress=True, **kwargs): + r"""ResNet-101 model from + `"Deep Residual Learning for Image Recognition" `_ + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], pretrained, progress, + **kwargs) + + +def resnet152(pretrained=False, progress=True, **kwargs): + r"""ResNet-152 model from + `"Deep Residual Learning for Image Recognition" `_ + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], pretrained, progress, + **kwargs) + + +def resnext50_32x4d(pretrained=False, progress=True, **kwargs): + r"""ResNeXt-50 32x4d model from + `"Aggregated Residual Transformation for Deep Neural Networks" `_ + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + kwargs['groups'] = 32 + kwargs['width_per_group'] = 4 + return _resnet('resnext50_32x4d', Bottleneck, [3, 4, 6, 3], + pretrained, progress, **kwargs) + + +def resnext101_32x8d(pretrained=False, progress=True, **kwargs): + r"""ResNeXt-101 32x8d model from + `"Aggregated Residual Transformation for Deep Neural Networks" `_ + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + kwargs['groups'] = 32 + kwargs['width_per_group'] = 8 + return _resnet('resnext101_32x8d', Bottleneck, [3, 4, 23, 3], + pretrained, progress, **kwargs) + + +def wide_resnet50_2(pretrained=False, progress=True, **kwargs): + r"""Wide ResNet-50-2 model from + `"Wide Residual Networks" `_ + + The model is the same as ResNet except for the bottleneck number of channels + which is twice larger in every block. The number of channels in outer 1x1 + convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048 + channels, and in Wide ResNet-50-2 has 2048-1024-2048. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + kwargs['width_per_group'] = 64 * 2 + return _resnet('wide_resnet50_2', Bottleneck, [3, 4, 6, 3], + pretrained, progress, **kwargs) + + +def wide_resnet101_2(pretrained=False, progress=True, **kwargs): + r"""Wide ResNet-101-2 model from + `"Wide Residual Networks" `_ + + The model is the same as ResNet except for the bottleneck number of channels + which is twice larger in every block. The number of channels in outer 1x1 + convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048 + channels, and in Wide ResNet-50-2 has 2048-1024-2048. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + kwargs['width_per_group'] = 64 * 2 + return _resnet('wide_resnet101_2', Bottleneck, [3, 4, 23, 3], + pretrained, progress, **kwargs) diff --git a/common/vision/transforms/__init__.py b/common/vision/transforms/__init__.py new file mode 100644 index 0000000..f4935f1 --- /dev/null +++ b/common/vision/transforms/__init__.py @@ -0,0 +1,182 @@ +import math +import random +from PIL import Image +import numpy as np +import torch +from torchvision.transforms import Normalize + + +class ResizeImage(object): + """Resize the input PIL Image to the given size. + + Args: + size (sequence or int): Desired output size. If size is a sequence like + (h, w), output size will be matched to this. If size is an int, + output size will be (size, size) + """ + + def __init__(self, size): + if isinstance(size, int): + self.size = (int(size), int(size)) + else: + self.size = size + + def __call__(self, img): + th, tw = self.size + return img.resize((th, tw)) + + def __repr__(self): + return self.__class__.__name__ + '(size={0})'.format(self.size) + + +class MultipleApply: + """Apply a list of transformations to an image and get multiple transformed images. + + Args: + transforms (list or tuple): list of transformations + + Example: + + >>> transform1 = T.Compose([ + ... ResizeImage(256), + ... T.RandomCrop(224) + ... ]) + >>> transform2 = T.Compose([ + ... ResizeImage(256), + ... T.RandomCrop(224), + ... ]) + >>> multiply_transform = MultipleApply([transform1, transform2]) + """ + + def __init__(self, transforms): + self.transforms = transforms + + def __call__(self, image): + return [t(image) for t in self.transforms] + + def __repr__(self): + format_string = self.__class__.__name__ + '(' + for t in self.transforms: + format_string += '\n' + format_string += ' {0}'.format(t) + format_string += '\n)' + return format_string + + +class Denormalize(Normalize): + """DeNormalize a tensor image with mean and standard deviation. + Given mean: ``(mean[1],...,mean[n])`` and std: ``(std[1],..,std[n])`` for ``n`` + channels, this transform will denormalize each channel of the input + ``torch.*Tensor`` i.e., + ``output[channel] = input[channel] * std[channel] + mean[channel]`` + + .. note:: + This transform acts out of place, i.e., it does not mutate the input tensor. + + Args: + mean (sequence): Sequence of means for each channel. + std (sequence): Sequence of standard deviations for each channel. + + """ + + def __init__(self, mean, std): + mean = np.array(mean) + std = np.array(std) + super().__init__((-mean / std).tolist(), (1 / std).tolist()) + + +class NormalizeAndTranspose: + """ + First, normalize a tensor image with mean and standard deviation. + Then, convert the shape (H x W x C) to shape (C x H x W). + """ + + def __init__(self, mean=(104.00698793, 116.66876762, 122.67891434)): + self.mean = np.array(mean, dtype=np.float32) + + def __call__(self, image): + if isinstance(image, Image.Image): + image = np.asarray(image, np.float32) + # change to BGR + image = image[:, :, ::-1] + # normalize + image -= self.mean + image = image.transpose((2, 0, 1)).copy() + elif isinstance(image, torch.Tensor): + # change to BGR + image = image[:, :, [2, 1, 0]] + # normalize + image -= torch.from_numpy(self.mean).to(image.device) + image = image.permute((2, 0, 1)) + else: + raise NotImplementedError(type(image)) + return image + + +class DeNormalizeAndTranspose: + """ + First, convert a tensor image from the shape (C x H x W ) to shape (H x W x C). + Then, denormalize it with mean and standard deviation. + """ + + def __init__(self, mean=(104.00698793, 116.66876762, 122.67891434)): + self.mean = np.array(mean, dtype=np.float32) + + def __call__(self, image): + image = image.transpose((1, 2, 0)) + # denormalize + image += self.mean + # change to RGB + image = image[:, :, ::-1] + return image + + +class RandomErasing(object): + """Random erasing augmentation from `Random Erasing Data Augmentation (CVPR 2017) + `_. This augmentation randomly selects a rectangle region in an image + and erases its pixels. + + Args: + probability (float): The probability that the Random Erasing operation will be performed. + sl (float): Minimum proportion of erased area against input image. + sh (float): Maximum proportion of erased area against input image. + r1 (float): Minimum aspect ratio of erased area. + mean (sequence): Value to fill the erased area. + """ + + def __init__(self, probability=0.5, sl=0.02, sh=0.4, r1=0.3, mean=(0.4914, 0.4822, 0.4465)): + self.probability = probability + self.mean = mean + self.sl = sl + self.sh = sh + self.r1 = r1 + + def __call__(self, img): + + if random.uniform(0, 1) >= self.probability: + return img + + for attempt in range(100): + area = img.size()[1] * img.size()[2] + + target_area = random.uniform(self.sl, self.sh) * area + aspect_ratio = random.uniform(self.r1, 1 / self.r1) + + h = int(round(math.sqrt(target_area * aspect_ratio))) + w = int(round(math.sqrt(target_area / aspect_ratio))) + + if w < img.size()[2] and h < img.size()[1]: + x1 = random.randint(0, img.size()[1] - h) + y1 = random.randint(0, img.size()[2] - w) + if img.size()[0] == 3: + img[0, x1:x1 + h, y1:y1 + w] = self.mean[0] + img[1, x1:x1 + h, y1:y1 + w] = self.mean[1] + img[2, x1:x1 + h, y1:y1 + w] = self.mean[2] + else: + img[0, x1:x1 + h, y1:y1 + w] = self.mean[0] + return img + + return img + + def __repr__(self): + return self.__class__.__name__ + '(p={})'.format(self.probability) diff --git a/common/vision/transforms/__pycache__/__init__.cpython-37.pyc b/common/vision/transforms/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..78146a12ad30cd93d745138f9818a4fc7fea2b7f GIT binary patch literal 7188 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 Yn@KUuj5%zcFh_GkxuGlqgo!Zm4-ldwD*ylh literal 0 HcmV?d00001 diff --git a/data/dataset.py b/data/dataset.py new file mode 100644 index 0000000..c735c85 --- /dev/null +++ b/data/dataset.py @@ -0,0 +1,285 @@ +# coding: utf-8 +from __future__ import print_function +from PIL import Image +import os +import os.path +import torch +import pickle as pkl +from torch.utils.data import Dataset +import torchvision.datasets as datasets +from typing import Any, Callable, cast, Dict, List, Optional, Tuple + +class penuDataset(Dataset): + """ + Pneumonia class. + """ + + def __init__(self, root, label_file, train=True, transform=None): + super(penuDataset, self).__init__() + self.root = root + self.transform = transform + self.train = train # training set or test set + self.label_file = label_file + with open(self.label_file, 'rb') as f: + train_dict = pkl.load(f) + train_list = train_dict['train_list'] + val_list = train_dict['val_list'] + + # now load the picked numpy arrays + if self.train: + self.train_data = [] + self.train_labels = [] + for i in range(len(train_list)): + img = train_list[i][0] + if isinstance(img, bytes): + img = img.decode("utf-8") + self.train_data.append(os.path.join(self.root, 'train', img)) + self.train_labels.append(train_list[i][1]) + else: + self.test_data = [] + self.test_labels = [] + for i in range(len(val_list)): + img = val_list[i][0] + if isinstance(img, bytes): + img = img.decode("utf-8") + self.test_data.append(os.path.join(self.root, 'test', img)) + self.test_labels.append(val_list[i][1]) + + def __getitem__(self, index): + """ + Args: + index (int): Index + + Returns: + tuple: (image, target) where target is index of the target class. + """ + if self.train: + img_name, target = self.train_data[index], self.train_labels[index] + else: + img_name, target = self.test_data[index], self.test_labels[index] + + img = Image.open(img_name).convert('RGB') + + if self.transform is not None: + img = self.transform(img) + + return img, target + + def __len__(self): + if self.train: + return len(self.train_data) + else: + return len(self.test_data) + + +class covidDataset_target(Dataset): + """ + COVID-19 class + Args: + root (str): datapath + label_file (str): the pkl file that restore the list of data + semi (bool): If true, read the list of labeled target domain data + If false, read the list of unlabeled target domain data + train (bool): If true: load the training data + transform: the transformation which is employed on the data + """ + def __init__(self, root, label_file, semi=False, train=True, transform=None): + super(covidDataset_target, self).__init__() + self.root = root + self.transform = transform + self.train = train # training set or test set + self.label_file = label_file + with open(self.label_file, 'rb') as f: + train_dict = pkl.load(f) + if semi is True: + train_list = train_dict['train_list_labeled'] + else: + # train_list = train_dict['train_list'] + train_list = train_dict['train_list_unlabeled'] + val_list = train_dict['val_list'] + + # now load the picked numpy arrays + if self.train: + self.train_data = [] + self.train_labels = [] + for i in range(len(train_list)): + img = train_list[i][0] + if isinstance(img, bytes): + img = img.decode("utf-8") + self.train_data.append(os.path.join(self.root, 'train', img)) + self.train_labels.append(train_list[i][1]) + else: + self.test_data = [] + self.test_labels = [] + for i in range(len(val_list)): + img = val_list[i][0] + if isinstance(img, bytes): + img = img.decode("utf-8") + self.test_data.append(os.path.join(self.root, 'val', img)) + self.test_labels.append(val_list[i][1]) + + def __getitem__(self, index): + """ + Args: + index (int): Index + + Returns: + tuple: (image, target) where target is index of the target class. + """ + if self.train: + img_name, targets = self.train_data[index], self.train_labels[index] + else: + img_name, targets = self.test_data[index], self.test_labels[index] + + img = Image.open(img_name).convert('RGB') + + if self.transform is not None: + img = self.transform(img) + + return img, targets + + def __len__(self): + if self.train: + return len(self.train_data) + else: + return len(self.test_data) + + def __repr__(self): + fmt_str = 'Dataset ' + self.__class__.__name__ + '\n' + fmt_str += ' Number of datapoints: {}\n'.format(self.__len__()) + tmp = 'train' if self.train is True else 'test' + fmt_str += ' Split: {}\n'.format(tmp) + fmt_str += ' Root Location: {}\n'.format(self.root) + tmp = ' Transforms (if any): ' + fmt_str += '{0}{1}\n'.format(tmp, self.transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) + return fmt_str + +class covid_target(Dataset): + """ + COVID-19 class + """ + def __init__(self, root, label_file, train=True, transform=None): + super(covid_target, self).__init__() + self.root = root + self.transform = transform + self.train = train # training set or test set + self.label_file = label_file + with open(self.label_file, 'rb') as f: + train_dict = pkl.load(f) + # train_list = train_dict['train_list_semi'] + train_dict['train_list'] + # load the test list + val_list = train_dict['test_list'] + + # now load the picked numpy arrays + if self.train: + self.train_data = [] + self.train_labels = [] + for i in range(len(train_list)): + img = train_list[i][0] + if isinstance(img, bytes): + img = img.decode("utf-8") + self.train_data.append(os.path.join(self.root, 'train', img)) + self.train_labels.append(train_list[i][1]) + else: + self.test_data = [] + self.test_labels = [] + for i in range(len(val_list)): + img = val_list[i][0] + if isinstance(img, bytes): + img = img.decode("utf-8") + self.test_data.append(os.path.join(self.root, 'test', img)) + self.test_labels.append(val_list[i][1]) + + def __getitem__(self, index): + """ + Args: + index (int): Index + + Returns: + tuple: (image, target) where target is index of the target class. + """ + if self.train: + img_name, target = self.train_data[index], self.train_labels[index] + else: + img_name, target = self.test_data[index], self.test_labels[index] + + img = Image.open(img_name).convert('RGB') + + if self.transform is not None: + img = self.transform(img) + + return img, target + + def __len__(self): + if self.train: + return len(self.train_data) + else: + return len(self.test_data) + +IMG_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm', '.tif', '.tiff', '.webp') + + +def pil_loader(path: str) -> Image.Image: + # open path as file to avoid ResourceWarning (https://github.com/python-pillow/Pillow/issues/835) + with open(path, 'rb') as f: + img = Image.open(f) + return img.convert('RGB') + + +# TODO: specify the return type +def accimage_loader(path: str) -> Any: + import accimage + try: + return accimage.Image(path) + except IOError: + # Potentially a decoding problem, fall back to PIL.Image + return pil_loader(path) + +def default_loader(path: str) -> Any: + from torchvision import get_image_backend + if get_image_backend() == 'accimage': + return accimage_loader(path) + else: + return pil_loader(path) + +class build_dataset(datasets.DatasetFolder): + """ + COVID-19 class + """ + + def __init__( + self, + root: str, + transform: Optional[Callable] = None, + target_transform: Optional[Callable] = None, + loader: Callable[[str], Any] = default_loader, + is_valid_file: Optional[Callable[[str], bool]] = None, + pseude_labels=None + ): + super(build_dataset, self).__init__(root, loader, IMG_EXTENSIONS if is_valid_file is None else None, + transform=transform, + target_transform=target_transform, + is_valid_file=is_valid_file) + + + self.targets = pseude_labels + def __getitem__(self, index: int) -> Tuple[Any, Any]: + """ + Args: + index (int): Index + + Returns: + tuple: (sample, target) where target is class_index of the target class. + """ + path, _ = self.samples[index] + target=self.targets[index] + sample = self.loader(path) + if self.transform is not None: + sample = self.transform(sample) + if self.target_transform is not None: + target = self.target_transform(target) + + return sample, target, index + + def __len__(self) -> int: + return len(self.samples) \ No newline at end of file diff --git a/data/prepare_data.py b/data/prepare_data.py new file mode 100644 index 0000000..853269a --- /dev/null +++ b/data/prepare_data.py @@ -0,0 +1,255 @@ +import os +import torch +import torchvision.transforms as transforms +import torchvision.datasets as datasets +from data.dataset import build_dataset + +import numpy as np +import cv2 +import random +from data.randaugment import RandAugment +import sys +#sys.path.append("..") +#import common.vision.datasets as datasets +from common.vision.transforms import ResizeImage, MultipleApply + +class Sampler(object): + def __init__(self, data_source): + pass + + def __iter__(self): + raise NotImplementedError + + def __len__(self): + raise NotImplementedError + +class UniformBatchSampler(Sampler): + def __init__(self, per_category, category_index_list, imgs): + self.per_category = per_category + self.category_index_list = category_index_list + self.imgs = imgs + self.batch_size = per_category * len(category_index_list) + self.batch_num = len(self.imgs) // self.batch_size + def __iter__(self): + for bat in range(self.batch_num): + batch = [] + for i in range(len(self.category_index_list)): + batch = batch + random.sample(self.category_index_list[i], self.per_category) + random.shuffle(batch) + yield batch + + def __len__(self): + return self.batch_num + +########################################## function for MEC +def _random_affine_augmentation(x): + M = np.float32([[1 + np.random.normal(0.0, 0.1), np.random.normal(0.0, 0.1), 0], + [np.random.normal(0.0, 0.1), 1 + np.random.normal(0.0, 0.1), 0]]) + rows, cols = x.shape[1:3] + dst = cv2.warpAffine(np.transpose(x.numpy(), [1, 2, 0]), M, (cols,rows)) + dst = np.transpose(dst, [2, 0, 1]) + return torch.from_numpy(dst) + +def _gaussian_blur(x, sigma=0.1): + ksize = int(sigma + 0.5) * 8 + 1 + dst = cv2.GaussianBlur(x.numpy(), (ksize, ksize), sigma) + return torch.from_numpy(dst) + +############# To control the categorical weight of each batch. +def make_weights_for_balanced_classes(images, nclasses): + count = [0] * nclasses + for item in images: + count[item[1]] += 1 + weight_per_class = [0.] * nclasses + N = float(sum(count)) + for i in range(nclasses): + weight_per_class[i] = N/float(count[i]) + weight = [0] * len(images) + # weight_per_class[-1] = weight_per_class[-1] ########### adjust the cate-weight for unknown category. + for idx, val in enumerate(images): + weight[idx] = weight_per_class[val[1]] + return weight + +def _select_image_process(DATA_TRANSFORM_TYPE): + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + if DATA_TRANSFORM_TYPE == 'randomcrop': + transforms_train_weak = transforms.Compose([ + transforms.Resize(256), + transforms.RandomCrop(224), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + normalize, + ]) + transforms_train_strong = transforms.Compose([ + transforms.Resize(256), + transforms.RandomCrop(224), + transforms.RandomHorizontalFlip(), + RandAugment(2, 10), + transforms.ToTensor(), + normalize, + ]) + transforms_test = transforms.Compose([ + transforms.Resize(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + normalize, + ]) + + elif DATA_TRANSFORM_TYPE == 'randomsizedcrop': ## default image pro-process in DALIB: https://github.com/thuml/Transfer-Learning-Library + transforms_train_weak = transforms.Compose([ + transforms.Resize((256, 256)), + transforms.RandomResizedCrop(224), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + normalize + ]) + transforms_train_strong1 = transforms.Compose([ + transforms.Resize((256, 256)), + transforms.RandomResizedCrop(224), + transforms.RandomHorizontalFlip(), + RandAugment(2, 10), + transforms.ToTensor(), + normalize + ]) + transforms_train_strong2 = transforms.Compose([ + transforms.Resize((256, 256)), + transforms.RandomResizedCrop(224), + transforms.RandomHorizontalFlip(), + RandAugment(2, 10), + transforms.ToTensor(), + normalize + ]) + transforms_test = transforms.Compose([ + transforms.Resize((256, 256)), + transforms.CenterCrop(224), + transforms.ToTensor(), + normalize + ]) + elif DATA_TRANSFORM_TYPE == 'center': ## Only apply to VisDA-2017 dataset following DALIB + transforms_train_weak = transforms.Compose([ + transforms.Resize((256, 256)), + transforms.CenterCrop(224), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + normalize + ]) + transforms_train_strong1 = transforms.Compose([ + transforms.Resize((256, 256)), + transforms.CenterCrop(224), + transforms.RandomHorizontalFlip(), + RandAugment(2, 10), + transforms.ToTensor(), + normalize + ]) + transforms_train_strong2 = transforms.Compose([ + transforms.Resize((256, 256)), + transforms.CenterCrop(224), + transforms.RandomHorizontalFlip(), + RandAugment(2, 10), + transforms.ToTensor(), + normalize + ]) + transforms_test = transforms.Compose([ + transforms.Resize((256, 256)), + transforms.CenterCrop(224), + transforms.ToTensor(), + normalize + ]) + else: + raise NotImplementedError + + return transforms_train_weak, transforms_train_strong1, transforms_train_strong2, transforms_test + +def generate_dataloader_sc(data_root,source,target,batch_size,num_workers,transform_type): + dataloaders = {} + if data_root == '/home/LAB/lijz19/code/WUDA/AAAI2021/data1/domain_adaptation/Office31': + dataroot_S = os.path.join(os.path.join(data_root, source), 'images') + dataroot_T = os.path.join(os.path.join(data_root, target), 'images') + dataroot_V = os.path.join(os.path.join(data_root, target), 'images') + else: + dataroot_S = os.path.join(data_root, source) + dataroot_T = os.path.join(data_root, target) + dataroot_V = os.path.join(data_root, target) + + if not os.path.isdir(dataroot_S): + raise ValueError('Invalid path of source data!!!') + + transforms_train_weak, transforms_train_strong1,transforms_train_strong2, transforms_test = _select_image_process(transform_type) + ############ dataloader ############################# + source_train_dataset = datasets.ImageFolder( + dataroot_S, + transform=MultipleApply([transforms_train_weak, transforms_train_strong1,transforms_train_strong2]) + ) + source_train_loader = torch.utils.data.DataLoader( + source_train_dataset, batch_size=batch_size, shuffle=True, drop_last=True, + num_workers=num_workers, pin_memory=False + ) + target_train_dataset = datasets.ImageFolder( + dataroot_T, + transform=MultipleApply([transforms_train_weak, transforms_train_strong1,transforms_train_strong2]) + ) + target_train_loader = torch.utils.data.DataLoader( + target_train_dataset, + batch_size=batch_size, shuffle=True, drop_last=True, + num_workers=num_workers, pin_memory=False + ) + target_build_dataset = build_dataset(dataroot_T, transform=MultipleApply([transforms_train_weak, transforms_train_strong1,transforms_train_strong2])) + + + target_test_dataset = datasets.ImageFolder( + dataroot_V, + transforms_test + ) + target_test_loader = torch.utils.data.DataLoader( + target_test_dataset, + batch_size=500, shuffle=False, drop_last= False, + num_workers=num_workers, pin_memory=False + ) + + source_cluster_dataset = datasets.ImageFolder( + dataroot_S, + transforms_test + ) + target_cluster_dataset = datasets.ImageFolder( + dataroot_T, + transforms_test + ) + source_cluster_loader = torch.utils.data.DataLoader( + source_cluster_dataset, + batch_size=1000, shuffle=False, + num_workers=num_workers, pin_memory=False + ) + target_cluster_loader = torch.utils.data.DataLoader( + target_cluster_dataset, + batch_size=1000, shuffle=False, + num_workers=num_workers, pin_memory=False + ) + + dataloaders['src_train'] = source_train_loader + dataloaders['tgt_train'] = target_train_loader + dataloaders['tgt_data'] = target_build_dataset + + dataloaders['test'] = target_test_loader + dataloaders['src_test'] = source_cluster_loader + dataloaders['tgt_test'] = target_cluster_loader + dataloaders['tgt_conf'] = None + dataloaders['tgt_non_conf'] = None + + return dataloaders + + +def generate_category_index_list_imgs(imgs, num_classes): + # for i in range(len(train_t_dataset.imgs)): + # path = train_t_dataset.imgs[i][0] + # target = source_train_dataset.imgs[path] + # item = (path, target) + # images.append(item) + category_index_list = [] + for i in range(num_classes): + list_temp = [] + for j in range(len(imgs)): + if i == imgs[j][1]: + list_temp.append(j) + category_index_list.append(list_temp) + return category_index_list \ No newline at end of file diff --git a/data/randaugment.py b/data/randaugment.py new file mode 100644 index 0000000..59ef52e --- /dev/null +++ b/data/randaugment.py @@ -0,0 +1,222 @@ +# copyright: https://github.com/ildoonet/pytorch-randaugment +# code in this file is adpated from rpmcruz/autoaugment +# https://github.com/rpmcruz/autoaugment/blob/master/transformations.py +# This code is modified version of one of ildoonet, for randaugmentation of fixmatch. + +import random + +import PIL, PIL.ImageOps, PIL.ImageEnhance, PIL.ImageDraw +import numpy as np +import torch +from PIL import Image + + + +def AutoContrast(img, _): + return PIL.ImageOps.autocontrast(img) + + +def Brightness(img, v): + assert v >= 0.0 + return PIL.ImageEnhance.Brightness(img).enhance(v) + + +def Color(img, v): + assert v >= 0.0 + return PIL.ImageEnhance.Color(img).enhance(v) + + +def Contrast(img, v): + assert v >= 0.0 + return PIL.ImageEnhance.Contrast(img).enhance(v) + + +def Equalize(img, _): + return PIL.ImageOps.equalize(img) + + +def Invert(img, _): + return PIL.ImageOps.invert(img) + + +def Identity(img, v): + return img + + +def Posterize(img, v): # [4, 8] + v = int(v) + v = max(1, v) + return PIL.ImageOps.posterize(img, v) + + +def Rotate(img, v): # [-30, 30] + # assert -30 <= v <= 30 + # if random.random() > 0.5: + # v = -v + return img.rotate(v) + + +def Sharpness(img, v): # [0.1,1.9] + assert v >= 0.0 + return PIL.ImageEnhance.Sharpness(img).enhance(v) + + +def ShearX(img, v): # [-0.3, 0.3] + # assert -0.3 <= v <= 0.3 + # if random.random() > 0.5: + # v = -v + return img.transform(img.size, PIL.Image.AFFINE, (1, v, 0, 0, 1, 0)) + + +def ShearY(img, v): # [-0.3, 0.3] + # assert -0.3 <= v <= 0.3 + # if random.random() > 0.5: + # v = -v + return img.transform(img.size, PIL.Image.AFFINE, (1, 0, 0, v, 1, 0)) + + +def TranslateX(img, v): # [-150, 150] => percentage: [-0.45, 0.45] + # assert -0.3 <= v <= 0.3 + # if random.random() > 0.5: + # v = -v + v = v * img.size[0] + return img.transform(img.size, PIL.Image.AFFINE, (1, 0, v, 0, 1, 0)) + + +def TranslateXabs(img, v): # [-150, 150] => percentage: [-0.45, 0.45] + # assert v >= 0.0 + # if random.random() > 0.5: + # v = -v + return img.transform(img.size, PIL.Image.AFFINE, (1, 0, v, 0, 1, 0)) + + +def TranslateY(img, v): # [-150, 150] => percentage: [-0.45, 0.45] + # assert -0.3 <= v <= 0.3 + # if random.random() > 0.5: + # v = -v + v = v * img.size[1] + return img.transform(img.size, PIL.Image.AFFINE, (1, 0, 0, 0, 1, v)) + + +def TranslateYabs(img, v): # [-150, 150] => percentage: [-0.45, 0.45] + # assert 0 <= v + # if random.random() > 0.5: + # v = -v + return img.transform(img.size, PIL.Image.AFFINE, (1, 0, 0, 0, 1, v)) + + +def Solarize(img, v): # [0, 256] + assert 0 <= v <= 256 + return PIL.ImageOps.solarize(img, v) + + +def Cutout(img, v): # [0, 60] => percentage: [0, 0.2] => change to [0, 0.5] + assert 0.0 <= v <= 0.5 + if v <= 0.: + return img + + v = v * img.size[0] + return CutoutAbs(img, v) + + +def CutoutAbs(img, v): # [0, 60] => percentage: [0, 0.2] + # assert 0 <= v <= 20 + if v < 0: + return img + w, h = img.size + x0 = np.random.uniform(w) + y0 = np.random.uniform(h) + + x0 = int(max(0, x0 - v / 2.)) + y0 = int(max(0, y0 - v / 2.)) + x1 = min(w, x0 + v) + y1 = min(h, y0 + v) + + xy = (x0, y0, x1, y1) + color = (125, 123, 114) + # color = (0, 0, 0) + img = img.copy() + PIL.ImageDraw.Draw(img).rectangle(xy, color) + return img + +def CutoutAbs_onechannel(img, v): # [0, 60] => percentage: [0, 0.2] + # assert 0 <= v <= 20 + if v < 0: + return img + w, h = img.size + x0 = np.random.uniform(w) + y0 = np.random.uniform(h) + + x0 = int(max(0, x0 - v / 2.)) + y0 = int(max(0, y0 - v / 2.)) + x1 = min(w, x0 + v) + y1 = min(h, y0 + v) + + xy = (x0, y0, x1, y1) + color = (127) + # color = (0, 0, 0) + img = img.copy() + PIL.ImageDraw.Draw(img).rectangle(xy, color) + return img + + +def augment_list(): + l = [ + (AutoContrast, 0, 1), + (Brightness, 0.05, 0.95), + (Color, 0.05, 0.95), + (Contrast, 0.05, 0.95), + (Equalize, 0, 1), + (Identity, 0, 1), + (Posterize, 4, 8), + (Rotate, -30, 30), + (Sharpness, 0.05, 0.95), + (ShearX, -0.3, 0.3), + (ShearY, -0.3, 0.3), + (Solarize, 0, 256), + (TranslateX, -0.3, 0.3), + (TranslateY, -0.3, 0.3) + ] + return l + +####################### +## This is the setting of Fixmatch!!! +## The setting of UDA is different from that in Fixmatch, for example, invert is adopted in UDA but not in Fixmatch. +## For simpility, we also adopt the StrongAug in Fixmatch for UDA. +class RandAugment: + def __init__(self, n, m): + self.n = n + self.m = m # [0, 30] in fixmatch, deprecated. + self.augment_list = augment_list() + + def __call__(self, img): + ops = random.choices(self.augment_list, k=self.n) + for op, min_val, max_val in ops: + val = min_val + float(max_val - min_val) * random.random() + img = op(img, val) + cutout_val = random.random() * 0.5 + img = Cutout(img, cutout_val) # for fixmatch + return img + + +class RandAugment_onechannel: + def __init__(self, n, m): + self.n = n + self.m = m # [0, 30] in fixmatch, deprecated. + self.augment_list = augment_list() + + def __call__(self, img): + ops = random.choices(self.augment_list, k=self.n) + for op, min_val, max_val in ops: + val = min_val + float(max_val - min_val) * random.random() + img = op(img, val) + cutout_val = random.random() * 0.5 + img = CutoutAbs_onechannel(img, cutout_val) # for fixmatch + return img + + +if __name__ == '__main__': + randaug = RandAugment(3, 5) + print(randaug) + for item in randaug.augment_list: + print(item) diff --git a/lr_schedule.py b/lr_schedule.py new file mode 100644 index 0000000..76499c2 --- /dev/null +++ b/lr_schedule.py @@ -0,0 +1,11 @@ +class InvScheduler(object): + def __init__(self, gamma, decay_rate, group_ratios, init_lr=0.001): + self.gamma = gamma + self.decay_rate = decay_rate + self.group_ratios = group_ratios + self.init_lr = init_lr + + def adjust_learning_rate(self, optimizer, iteration): + lr = self.init_lr * (1 + self.gamma * iteration) ** (-self.decay_rate) + for (param_group, ratio) in zip(optimizer.param_groups, self.group_ratios): + param_group['lr'] = lr * ratio diff --git a/main.py b/main.py new file mode 100644 index 0000000..7abf255 --- /dev/null +++ b/main.py @@ -0,0 +1,314 @@ +import argparse +import csv +import json +import os +import shutil +import copy + +import torch +from termcolor import colored +from torch.utils.tensorboard import SummaryWriter + +from lr_schedule import InvScheduler +from model.contrastive_loss import supervised_loss, PairEnum,InfoNCELoss,SupConLoss,info_nce_logits,AdaptiveFeatureNorm +from model.key_memory import KeyMemory + +from model.model import ImageClassifier + +from pseudo_labeler import KMeansPseudoLabeler +from train_target import Train +from utils import configure, get_dataset_name, moment_update, str2bool +import utils +parser = argparse.ArgumentParser() + +# dataset configurations +parser.add_argument('--config', + type=str, + default='config/config.yml', + help='Dataset configuration parameters') +parser.add_argument('--dataset_root', + type=str, + default='./AAAI2023/data/domain_adaptation/') +parser.add_argument('--src', + type=str, + default='amazon', + help='Source dataset name') +parser.add_argument('--tgt', + type=str, + default='webcam', + help='Target dataset name') +parser.add_argument('--batch_size', + type=int, + default=32, + help='Batch size for both training and evaluation') +parser.add_argument('--eval_batch_size', + type=int, + default=64, + help='Batch size for both training and evaluation') +parser.add_argument('--pseudo_batch_size', + type=int, + default=4096, + help='Batch size for pseudo labeling') +parser.add_argument('--max_iterations', + type=int, + default=3000, + help='Maximum number of iterations') + +# logging configurations +parser.add_argument('--log_dir', + type=str, + default='office31', + help='Parent directory for log files') +parser.add_argument('--log_summary_interval', + type=int, + default=100, + help='Logging summaries frequency') +parser.add_argument('--log_image_interval', + type=int, + default=1000, + help='Logging images frequency') +parser.add_argument('--num_project_samples', + type=int, + default=384, + help='Number of samples for tensorboard projection') +parser.add_argument('--acc_file', + type=str, + default='hyper_search.csv', # 'result.txt' + help='File where accuracies are wrote') + +# resource configurations +parser.add_argument('--gpu', + type=str, + default='0', + help='Selected gpu index') +parser.add_argument('--num_workers', + type=int, + default=1, + help='Number of workers') + +# InfoNCE loss configurations +parser.add_argument('--temperature', + type=float, + default=0.07, + help='Temperature parameter for InfoNCE loss') + +# hyper-parameters +parser.add_argument('--cw', + type=float, + default=1, + help='Weight for NaCL') +parser.add_argument('--thresh', + type=float, + default=0.95, + help='Confidence threshold for pseudo labeling target samples')# +parser.add_argument('--max_key_size', + type=int, + default=20, + help='Maximum number of key feature size computed in the model') +parser.add_argument('--min_conf_samples', + type=int, + default=1, + help='Minimum number of samples per confident target class') +parser.add_argument('--kcc', + type=int, + default=3, + help='the lcc') + +# model configurations +parser.add_argument('--network', + type=str, + default='resnet50', # resnet101 + help='Base network architecture') +parser.add_argument('--contrast_dim', + type=int, + default=128, + help='contrast layer dimension') +parser.add_argument('--alpha', + type=float, + default=0.9, + help='momentum coefficient for model ema') +parser.add_argument('--frozen_layer', + type=str, + default='layer1', + help='Frozen layer in the base network') +parser.add_argument('--optimizer', + type=str, + default='sgd', + help='Optimizer type') +parser.add_argument('--lr', + type=float, + default=0.001, + help='Initial learning rate') +parser.add_argument('--momentum', + type=float, + default=0.9, + help='Optimizer parameter, momentum') +parser.add_argument('--weight_decay', + type=float, + default=0.0005, + help='Optimizer parameter, weight decay') +parser.add_argument('--nesterov', + type=str2bool, + default=False, # True + help='Optimizer parameter, nesterov') + +parser.add_argument("--phase", type=str, default='train', choices=['train', 'test'], + help="When phase is 'test', only train the model." + "When phase is 'test', only test the model.") + +# learning rate scheduler configurations +parser.add_argument('--lr_scheduler', + type=str, + default='inv', + help='Learning rate scheduler type') +parser.add_argument('--gamma', + type=float, + default=0.001, # 0.0005 + help='Inv learning rate scheduler parameter, gamma') +parser.add_argument('--decay_rate', + type=float, + default=0.75, # 2.25 + help='Inv learning rate scheduler parameter, decay rate') +parser.add_argument('--non-linear', default=False, action='store_true', + help='whether not use the linear version') +parser.add_argument("--momentum", type=str, default='True', choices=['True', 'False'], + help="When momentum is 'True', MoCo." + "When momentum is 'False', SimCLR") +parser.add_argument("--batch_norm", type=str, default='True', choices=['True', 'False'], + help="Whether use batch_norm") +parser.add_argument("--pseudo_pre", type=str, default='True', choices=['True', 'False'], + help="When pseudo_pre is 'True', use FixMtch loss on target data.") +parser.add_argument("--mcc", type=str, default='False', choices=['True', 'False'], + help="Ablation study") +parser.add_argument("--module", type=str, default='domain_loss', choices=['source_only', 'domain_loss'], + help="When module is 'domain_loss', it is our method.") + +def main(): + args = parser.parse_args() + print(args) + config = configure(args.config) + + os.environ['CUDA_DEVICE_ORDER'] = 'PCI_BUS_ID' + os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu + # define model name + setup_list = [args.module, + args.src, + args.tgt, + args.network, + f"contrast_dim_{args.contrast_dim}", + f"maxiter_{args.max_iterations}", + f"batchsize_{args.batch_size}", + f"alpha_{args.alpha}", + f"cw_{args.cw}", + f"max_key_size_{args.max_key_size}", + f"kcc{args.kcc}", + f"twomodel_{args.self_supervise_type}", + f"norm_{args.batch_norm}", + f"pred_{args.pseudo_pre}", + f"mcc_{args.mcc}" + ] + model_name = "_".join(setup_list) + print(colored(f"Model name: {model_name}", 'green')) + model_dir = os.path.join(args.log_dir, model_name) + + if os.path.isdir(model_dir): + shutil.rmtree(model_dir) + os.mkdir(model_dir) + summary_writer = SummaryWriter(model_dir) + + # save parsed arguments + with open(os.path.join(model_dir, 'parsed_args.txt'), 'w') as f: + json.dump(args.__dict__, f, indent=2) + + dataset_name = get_dataset_name(args.src, args.tgt) + + dataset_config = config.data.dataset[dataset_name] + data_root = os.path.join(args.dataset_root, dataset_name) + + criterion = SupConLoss() + + backbone = utils.get_model(args.network) + pool_layer = None + model = ImageClassifier(backbone, dataset_config.num_classes, bottleneck_dim=args.contrast_dim, + pool_layer=pool_layer).cuda() + backbone_ema = utils.get_model(args.network) + model_ema = ImageClassifier(backbone_ema, dataset_config.num_classes, bottleneck_dim=args.contrast_dim, + pool_layer=pool_layer).cuda() + + moment_update(model, model_ema, 0) + + model = model.cuda() + model_ema = model_ema.cuda() + + contrast_loss = InfoNCELoss(temperature=args.temperature).cuda() + adaptive_feature_norm = AdaptiveFeatureNorm(1).cuda() + max_key_size=args.max_key_size*dataset_config.num_classes + src_memory = KeyMemory(max_key_size, args.contrast_dim,dataset_config.num_classes).cuda() + tgt_memory = KeyMemory(max_key_size, args.contrast_dim,dataset_config.num_classes).cuda() + + tgt_pseudo_labeler = KMeansPseudoLabeler(num_classes=dataset_config.num_classes, + batch_size=args.pseudo_batch_size) + + parameters = model.get_parameter_list() + group_ratios = [parameter['lr'] for parameter in parameters] + + optimizer = torch.optim.SGD(parameters, + lr=args.lr, + momentum=args.momentum, + weight_decay=args.weight_decay, + nesterov=args.nesterov) + + assert args.lr_scheduler == 'inv' + lr_scheduler = InvScheduler(gamma=args.gamma, + decay_rate=args.decay_rate, + group_ratios=group_ratios, + init_lr=args.lr) + + trainer = Train(model, model_ema, optimizer, lr_scheduler, model_dir,dataset_name, + summary_writer, args.src, args.tgt, data_root,contrast_loss,supervised_loss,info_nce_logits, PairEnum,src_memory, tgt_memory, tgt_pseudo_labeler,criterion,adaptive_feature_norm, + cw=args.cw, + thresh=args.thresh, + min_conf_samples=args.min_conf_samples, + num_classes=dataset_config.num_classes, + batch_size=args.batch_size, + eval_batch_size=args.eval_batch_size, + num_workers=args.num_workers, + max_iter=args.max_iterations, + iters_per_epoch=dataset_config.iterations_per_epoch, + log_summary_interval=args.log_summary_interval, + log_image_interval=args.log_image_interval, + num_proj_samples=args.num_project_samples, + acc_metric=dataset_config.acc_metric, + alpha=args.alpha,transform_type=dataset_config.type,module=args.module,kcc=args.kcc,phase= args.phase, supervise_type = args.momentum, batch_norm = args.batch_norm,pseudo_pre=args.pseudo_pre,mcc=args.mcc) + + tgt_best_acc,tgt_pseudo_acc = trainer.train() + + # write to text file + with open(args.acc_file, 'a') as f: + f.write(model_name + ' ' + str(tgt_best_acc) + str(tgt_pseudo_acc) + '\n') + f.close() + + # write to xlsx file + write_list = [ + args.src, + args.tgt, + args.network, + args.contrast_dim, + args.temperature, + args.alpha, + args.cw, + args.thresh, + args.max_key_size, + args.module, + args.batch_size, + args.min_conf_samples, + args.gpu, + tgt_best_acc + ] + with open(args.acc_file, 'a') as f: + csv_writer = csv.writer(f) + csv_writer.writerow(write_list) + + +if __name__ == '__main__': + main() diff --git a/main_covid.py b/main_covid.py new file mode 100644 index 0000000..da6aba7 --- /dev/null +++ b/main_covid.py @@ -0,0 +1,274 @@ +import argparse +import csv +import json +import os +import shutil +import copy + +import torch +from termcolor import colored +from torch.utils.tensorboard import SummaryWriter + +from lr_schedule import InvScheduler +from model.contrastive_loss import supervised_loss,InfoNCELoss,GaussianKernel +from model.key_memory import KeyMemory + +from model.model import ImageClassifier + +from pseudo_labeler import KMeansPseudoLabeler +from train_covid import Train +from utils import configure, get_dataset_name, moment_update, str2bool,SupConLoss +import utils +parser = argparse.ArgumentParser() + +# dataset configurations +parser.add_argument('--config', + type=str, + default='config/config.yml', + help='Dataset configuration parameters') + +# datapath +parser.add_argument('--src', default='./all_data_pneumonia/', type=str, help='data path of source data') +parser.add_argument('--label_file_source', default='./COVID-DA-master/data/pneumonia_task_for_python3.pkl', type=str, + help='the pkl file that records the source data list and labels') +parser.add_argument('--tgt', default='./all_data_covid/', type=str, help='data path of target data') +parser.add_argument('--label_file_target', default='./COVID-DA-master/data/COVID-19_task_for_python3.pkl', type=str, + help='the pkl file that records the target data list and labels') + +# training configurations +parser.add_argument('--batch_size', + type=int, + default=32, + help='Batch size for both training and evaluation') +parser.add_argument('--eval_batch_size', + type=int, + default=32, + help='Batch size for both training and evaluation') +parser.add_argument('--pseudo_batch_size', + type=int, + default=4096, + help='Batch size for pseudo labeling') +parser.add_argument('--max_iterations', + type=int, + default=20000, + help='Maximum number of iterations') +parser.add_argument('--num_classes', + type=int, + default=2, + help='num of classes') + +# logging configurations +parser.add_argument('--log_dir', + type=str, + default='logs', + help='Parent directory for log files') +parser.add_argument('--log_summary_interval', + type=int, + default=100, + help='Logging summaries frequency') +parser.add_argument('--log_image_interval', + type=int, + default=1000, + help='Logging images frequency') +parser.add_argument('--acc_file', + type=str, + default='hyper_search.csv', # 'result.txt' + help='File where accuracies are wrote') + +# resource configurations + +parser.add_argument('--num_workers', + type=int, + default=1, + help='Number of workers') + +# InfoNCE loss configurations +parser.add_argument('--temperature', + type=float, + default=0.07, + help='Temperature parameter for InfoNCE loss') + +# hyper-parameters +parser.add_argument('--cw', + type=float, + default=1, + help='Weight for NCE contrast loss') + +parser.add_argument('--max_key_size', + type=int, + default=200, + help='Maximum number of key feature size computed in the model') +parser.add_argument('--min_conf_samples', + type=int, + default=1, + help='Minimum number of samples per confident target class') +parser.add_argument('--kcc', + type=int, + default=3, + help='the lcc') + +# model configurations +parser.add_argument('--network', + type=str, + default='resnet18', # resnet101 + help='Base network architecture') +parser.add_argument('--contrast_dim', + type=int, + default=128, + help='contrast layer dimension') +parser.add_argument('--alpha', + type=float, + default=0.9, + help='momentum coefficient for model ema') + +# optimizer configurations +parser.add_argument('--optimizer', + type=str, + default='sgd', + help='Optimizer type') +parser.add_argument('--lr', + type=float, + default=0.001, + help='Initial learning rate') +parser.add_argument('--momentum', + type=float, + default=0.9, + help='Optimizer parameter, momentum') +parser.add_argument('--weight_decay', + type=float, + default=0.0005, + help='Optimizer parameter, weight decay') +parser.add_argument('--nesterov', + type=str2bool, + default=False, # True + help='Optimizer parameter, nesterov') + +# learning rate scheduler configurations +parser.add_argument('--lr_scheduler', + type=str, + default='inv', + help='Learning rate scheduler type') +parser.add_argument('--gamma', + type=float, + default=0.001, + help='Inv learning rate scheduler parameter, gamma') +parser.add_argument('--decay_rate', + type=float, + default=0.75, # + help='Inv learning rate scheduler parameter, decay rate') +parser.add_argument('--non-linear', default=False, action='store_true', + help='whether not use the linear version') +parser.add_argument("--module", type=str, default='contrastive_loss', choices=['contrastive_loss', 'source_only'], + help="When module is 'contrastive_loss', it is our method.") + +def main(): + args = parser.parse_args() + print(args) + config = configure(args.config) + + os.environ['CUDA_DEVICE_ORDER'] = 'PCI_BUS_ID' + + # define model name + setup_list = ['covid19', + args.module, + args.network, + f"contrast_dim_{args.contrast_dim}", + f"maxiter_{args.max_iterations}", + f"batchsize_{args.batch_size}", + f"augment_{args.cw}", + f"kcc_{args.kcc}" + ] + model_name = "_".join(setup_list) + print(colored(f"Model name: {model_name}", 'green')) + model_dir = os.path.join(args.log_dir, model_name) + + if os.path.isdir(model_dir): + shutil.rmtree(model_dir) + os.mkdir(model_dir) + summary_writer = SummaryWriter(model_dir) + + # save parsed arguments + with open(os.path.join(model_dir, 'parsed_args.txt'), 'w') as f: + json.dump(args.__dict__, f, indent=2) + + criterion = SupConLoss(temperature=0.07) + + backbone = utils.get_model(args.network) + pool_layer = None + model = ImageClassifier(backbone, args.num_classes, bottleneck_dim=args.contrast_dim, + pool_layer=pool_layer).cuda() + backbone_ema = utils.get_model(args.network) + model_ema = ImageClassifier(backbone_ema, args.num_classes, bottleneck_dim=args.contrast_dim, + pool_layer=pool_layer).cuda() + + moment_update(model, model_ema, 0) + + model = model.cuda() + model_ema = model_ema.cuda() + + contrast_loss = InfoNCELoss(temperature=args.temperature).cuda() + max_key_size=args.max_key_size*args.num_classes + src_memory = KeyMemory(max_key_size, args.contrast_dim,args.num_classes).cuda() + tgt_memory = KeyMemory(max_key_size, args.contrast_dim,args.num_classes).cuda() + + tgt_pseudo_labeler = KMeansPseudoLabeler(num_classes=args.num_classes, + batch_size=args.pseudo_batch_size) + + parameters = model.get_parameter_list() + group_ratios = [parameter['lr'] for parameter in parameters] + + optimizer = torch.optim.SGD(parameters, + lr=args.lr, + momentum=args.momentum, + weight_decay=args.weight_decay, + nesterov=args.nesterov) + + assert args.lr_scheduler == 'inv' + lr_scheduler = InvScheduler(gamma=args.gamma, + decay_rate=args.decay_rate, + group_ratios=group_ratios, + init_lr=args.lr) + + trainer = Train(model, model_ema, optimizer, lr_scheduler, model_dir, + summary_writer, args.src, args.tgt, args.label_file_source,args.label_file_target,contrast_loss,supervised_loss,src_memory, tgt_memory, tgt_pseudo_labeler,criterion, + cw=args.cw, + min_conf_samples=args.min_conf_samples, + num_classes=args.num_classes, + batch_size=args.batch_size, + eval_batch_size=args.eval_batch_size, + num_workers=args.num_workers, + max_iter=args.max_iterations, + iters_per_epoch=100, + log_summary_interval=args.log_summary_interval, + log_image_interval=args.log_image_interval, + acc_metric='total_mean', + alpha=args.alpha,module=args.module,kcc=args.kcc) + + tgt_best_acc = trainer.train() + + # write to text file + # with open(args.acc_file, 'a') as f: + # f.write(model_name + ' ' + str(tgt_best_acc) + '\n') + # f.close() + + # write to xlsx file + write_list = [ + args.src, + args.tgt, + args.network, + args.contrast_dim, + args.temperature, + args.alpha, + args.cw, + args.max_key_size, + args.module, + args.batch_size, + args.min_conf_samples, + args.gpu, + tgt_best_acc + ] + with open(args.acc_file, 'a') as f: + csv_writer = csv.writer(f) + csv_writer.writerow(write_list) +if __name__ == '__main__': + main() diff --git a/metric/__init__.py b/metric/__init__.py new file mode 100644 index 0000000..a3cd692 --- /dev/null +++ b/metric/__init__.py @@ -0,0 +1,107 @@ +import torch +import prettytable + +def binary_accuracy(output: torch.Tensor, target: torch.Tensor) -> float: + """Computes the accuracy for binary classification""" + with torch.no_grad(): + batch_size = target.size(0) + pred = (output >= 0.5).float().t().view(-1) + correct = pred.eq(target.view(-1)).float().sum() + correct.mul_(100. / batch_size) + return correct + + +def accuracy(output, target, topk=(1,)): + r""" + Computes the accuracy over the k top predictions for the specified values of k + + Args: + output (tensor): Classification outputs, :math:`(N, C)` where `C = number of classes` + target (tensor): :math:`(N)` where each value is :math:`0 \leq \text{targets}[i] \leq C-1` + topk (sequence[int]): A list of top-N number. + + Returns: + Top-N accuracies (N :math:`\in` topK). + """ + with torch.no_grad(): + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target[None]) + + res = [] + for k in topk: + correct_k = correct[:k].flatten().sum(dtype=torch.float32) + res.append(correct_k * (100.0 / batch_size)) + return res + + +class ConfusionMatrix(object): + def __init__(self, num_classes): + self.num_classes = num_classes + self.mat = None + + def update(self, target, output): + """ + Update confusion matrix. + + Args: + target: ground truth + output: predictions of models + + Shape: + - target: :math:`(minibatch, C)` where C means the number of classes. + - output: :math:`(minibatch, C)` where C means the number of classes. + """ + n = self.num_classes + if self.mat is None: + self.mat = torch.zeros((n, n), dtype=torch.int64, device=target.device) + with torch.no_grad(): + k = (target >= 0) & (target < n) + inds = n * target[k].to(torch.int64) + output[k] + self.mat += torch.bincount(inds, minlength=n**2).reshape(n, n) + + def reset(self): + self.mat.zero_() + + def compute(self): + """compute global accuracy, per-class accuracy and per-class IoU""" + h = self.mat.float() + acc_global = torch.diag(h).sum() / h.sum() + acc = torch.diag(h) / h.sum(1) + iu = torch.diag(h) / (h.sum(1) + h.sum(0) - torch.diag(h)) + return acc_global, acc, iu + + # def reduce_from_all_processes(self): + # if not torch.distributed.is_available(): + # return + # if not torch.distributed.is_initialized(): + # return + # torch.distributed.barrier() + # torch.distributed.all_reduce(self.mat) + + def __str__(self): + acc_global, acc, iu = self.compute() + return ( + 'global correct: {:.1f}\n' + 'average row correct: {}\n' + 'IoU: {}\n' + 'mean IoU: {:.1f}').format( + acc_global.item() * 100, + ['{:.1f}'.format(i) for i in (acc * 100).tolist()], + ['{:.1f}'.format(i) for i in (iu * 100).tolist()], + iu.mean().item() * 100) + + def format(self, classes: list): + """Get the accuracy and IoU for each class in the table format""" + acc_global, acc, iu = self.compute() + + table = prettytable.PrettyTable(["class", "acc", "iou"]) + for i, class_name, per_acc, per_iu in zip(range(len(classes)), classes, (acc * 100).tolist(), (iu * 100).tolist()): + table.add_row([class_name, per_acc, per_iu]) + + return 'global correct: {:.1f}\nmean correct:{:.1f}\nmean IoU: {:.1f}\n{}'.format( + acc_global.item() * 100, acc.mean().item() * 100, iu.mean().item() * 100, table.get_string()) + diff --git a/metric/__pycache__/__init__.cpython-37.pyc b/metric/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca2f9f127a4e9df0ac0f3e5c1021f71cf9717e54 GIT binary patch literal 4188 zcmb_fTW=f36`t7}mn&Iz6UCQ04~t$>v9TpPHEKt(9osTuq)ml1cH)+iyIOIE)QXp- zW{0*#FM$GfAC01YDNy8re9T|krviQQFDQ_g_B*pAEy?LqyTlCVemUnm-#K&V#EF36 zyY}AIoqsJc_D`zJJ_m(cNZGHD2_|@l)yscg=fZ07x+U43ZIUDGZ*1WR_k~k;#e%2^ z{{^pm_n4@P-~|(btUR~tzTo#+ZSfV>W1IE2+VY^ECOsVqsbxbaX|HA%UOLeIfi659 ztCqySl6s(e4T~n>bCIe@8%Wt7kZCsN6ZYrNILrCi5`4l(R?dXgcE|RFjU6Oc*l4wL zd+cG1sZF@)txVX+$(^w;oZLFkCLF6c_t|gR7wmUTxHzphT-!*yIFZaky(`1G(HN+> zaS%3B749UxSRI6oPMl>)Gik(h3B_@$781UHeEjO)_@=er-`cEI3s?Rv_pyPa7D{rma5u%xN!tG)Bfy2xZaKR?)vu1=7n&hwjDm%l}d)&8{v(xH|Xx* zK-j@xPG;Nl)k}LhwEBFN`4Td2?3RZNlWexjrEsew_ronMpXz7jBH8Hc7AK=vB)YnbjM+~RiFNit1mf`l$^PS3bnO5h7)y@!PGz>JxqDS@(&ZQbxySivjm}U@aqGvK*Mp4`DFsN9bu#_v|B!xrLP7K_(g4mDRyy!g|5# zum|DbAKWTD{JVx*S=}p{wO*0FSonsEMR5Y$TNO({^~vJoM%rr*GO*EaVwm*PIepS? zDQ(bpbkLmVECQ_~$F`WvH)~e00H8%vh>>tL+MG;wn(8N*^Ty3*gmHmZCBMPA$A@Q+ z9b$DhY)%oRz#|lqvpoh{V0&Efwy%D!tv%3oZZ|EIoSg5u!g`7Rh-+)?f%d;5+81`) z#XamcqzF0(t>hq!afRkg_%h2as-IyaH)jskM!TQ8pd06Hko-$)T%|oG)>Vim;t%2K zrVfDIl^0)|Q3M(Bmwgdy8G<@X`Gyb<1U!X1jW}xb)KXg2de~CwpeI7D26}gHw=|$+ zhV>)#0(Pr*a*8a?v)SuS(~)mJL>Mj(FZEqC zX0#gP!*`BvY(~uYrPzm(G2SK$vwcTo4uCzP8fQXr5c2bE1fwZisfGM3+U(9F9tMF1*|%B>0;<-$q^$90I9$Ao3~FefunECQ0#e3`HC z;hE!doQ|DKk~oUsWF+|&3Wz`0gl*X)M2{oHBx4S_SQEsN%S;#s&Mhia)OeRY=U`*7 zGDR$}+Ynzu?z34FiZ8s);k~KIrha2Re73%Nxj71AL>6&NhAMpmHZkEF`bGidW&X)v z!?I!~yb?I(`~n0Rg2H_y<7-;D!lR`TID8BMO!!}{eL4UidgXpFHxD6eN#)k+rGh8N zB>G)&og6ud>SjdC(jFcgzJFYpQIu(g=R5ExUL$q;wR-%n)A9DXs1*4Z23zhm;*%w5UvP^ALSyTuZLn z2>_(!?*Y8gZX~qHXPHIIidTk^2%3 zu;jshomuI*gDCgiEobD7DkC4!t~;*emE6y(v<7GUpTJqUV?T!r16DB~7z}{HS!fFf>3F9jsSgM$T+?NQTG&ZCP#@vC!<+vF z=?2L&h)>af9NodQQEk!avsgfot@VM~u)grQsXUNd8mS7IR| zSdjsOx`ifnhuQ-?9|@^RuLbvF+yil~I*JE8$7pQ>xFRt3ih6NZ)+?YediB&jD!joz zX14~`n?8n?tW*37Uq+Poru!(Rwpj}bKQfC)Q4vHD-20#-QC^Iq{XyKJZKFv2j1Kt$ zWmhOO7$=@89Kv>a%hw<_C5k`QkCDBPWDewW-|?4y+dt(mnjZL|chFg@mQgdYCSgDB ybZ`Lgfq9ZBL(BA*GchXO;yZhIRhs#S>}I}Y;a@NBaFaZuAz|!mdDiJ5IR77fLKy7; literal 0 HcmV?d00001 diff --git a/model/WideResNet.py b/model/WideResNet.py new file mode 100644 index 0000000..282e63f --- /dev/null +++ b/model/WideResNet.py @@ -0,0 +1,240 @@ +#!/usr/bin/python +# -*- encoding: utf-8 -*- +import math + +import torch +import torch.nn as nn + +import torch.nn.functional as F + +from torch.nn import BatchNorm2d + +''' + As in the paper, the wide resnet only considers the resnet of the pre-activated version, + and it only considers the basic blocks rather than the bottleneck blocks. +''' + + +class BasicBlockPreAct(nn.Module): + def __init__(self, in_chan, out_chan, drop_rate=0, stride=1, pre_res_act=False): + super(BasicBlockPreAct, self).__init__() + self.bn1 = BatchNorm2d(in_chan, momentum=0.001) + self.relu1 = nn.LeakyReLU(inplace=True, negative_slope=0.1) + self.conv1 = nn.Conv2d(in_chan, out_chan, kernel_size=3, stride=stride, padding=1, bias=False) + self.bn2 = BatchNorm2d(out_chan, momentum=0.001) + self.relu2 = nn.LeakyReLU(inplace=True, negative_slope=0.1) + self.dropout = nn.Dropout(drop_rate) if not drop_rate == 0 else None + self.conv2 = nn.Conv2d(out_chan, out_chan, kernel_size=3, stride=1, padding=1, bias=False) + self.downsample = None + if in_chan != out_chan or stride != 1: + self.downsample = nn.Conv2d( + in_chan, out_chan, kernel_size=1, stride=stride, bias=False + ) + self.pre_res_act = pre_res_act + # self.init_weight() + + def forward(self, x): + bn1 = self.bn1(x) + act1 = self.relu1(bn1) + residual = self.conv1(act1) + residual = self.bn2(residual) + residual = self.relu2(residual) + if self.dropout is not None: + residual = self.dropout(residual) + residual = self.conv2(residual) + + shortcut = act1 if self.pre_res_act else x + if self.downsample is not None: + shortcut = self.downsample(shortcut) + + out = shortcut + residual + return out + + def init_weight(self): + # for _, md in self.named_modules(): + # if isinstance(md, nn.Conv2d): + # nn.init.kaiming_normal_( + # md.weight, a=0, mode='fan_in', nonlinearity='leaky_relu') + # if md.bias is not None: + # nn.init.constant_(md.bias, 0) + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, a=0, mode='fan_in', nonlinearity='leaky_relu') + if m.bias is not None: + nn.init.constant_(m.bias, 0) + + +class WideResnetBackbone(nn.Module): + def __init__(self, k=1, n=28, drop_rate=0): + super(WideResnetBackbone, self).__init__() + self.k, self.n = k, n + assert (self.n - 4) % 6 == 0 + n_blocks = (self.n - 4) // 6 + n_layers = [16, ] + [self.k * 16 * (2 ** i) for i in range(3)] + + self.conv1 = nn.Conv2d( + 3, + n_layers[0], + kernel_size=3, + stride=1, + padding=1, + bias=False + ) + self.layer1 = self.create_layer( + n_layers[0], + n_layers[1], + bnum=n_blocks, + stride=1, + drop_rate=drop_rate, + pre_res_act=True, + ) + self.layer2 = self.create_layer( + n_layers[1], + n_layers[2], + bnum=n_blocks, + stride=2, + drop_rate=drop_rate, + pre_res_act=False, + ) + self.layer3 = self.create_layer( + n_layers[2], + n_layers[3], + bnum=n_blocks, + stride=2, + drop_rate=drop_rate, + pre_res_act=False, + ) + self.bn_last = BatchNorm2d(n_layers[3], momentum=0.001) + self.relu_last = nn.LeakyReLU(inplace=True, negative_slope=0.1) + self.init_weight() + + def create_layer( + self, + in_chan, + out_chan, + bnum, + stride=1, + drop_rate=0, + pre_res_act=False, + ): + layers = [ + BasicBlockPreAct( + in_chan, + out_chan, + drop_rate=drop_rate, + stride=stride, + pre_res_act=pre_res_act), ] + for _ in range(bnum - 1): + layers.append( + BasicBlockPreAct( + out_chan, + out_chan, + drop_rate=drop_rate, + stride=1, + pre_res_act=False, )) + return nn.Sequential(*layers) + + def forward(self, x): + feat = self.conv1(x) + + feat = self.layer1(feat) + feat2 = self.layer2(feat) # 1/2 + out_features = self.layer3(feat2) # 1/4 + + out_features = self.bn_last(out_features) + out_features = self.relu_last(out_features) + return out_features + + def init_weight(self): + # for _, child in self.named_children(): + # if isinstance(child, nn.Conv2d): + # n = child.kernel_size[0] * child.kernel_size[0] * child.out_channels + # nn.init.normal_(child.weight, 0, 1. / ((0.5 * n) ** 0.5)) + # # nn.init.kaiming_normal_( + # # child.weight, a=0.1, mode='fan_out', + # # nonlinearity='leaky_relu' + # # ) + # + # if child.bias is not None: + # nn.init.constant_(child.bias, 0) + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + + nn.init.kaiming_normal_(m.weight, a=0, mode='fan_in', nonlinearity='leaky_relu') + if m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + elif isinstance(m, nn.Linear): + m.bias.data.zero_() + +class Normalize(nn.Module): + + def __init__(self, power=2): + super(Normalize, self).__init__() + self.power = power + + def forward(self, x): + norm = x.pow(self.power).sum(1, keepdim=True).pow(1. / self.power) + out = x.div(norm) + return out + +class WideResnet(nn.Module): + ''' + for wide-resnet-28-10, the definition should be WideResnet(n_classes, 10, 28) + ''' + + def __init__(self, n_classes, k=1, n=28, low_dim=64, proj=True): + super(WideResnet, self).__init__() + self.n_layers, self.k = n, k + self.backbone = WideResnetBackbone(k=k, n=n) + self.classifier = nn.Linear(64 * self.k, n_classes, bias=True) + + self.proj = proj + if proj: + self.l2norm = Normalize(2) + + self.fc1 = nn.Linear(64 * self.k, 64 * self.k) + self.relu_mlp = nn.LeakyReLU(inplace=True, negative_slope=0.1) + self.fc2 = nn.Linear(64 * self.k, low_dim) + + + def forward(self, x): + feat = self.backbone(x)[-1] + feat = torch.mean(feat, dim=(2, 3)) + out = self.classifier(feat) + + if self.proj: + feat = self.fc1(feat) + feat = self.relu_mlp(feat) + feat = self.fc2(feat) + + feat = self.l2norm(feat) + return out,feat + else: + return out + + def init_weight(self): + nn.init.xavier_normal_(self.classifier.weight) + if not self.classifier.bias is None: + nn.init.constant_(self.classifier.bias, 0) + + +if __name__ == "__main__": + x = torch.randn(2, 3, 224, 224) + lb = torch.randint(0, 10, (2,)).long() + + net = WideResnetBackbone() + out = net(x) + print(out[0].size()) + del net, out + + net = WideResnet(n_classes=10) + criteria = nn.CrossEntropyLoss() + out = net(x) + loss = criteria(out, lb) + loss.backward() + print(out.size()) \ No newline at end of file diff --git a/model/__pycache__/WideResNet.cpython-37.pyc b/model/__pycache__/WideResNet.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..51affd6ac329555a00727aa0ae8c06b5792a8a40 GIT binary patch literal 6187 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 YqCS0Y`s(zDGryy}ntyh>GX3@c3rPz8G5`Po literal 0 HcmV?d00001 diff --git a/model/__pycache__/key_memory.cpython-37.pyc b/model/__pycache__/key_memory.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..32eae49fe22bebed69e78ff1015148fa66d6d4be GIT binary patch literal 1701 zcmZ8h&ub(_6t1eS?&R46fsINzGqnP(WQ3U;`>^T`zNhQ0A)1dX2av93#ilm|J$Qah>IpHMj zfbXvBeyz?QsadVhbA*l~gb860bZ>qGVTq*;xnxVW0RDg0AwVY?JVPl zOt}mW$ci423*L}rS9051_Te0?rhLVg0~t1aA1s!`hWBAzK{~u;1eRN}GXbyD04?yw zZcFqU{7PgOJ;2)gJ-notLI|OMtSMlez=ZMdr`HJE#bcG(xmM6IGh)|6nZk zADg0@96p_^xjHnb*_rz2@ZAM_@9+gpk{uVC`I*wXbt6Pk6;=q>^X9@73+4JZ&V?*y zE-WgkesZ0>%#2aS@mXe19XC(4b=z7^3S*TPC-d=GX&2gB=WwgDN`mFQ6pm+73Kv;b znHmhvbWzzP1P7`d>j8k*LloN>1~*nd10r;V@XrbHCwcMJ=(L`x(Kq)WjLKrVxcA{G zucaE9Y^=oNhxbRiKA9UU^18A*Gq!l9L|Gd%nt@e0`ca*WnXmuR*}3k+D=|#73xd!s z8nr*RPw%of*kbpVEl2Cj0>(5R;lYgfyb!HWDmhT^g% zZvvn~xI(%BVW!aspuu^^@8T81^JUlHlPORMNXHwx3Xn9@!OfoC?4u@l4bS5{AVu^9 zNb)WDj{MM)g|%c!hLB3EWF(c%@>9JBa9yXW#YAV)MH$p*q8!iXGSgdl$H$N^Uk=C1 zx|(Q=*7beuA+=}cLSxG$p?)2fbn7Iu`KefwFdek}mW8g@?hrvbG(ZUjER#j9jD8dT z-HNyHfnIwHMKX6_?**Yf8q+xFL3wb-bO(Nm{Y_~$f6B2naA1+J6MS*-5l9iiVq9Ra z`LbLv=xjD-&{Om{3EBw59HLciY=Mu>pZkMX!FDIg3g0Gg!viJ)fmnO-VsC@(*5(!( zLcE2BghyyF=^6^#v_V2!46mdqMz5I8d+>LI&Io;(tLy6|cCipuHdENqLO@ODCF%nK zz_YTw@m-+b0Vg^^aTkOe-n3k<%2J3;=z!<|jj&w)n}IYi*h4WLY{lF0z@H|u-a!i_ zn)aWhJ^v{ggLmmJ`yYPs BovZ)= literal 0 HcmV?d00001 diff --git a/model/__pycache__/model_ljz.cpython-37.pyc b/model/__pycache__/model_ljz.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..73e9e149c5b9084cd4328bf3208dab6452138564 GIT binary patch literal 6939 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 j=5Mn# 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 literal 0 HcmV?d00001 diff --git a/model/__pycache__/utils.cpython-37.pyc b/model/__pycache__/utils.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b5a2a059d67199d1e8bd6ba76b1858b85be06e8d GIT binary patch literal 3210 zcmaJ@O_Li(8Sb7hjYis!Y?jywDNuzZWno7foA0n}?9C?T5Og4btAt%szYe4?l#KVWs_00+*TIq(zuMsY~_#yJ;w-X2N2HWaPuR)4(R^L{+<)4jj8 z7BG~k_*3*3^!`bMWpU8Cjj9G{1QR@Cz3QJ2t)9iHZ)JRF_iXfS;XGwMM{J3j@SpOY zdzXp22%a(#B-X$?vwJnnG(;0K&7_90FJ2YvVgs^uu_<1`?m+O*SbO_9zQ?+4uAMYb ziWK0;Mrpefma4fu?g{M-_J&V_Ys%U=n*WasvrojY@O?8)y#${l#;HQ@+% zPFi~}tp6VCKGy4^Hs_q>AH1|*7QuOg&Y;!*zgIA5?{|Ck{iukKx+6J!{%;iRJxdKku8q*NGcKMeC|n4stM(_H946;Y9d zB8>~}94AkdBu8jRL`9@)IldHSp>%1^?WY;~%_e&~{vxf5VJ5XEUd;ONSzS#%FF}KQqxr-z(j7xAf+GR{Nawxd0}f z`ep5ae?2`ay|Q+d9k2)YXZ5mv?g<;nae$oh$$gA#KncdLvsrNZ!@@7EGY;7s zvj*1cWgxsFC>v+|3KQ-XRt8tt+?q9?v9kU;EB&&$%TAu%V<-3Tk?xJsC*4cJMXmc^ zKqe2U*U+R8d9Xg?IELdG{s-&C`K*eK2@v9Db>7!DBH!k+jvZ!NZlU*8uuHIrN5k>n zH|ao%yvL?36NE)XI=k5@jxx2^xe(S?KbGWa%{$ZJVIGRnFiP_dkmyF^arVSS$b3!P zDk&r}g>I&Kkw}%qMLNnQ1xveXoTY_!Wt1N#x+arx7R3qn6jE@tiPB%ejLd| z1zb_OUf@bz$8ZN#(L96Y9-n^gva+4k>6FDQ)yaevO_M7~*#SFd>dgWPS&jPEYe>o8 zno(#iOqgE(#Zl6#lx(G54NOfB8h<4kq^k2WDR3ZtDA4@rs z@&>-xw&Z*GGyTdUqB)Z;pwgsRK<>MkR0LrLMxxkGue@O2g(SRVNZOM%Nb4XB0Z+sW z1lT>H@0lSrIISl5PnDtDmBC0jts?sw!+ERlv$Uy;k6&9MlZ`y)ko3yX1Xd zI=`c6x*$gPjDzgny$50jka@RVm*2*TlDumCpshUDK?Upsy1D8rl92>y6F=EPukD$5 z^=fGzs&txEkqzk93bW`5;7m@^JYPC*6;AV^T`Vr*xXA!NrHSFT}sJc zzeh_UmTt7JFS`%S#_sCHgA2?pMlwFqP7&ot$lVX1NzY%(_qHn2WB-OX_F+&y(`&864+h2jc-?6(a^PuB$N(PmFBnv^Ei>;g8;6& zM{L1la=Nt#e5X0InpRKLNOYLc@mK!=Ls|xH@@m6gFyA?*W34_NuHlY*i)v nZA_c torch.Tensor: + r""" + Update the `index_matrix` which convert `kernel_matrix` to loss. + If `index_matrix` is a tensor with shape (2 x batch_size, 2 x batch_size), then return `index_matrix`. + Else return a new tensor with shape (2 x batch_size, 2 x batch_size). + """ + if index_matrix is None or index_matrix.size(0) != batch_size * 2: + index_matrix = torch.zeros(2 * batch_size, 2 * batch_size) + if linear: + for i in range(batch_size): + s1, s2 = i, (i + 1) % batch_size + t1, t2 = s1 + batch_size, s2 + batch_size + index_matrix[s1, s2] = 1. / float(batch_size) + index_matrix[t1, t2] = 1. / float(batch_size) + index_matrix[s1, t2] = -1. / float(batch_size) + index_matrix[s2, t1] = -1. / float(batch_size) + else: + for i in range(batch_size): + for j in range(batch_size): + if i != j: + index_matrix[i][j] = 1. / float(batch_size * (batch_size - 1)) + index_matrix[i + batch_size][j + batch_size] = 1. / float(batch_size * (batch_size - 1)) + for i in range(batch_size): + for j in range(batch_size): + index_matrix[i][j + batch_size] = -1. / float(batch_size * batch_size) + index_matrix[i + batch_size][j] = -1. / float(batch_size * batch_size) + return index_matrix + +class InfoNCELoss(nn.Module): + def __init__(self, temperature=0.1): + super(InfoNCELoss, self).__init__() + self.temperature = temperature + + def forward(self, r_src, r_tgt, pos_matrix, neg_matrix): + """ + Compute the NCE scores for predicting r_src->r_trg. + Input: + r_src : (n_batch, n_rkhs) + r_tgt : (n_keys, n_rkhs) + pos_matrix : (n_batch, n_keys) + neg_matrix : (n_batch, n_keys) + Output: + query_to_key_loss : scalar + contrast_norm_loss : scalar + """ + # compute src->trg raw scores for batch + # (n_batch, n_keys) + raw_scores = torch.mm(r_src, r_tgt.transpose(0, 1)).float() + raw_scores /= self.temperature + + ''' + pos_scores includes scores for all the positive samples + neg_scores includes scores for all the negative samples, with + scores for positive samples set to the min score (-1 / self.temperature here) + ''' + # (n_batch, n_keys) + pos_scores = (pos_matrix * raw_scores) + + # (n_batch, n_keys) + neg_scores = (neg_matrix * raw_scores) - ((1. - neg_matrix) / self.temperature) + + ''' + for each set of positive examples P_i, compute the max over scores + for the set of negative samples N_i that are shared across P_i + ''' + # (n_batch, 1) + neg_maxes = torch.max(neg_scores, dim=1, keepdim=True)[0] + + ''' + compute a "partial, safe sum exp" over each negative sample set N_i, + to broadcast across the positive samples in P_i which share N_i + -- size will be (n_batch, 1) + ''' + neg_sumexp = (neg_matrix * torch.exp(neg_scores - neg_maxes)).sum(dim=1, keepdim=True) + + ''' + use broadcasting of neg_sumexp across the scores in P_i, to compute + the log-sum-exps for the denominators in the NCE log-softmaxes + -- size will be (n_batch, n_keys) + ''' + all_logsumexp = torch.log(torch.exp(pos_scores - neg_maxes) + neg_sumexp) + + # compute numerators for the NCE log-softmaxes + # (n_batch, n_keys) + pos_shiftexp = pos_scores - neg_maxes + + # compute the final log-softmax scores for NCE... + # (n_batch, n_keys) + nce_scores = pos_matrix * (pos_shiftexp - all_logsumexp) + + contrast_loss = -nce_scores.sum() / pos_matrix.sum() + + return contrast_loss +class SupConLoss(torch.nn.Module): + """Supervised Contrastive Learning: https://arxiv.org/pdf/2004.11362.pdf. + It also supports the unsupervised contrastive loss in SimCLR + From: https://github.com/HobbitLong/SupContrast""" + def __init__(self, temperature=0.07, contrast_mode='all', + base_temperature=0.07): + super(SupConLoss, self).__init__() + self.temperature = temperature + self.contrast_mode = contrast_mode + self.base_temperature = base_temperature + + def forward(self, features, labels=None, mask=None): + """Compute loss for model. If both `labels` and `mask` are None, + it degenerates to SimCLR unsupervised loss: + https://arxiv.org/pdf/2002.05709.pdf + Args: + features: hidden vector of shape [bsz, n_views, ...]. + labels: ground truth of shape [bsz]. + mask: contrastive mask of shape [bsz, bsz], mask_{i,j}=1 if sample j + has the same class as sample i. Can be asymmetric. + Returns: + A loss scalar. + """ + + device = (torch.device('cuda') + if features.is_cuda + else torch.device('cpu')) + + if len(features.shape) < 3: + raise ValueError('`features` needs to be [bsz, n_views, ...],' + 'at least 3 dimensions are required') + if len(features.shape) > 3: + features = features.view(features.shape[0], features.shape[1], -1) + + batch_size = features.shape[0] + if labels is not None and mask is not None: + raise ValueError('Cannot define both `labels` and `mask`') + elif labels is None and mask is None: + mask = torch.eye(batch_size, dtype=torch.float32).to(device) + elif labels is not None: + labels = labels.contiguous().view(-1, 1) + if labels.shape[0] != batch_size: + raise ValueError('Num of labels does not match num of features') + mask = torch.eq(labels, labels.T).float().to(device) + else: + mask = mask.float().to(device) + + contrast_count = features.shape[1] + contrast_feature = torch.cat(torch.unbind(features, dim=1), dim=0) + if self.contrast_mode == 'one': + anchor_feature = features[:, 0] + anchor_count = 1 + elif self.contrast_mode == 'all': + anchor_feature = contrast_feature + anchor_count = contrast_count + else: + raise ValueError('Unknown mode: {}'.format(self.contrast_mode)) + + # compute logits + anchor_dot_contrast = torch.div( + torch.matmul(anchor_feature, contrast_feature.T), + self.temperature) + + # for numerical stability + logits_max, _ = torch.max(anchor_dot_contrast, dim=1, keepdim=True) + logits = anchor_dot_contrast - logits_max.detach() + + # tile mask + mask = mask.repeat(anchor_count, contrast_count) + # mask-out self-contrast cases + logits_mask = torch.scatter( + torch.ones_like(mask), + 1, + torch.arange(batch_size * anchor_count).view(-1, 1).to(device), + 0 + ) + mask = mask * logits_mask + + # compute log_prob + exp_logits = torch.exp(logits) * logits_mask + log_prob = logits - torch.log(exp_logits.sum(1, keepdim=True)) + + # compute mean of log-likelihood over positive + mean_log_prob_pos = (mask * log_prob).sum(1) / mask.sum(1) + + # loss + loss = - (self.temperature / self.base_temperature) * mean_log_prob_pos + loss = loss.view(anchor_count, batch_size).mean() + + return loss + +def info_nce_logits(features): + + b_ = 0.5 * int(features.size(0)) + + labels = torch.cat([torch.arange(b_) for i in range(2)], dim=0) + labels = (labels.unsqueeze(0) == labels.unsqueeze(1)).float() + labels = labels.cuda() + + # features = F.normalize(features, dim=1) + + similarity_matrix = torch.matmul(features, features.T) + # assert similarity_matrix.shape == ( + # self.args.n_views * self.args.batch_size, self.args.n_views * self.args.batch_size) + # assert similarity_matrix.shape == labels.shape + + # discard the main diagonal from both: labels and similarities matrix + mask = torch.eye(labels.shape[0], dtype=torch.bool).cuda() + labels = labels[~mask].view(labels.shape[0], -1) + similarity_matrix = similarity_matrix[~mask].view(similarity_matrix.shape[0], -1) + # assert similarity_matrix.shape == labels.shape + + # select and combine multiple positives + positives = similarity_matrix[labels.bool()].view(labels.shape[0], -1) + + # select only the negatives the negatives + negatives = similarity_matrix[~labels.bool()].view(similarity_matrix.shape[0], -1) + + logits = torch.cat([positives, negatives], dim=1) + labels = torch.zeros(logits.shape[0], dtype=torch.long).cuda() + + # logits = logits / args.temperature + logits = logits + return logits, labels + + + +class AdaptiveFeatureNorm(nn.Module): + r""" + The `Stepwise Adaptive Feature Norm loss (ICCV 2019) `_ + + Instead of using restrictive scalar R to match the corresponding feature norm, Stepwise Adaptive Feature Norm + is used in order to learn task-specific features with large norms in a progressive manner. + We denote parameters of backbone :math:`G` as :math:`\theta_g`, parameters of bottleneck :math:`F_f` as :math:`\theta_f` + , parameters of classifier head :math:`F_y` as :math:`\theta_y`, and features extracted from sample :math:`x_i` as + :math:`h(x_i;\theta)`. Full loss is calculated as follows + + .. math:: + L(\theta_g,\theta_f,\theta_y)=\frac{1}{n_s}\sum_{(x_i,y_i)\in D_s}L_y(x_i,y_i)+\frac{\lambda}{n_s+n_t} + \sum_{x_i\in D_s\cup D_t}L_d(h(x_i;\theta_0)+\Delta_r,h(x_i;\theta))\\ + + where :math:`L_y` denotes classification loss, :math:`L_d` denotes norm loss, :math:`\theta_0` and :math:`\theta` + represent the updated and updating model parameters in the last and current iterations respectively. + + Args: + delta (float): positive residual scalar to control the feature norm enlargement. + + Inputs: + - f (tensor): feature representations on source or target domain. + + Shape: + - f: :math:`(N, F)` where F means the dimension of input features. + - Outputs: scalar. + + Examples:: + + >>> adaptive_feature_norm = AdaptiveFeatureNorm(delta=1) + >>> f_s = torch.randn(32, 1000) + >>> f_t = torch.randn(32, 1000) + >>> norm_loss = adaptive_feature_norm(f_s) + adaptive_feature_norm(f_t) + """ + + def __init__(self, delta): + super(AdaptiveFeatureNorm, self).__init__() + self.delta = delta + + def forward(self, f: torch.Tensor) -> torch.Tensor: + radius = f.norm(p=2, dim=1).detach() + assert radius.requires_grad == False + radius = radius + self.delta + loss = ((f.norm(p=2, dim=1) - radius) ** 2).mean() + return loss + +class BatchSpectralPenalizationLoss(nn.Module): + r"""Batch spectral penalization loss from `Transferability vs. Discriminability: Batch + Spectral Penalization for Adversarial Domain Adaptation (ICML 2019) + `_. + + Given source features :math:`f_s` and target features :math:`f_t` in current mini batch, singular value + decomposition is first performed + + .. math:: + f_s = U_s\Sigma_sV_s^T + + .. math:: + f_t = U_t\Sigma_tV_t^T + + Then batch spectral penalization loss is calculated as + + .. math:: + loss=\sum_{i=1}^k(\sigma_{s,i}^2+\sigma_{t,i}^2) + + where :math:`\sigma_{s,i},\sigma_{t,i}` refer to the :math:`i-th` largest singular value of source features + and target features respectively. We empirically set :math:`k=1`. + + Inputs: + - f_s (tensor): feature representations on source domain, :math:`f^s` + - f_t (tensor): feature representations on target domain, :math:`f^t` + + Shape: + - f_s, f_t: :math:`(N, F)` where F means the dimension of input features. + - Outputs: scalar. + + """ + + def __init__(self): + super(BatchSpectralPenalizationLoss, self).__init__() + + def forward(self, f_s, f_t): + _, s_s, _ = torch.svd(f_s) + _, s_t, _ = torch.svd(f_t) + loss = torch.pow(s_s[0], 2) + torch.pow(s_t[0], 2) + return loss diff --git a/model/key_memory.py b/model/key_memory.py new file mode 100644 index 0000000..bb8d411 --- /dev/null +++ b/model/key_memory.py @@ -0,0 +1,50 @@ +import math + +import torch +from torch import nn +import torch.nn.functional as F + +class KeyMemory(nn.Module): + def __init__(self, queue_size, feature_dim, classes): + super(KeyMemory, self).__init__() + self.queue_size = queue_size + self.feature_dim = feature_dim + self.index = 0 + self.classes = classes + + stdv = 1. / math.sqrt(self.feature_dim / 3) + self.register_buffer('features', torch.rand(self.queue_size, self.feature_dim).mul_(2 * stdv).add_(-stdv)) + # self.register_buffer('features',F.normalize(torch.randn(self.queue_size, self.feature_dim).cuda(), dim=-1)) + self.register_buffer('labels', torch.tensor([-1] * self.queue_size)) + # self.register_buffer('labels', torch.tensor(-torch.ones(self.queue_size, self.classes))) + print(f'Using queue shape: ({self.queue_size}, {self.feature_dim})') + + def store_keys(self, batch_features, batch_labels): + batch_size = batch_features.size(0) + batch_features.detach() + batch_labels.detach() + + # update memory + with torch.no_grad(): + store_indices = torch.arange(batch_size).cuda() + store_indices += self.index + store_indices = torch.fmod(store_indices, self.queue_size) + store_indices = store_indices.long() + self.features.index_copy_(0, store_indices, batch_features) + self.labels.index_copy_(0, store_indices, batch_labels) + self.index = (self.index + batch_size) % self.queue_size + + def get_queue(self): + features = self.features.clone() + labels = self.labels.clone() + + # certain_flag = labels.ge(0) + # # certain_flag = torch.max(labels, dim=1)[0].gt(-1) + + # certain_features = features[certain_flag] + # certain_labels = labels[certain_flag] + # return certain_features, certain_labels + return features, labels + + def get_size(self): + return self.queue_size, self.feature_dim diff --git a/model/model.py b/model/model.py new file mode 100644 index 0000000..fa94699 --- /dev/null +++ b/model/model.py @@ -0,0 +1,186 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + +import model.resnet as resnet +from model.utils import BatchNormDomain, initialize_layer +from common.modules.classifier import Classifier as ClassifierBase + +class Normalize(nn.Module): + def __init__(self, p=2): + super(Normalize, self).__init__() + self.p = p + + def forward(self, x): + return F.normalize(x, p=self.p, dim=1) +class AdaptiveFeatureNorm(nn.Module): + r""" + The `Stepwise Adaptive Feature Norm loss (ICCV 2019) `_ + + Instead of using restrictive scalar R to match the corresponding feature norm, Stepwise Adaptive Feature Norm + is used in order to learn task-specific features with large norms in a progressive manner. + We denote parameters of backbone :math:`G` as :math:`\theta_g`, parameters of bottleneck :math:`F_f` as :math:`\theta_f` + , parameters of classifier head :math:`F_y` as :math:`\theta_y`, and features extracted from sample :math:`x_i` as + :math:`h(x_i;\theta)`. Full loss is calculated as follows + + .. math:: + L(\theta_g,\theta_f,\theta_y)=\frac{1}{n_s}\sum_{(x_i,y_i)\in D_s}L_y(x_i,y_i)+\frac{\lambda}{n_s+n_t} + \sum_{x_i\in D_s\cup D_t}L_d(h(x_i;\theta_0)+\Delta_r,h(x_i;\theta))\\ + + where :math:`L_y` denotes classification loss, :math:`L_d` denotes norm loss, :math:`\theta_0` and :math:`\theta` + represent the updated and updating model parameters in the last and current iterations respectively. + + Args: + delta (float): positive residual scalar to control the feature norm enlargement. + + Inputs: + - f (tensor): feature representations on source or target domain. + + Shape: + - f: :math:`(N, F)` where F means the dimension of input features. + - Outputs: scalar. + + Examples:: + + >>> adaptive_feature_norm = AdaptiveFeatureNorm(delta=1) + >>> f_s = torch.randn(32, 1000) + >>> f_t = torch.randn(32, 1000) + >>> norm_loss = adaptive_feature_norm(f_s) + adaptive_feature_norm(f_t) + """ + + def __init__(self, delta): + super(AdaptiveFeatureNorm, self).__init__() + self.delta = delta + + def forward(self, f: torch.Tensor) -> torch.Tensor: + radius = f.norm(p=2, dim=1).detach() + assert radius.requires_grad == False + radius = radius + self.delta + loss = ((f.norm(p=2, dim=1) - radius) ** 2).mean() + return loss + +class ImageClassifier(ClassifierBase): + def __init__(self, backbone: nn.Module, num_classes: int, bottleneck_dim = 256, **kwargs): + super(ImageClassifier, self).__init__(backbone, num_classes, bottleneck_dim, **kwargs) + + + +class CIFARmodel(nn.Module): + """A generic Classifier class for domain adaptation. + + Args: + backbone (torch.nn.Module): Any backbone to extract 2-d features from data + num_classes (int): Number of classes + bottleneck (torch.nn.Module, optional): Any bottleneck layer. Use no bottleneck by default + bottleneck_dim (int, optional): Feature dimension of the bottleneck layer. Default: -1 + head (torch.nn.Module, optional): Any classifier head. Use :class:`torch.nn.Linear` by default + finetune (bool): Whether finetune the classifier or train from scratch. Default: True + + .. note:: + Different classifiers are used in different domain adaptation algorithms to achieve better accuracy + respectively, and we provide a suggested `Classifier` for different algorithms. + Remember they are not the core of algorithms. You can implement your own `Classifier` and combine it with + the domain adaptation algorithm in this algorithm library. + + .. note:: + The learning rate of this classifier is set 10 times to that of the feature extractor for better accuracy + by default. If you have other optimization strategies, please over-ride :meth:`~Classifier.get_parameters`. + + Inputs: + - x (tensor): input data fed to `backbone` + + Outputs: + - predictions: classifier's predictions + - features: features after `bottleneck` layer and before `head` layer + + Shape: + - Inputs: (minibatch, *) where * means, any number of additional dimensions + - predictions: (minibatch, `num_classes`) + - features: (minibatch, `features_dim`) + + """ + + def __init__(self, backbone: nn.Module, num_classes: int, + bottleneck_dim, pool_layer=None): + super(CIFARmodel, self).__init__() + self.backbone = backbone + self.parameter_list = [{"params": self.backbone.parameters(), "lr": 1}] + self.num_classes = num_classes + if pool_layer is None: + self.pool_layer = nn.Sequential( + nn.AdaptiveAvgPool2d(output_size=(1, 1)), + nn.Flatten() + ) + else: + self.pool_layer = pool_layer + # if bottleneck is None: + # self.bottleneck = nn.Identity() + # self._features_dim = backbone.out_features + # else: + # self.bottleneck = bottleneck + # assert bottleneck_dim > 0 + # self._features_dim = bottleneck_dim + + # if head is None: + # self.head = nn.Linear(self._features_dim, num_classes) + # else: + # self.head = head + # self.finetune = finetune + # self.contrast_layer = nn.Sequential( + # # nn.Linear(self.base_network.out_dim,self.base_network.out_dim), + # # nn.ReLU(inplace=True), + # nn.Dropout(0.5), + # nn.Linear(self.backbone.out_features,bottleneck_dim) + # ) + self.contrast_layer = nn.Sequential( + nn.Linear(128,128), + nn.ReLU(inplace=True), + # nn.Dropout(0.5), + nn.Linear(128,128) + ) + + initialize_layer(self.contrast_layer) + self.parameter_list += [{"params": self.contrast_layer.parameters(), "lr": 10}] + + self.classifier = nn.Linear(128, self.num_classes) + initialize_layer(self.classifier) + self.parameter_list += [{"params": self.classifier.parameters(), "lr": 10}] + + @property + def features_dim(self) -> int: + """The dimension of features before the final `head` layer""" + return self._features_dim + + def forward(self, x: torch.Tensor): + """""" + # f = self.pool_layer(self.backbone(x)) + # f = self.bottleneck(f) + # predictions = self.head(f) + # if self.training: + # return predictions, f + # else: + # return predictions + end_points = {} + features = self.pool_layer(self.backbone(x)) + # features = F.normalize(features, p=2, dim=1) + # features=self.bottleneck(features) + features = F.relu(features) + # features = F.normalize(features, p=2, dim=1) + end_points['features'] = features + + # contrast loss head + contrast_features = self.contrast_layer(features) + contrast_features = F.normalize(contrast_features, p=2, dim=1) + end_points['contrast_features'] = contrast_features + + logits = self.classifier(features) + end_points['logits'] = logits + + confidences, predictions = torch.max(F.softmax(logits, dim=1), 1) + end_points['predictions'] = predictions + end_points['confidences'] = confidences + + return end_points + + def get_parameter_list(self): + return self.parameter_list diff --git a/model/resnet.py b/model/resnet.py new file mode 100644 index 0000000..04adee5 --- /dev/null +++ b/model/resnet.py @@ -0,0 +1,310 @@ +# modified from torchvision +import torch.nn as nn +from torch.nn import BatchNorm2d +from torchvision.models import utils as vutils + +from model.utils import BatchNormDomain, init_weights + +__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', + 'resnet152', 'resnext50_32x4d', 'resnext101_32x8d'] + +model_urls = { + 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth', + 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth', + 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth', + 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth', + 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth', + 'resnext50_32x4d': 'https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth', + 'resnext101_32x8d': 'https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth', +} + + +def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1): + """3x3 convolution with padding""" + return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, + padding=dilation, groups=groups, bias=False, dilation=dilation) + + +def conv1x1(in_planes, out_planes, stride=1): + """1x1 convolution""" + return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False) + + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1, + base_width=64, dilation=1, norm_layer=None, num_domains=1): + super(BasicBlock, self).__init__() + if norm_layer is None: + norm_layer = BatchNorm2d + if groups != 1 or base_width != 64: + raise ValueError('BasicBlock only supports groups=1 and base_width=64') + if dilation > 1: + raise NotImplementedError("Dilation > 1 not supported in BasicBlock") + # Both self.conv1 and self.downsample layers downsample the input when stride != 1 + self.conv1 = conv3x3(inplanes, planes, stride) + self.bn1 = BatchNormDomain(planes, num_domains, norm_layer) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes) + self.bn2 = BatchNormDomain(planes, num_domains, norm_layer) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + identity = x + + out = self.conv1(x) + out = self.bn1(out) + + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + + if self.downsample is not None: + identity = self.downsample(x) + + out += identity + out = self.relu(out) + + return out + + +class Bottleneck(nn.Module): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1, + base_width=64, dilation=1, norm_layer=None, num_domains=1): + super(Bottleneck, self).__init__() + if norm_layer is None: + norm_layer = BatchNorm2d + width = int(planes * (base_width / 64.)) * groups + # Both self.conv2 and self.downsample layers downsample the input when stride != 1 + self.conv1 = conv1x1(inplanes, width) + self.bn1 = BatchNormDomain(width, num_domains, norm_layer) + self.conv2 = conv3x3(width, width, stride, groups, dilation) + self.bn2 = BatchNormDomain(width, num_domains, norm_layer) + self.conv3 = conv1x1(width, planes * self.expansion) + self.bn3 = BatchNormDomain(planes * self.expansion, num_domains, + norm_layer) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + identity = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + identity = self.downsample(x) + + out += identity + out = self.relu(out) + + return out + + +class ResNet(nn.Module): + + def __init__(self, block, layers, zero_init_residual=False, + groups=1, width_per_group=64, + replace_stride_with_dilation=None, # num_classes=1000, + frozen=None, norm_layer=None, num_domains=1): + super(ResNet, self).__init__() + if frozen is None: + frozen = [] + if norm_layer is None: + norm_layer = BatchNorm2d + self._norm_layer = norm_layer + self._num_domains = num_domains + + self.inplanes = 64 + self.dilation = 1 + if replace_stride_with_dilation is None: + # each element in the tuple indicates if we should replace + # the 2x2 stride with a dilated convolution instead + replace_stride_with_dilation = [False, False, False] + if len(replace_stride_with_dilation) != 3: + raise ValueError("replace_stride_with_dilation should be None " + "or a 3-element tuple, got {}".format(replace_stride_with_dilation)) + self.groups = groups + self.base_width = width_per_group + self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3, + bias=False) + self.bn1 = BatchNormDomain(self.inplanes, num_domains, self._norm_layer) + self.relu = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2, + dilate=replace_stride_with_dilation[0]) + self.layer3 = self._make_layer(block, 256, layers[2], stride=2, + dilate=replace_stride_with_dilation[1]) + self.layer4 = self._make_layer(block, 512, layers[3], stride=2, + dilate=replace_stride_with_dilation[2]) + self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) + self.out_dim = 512 * block.expansion + # self.dropout = nn.Dropout(p=dropout_ratio) + # self.fc = nn.Linear(512 * block.expansion, num_classes) + self.frozen = frozen + self.ordered_module_names = ['conv1', 'bn1', 'relu', 'maxpool', + 'layer1', 'layer2', 'layer3', 'layer4', 'avgpool'] + self.domain = None + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): + nn.init.constant_(m.weight, 1) + nn.init.constant_(m.bias, 0) + + # Zero-initialize the last BN in each residual branch, + # so that the residual branch starts with zeros, and each residual block behaves like an identity. + # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677 + if zero_init_residual: + for m in self.modules(): + if isinstance(m, Bottleneck): + for i in range(self._num_domains): + nn.init.constant_(m.bn3.bn_domain[i].weight, 0) + elif isinstance(m, BasicBlock): + for i in range(self._num_domains): + nn.init.constant_(m.bn2.bn_domain[i].weight, 0) + + def set_bn_domain(self, domain=0): + self.domain = domain + for m in self.modules(): + if isinstance(m, BatchNormDomain): + m.set_domain(domain) + + def _make_layer(self, block, planes, blocks, stride=1, dilate=False): + norm_layer = self._norm_layer + num_domains = self._num_domains + downsample = None + previous_dilation = self.dilation + if dilate: + self.dilation *= stride + stride = 1 + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + conv1x1(self.inplanes, planes * block.expansion, stride), + BatchNormDomain(planes * block.expansion, num_domains, norm_layer), + ) + + layers = [] + layers.append(block(self.inplanes, planes, stride, downsample, self.groups, + self.base_width, previous_dilation, norm_layer, num_domains=num_domains)) + self.inplanes = planes * block.expansion + for _ in range(1, blocks): + layers.append(block(self.inplanes, planes, groups=self.groups, + base_width=self.base_width, dilation=self.dilation, + norm_layer=norm_layer, num_domains=num_domains)) + + return nn.Sequential(*layers) + + def forward(self, x): + for name in self.ordered_module_names: + module = self._modules[name] + x = module(x) + x = x.detach() if name in self.frozen else x + x = x.view(x.size(0), -1) + + return x + + +def _resnet(arch, block, layers, num_domains, pretrained, progress, **kwargs): + model = ResNet(block, layers, num_domains=num_domains, **kwargs) + BN2BNDomain = True + if pretrained: + state_dict = vutils.load_state_dict_from_url(model_urls[arch], + progress=progress) + BN2BNDomain = True + else: + state_dict = None + BN2BNDomain = False + + init_weights(model, state_dict, num_domains, BN2BNDomain) + return model + + +def resnet18(num_domains=1, pretrained=False, progress=True, **kwargs): + """Constructs a ResNet-18 model. + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], num_domains, + pretrained, progress, **kwargs) + + +def resnet34(num_domains=1, pretrained=False, progress=True, **kwargs): + """Constructs a ResNet-34 model. + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], num_domains, + pretrained, progress, **kwargs) + + +def resnet50(num_domains=1, pretrained=False, progress=True, **kwargs): + """Constructs a ResNet-50 model. + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], num_domains, + pretrained, progress, **kwargs) + + +def resnet101(num_domains=1, pretrained=False, progress=True, **kwargs): + """Constructs a ResNet-101 model. + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], num_domains, + pretrained, progress, **kwargs) + + +def resnet152(num_domains=1, pretrained=False, progress=True, **kwargs): + """Constructs a ResNet-152 model. + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], num_domains, + pretrained, progress, **kwargs) + + +def resnext50_32x4d(num_domains=1, pretrained=False, progress=True, **kwargs): + """Constructs a ResNeXt-50 32x4d model. + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + kwargs['groups'] = 32 + kwargs['width_per_group'] = 4 + return _resnet('resnext50_32x4d', Bottleneck, [3, 4, 6, 3], num_domains, + pretrained, progress, **kwargs) + + +def resnext101_32x8d(num_domains=1, pretrained=False, progress=True, **kwargs): + """Constructs a ResNeXt-101 32x8d model. + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + kwargs['groups'] = 32 + kwargs['width_per_group'] = 8 + return _resnet('resnext101_32x8d', Bottleneck, [3, 4, 23, 3], num_domains, + pretrained, progress, **kwargs) diff --git a/model/utils.py b/model/utils.py new file mode 100644 index 0000000..36058b7 --- /dev/null +++ b/model/utils.py @@ -0,0 +1,89 @@ +import torch +import torch.nn as nn +from torch.nn import init + + +def weights_init_he(m): + classname = m.__class__.__name__ + if classname.find('BatchNorm') != -1: + if 'weight' in m.state_dict().keys(): + m.weight.data.normal_(1.0, 0.02) + if 'bias' in m.state_dict().keys(): + m.bias.data.fill_(0) + else: + if 'weight' in m.state_dict().keys(): + init.kaiming_normal_(m.weight) + if 'bias' in m.state_dict().keys(): + m.bias.data.fill_(0) + + +def init_weights(model, state_dict, num_domains=1, BN2BNDomain=False): + model.apply(weights_init_he) + + if state_dict is not None: + + model_state_dict = model.state_dict() + + keys = set(model_state_dict.keys()) + trained_keys = set(state_dict.keys()) + + shared_keys = keys.intersection(trained_keys) + new_state_dict = {key: state_dict[key] for key in shared_keys} + if BN2BNDomain: + for k in (trained_keys - shared_keys): + if k.find('fc') != -1: + continue + suffix = k.split('.')[-1] + for d in range(num_domains): + bn_key = k.replace(suffix, 'bn_domain.' + str(d) + '.' + suffix) + new_state_dict[bn_key] = state_dict[k] + + model.load_state_dict(new_state_dict) + + return model + + +class DomainModule(nn.Module): + def __init__(self, num_domains, **kwargs): + super(DomainModule, self).__init__() + self.num_domains = num_domains + self.domain = 0 + + def set_domain(self, domain=0): + assert (domain < self.num_domains), \ + "The domain id exceeds the range (%d vs. %d)" \ + % (domain, self.num_domains) + self.domain = domain + + +class BatchNormDomain(DomainModule): + def __init__(self, in_size, num_domains, norm_layer, **kwargs): + super(BatchNormDomain, self).__init__(num_domains) + self.bn_domain = nn.ModuleDict() + for n in range(self.num_domains): + self.bn_domain[str(n)] = norm_layer(in_size, **kwargs) + + def forward(self, x): + out = self.bn_domain[str(self.domain)](x) + return out + + +def tanh_clip(x, clip_val=10.): + """ + soft clip values to the range [-clip_val, +clip_val] + """ + if clip_val is not None: + x_clip = clip_val * torch.tanh((1. / clip_val) * x) + else: + x_clip = x + return x_clip + + +def initialize_layer(layer): + for m in layer.modules(): + if isinstance(m, (nn.BatchNorm2d, nn.BatchNorm1d)): + nn.init.constant_(m.weight, 1) + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.Linear): + nn.init.kaiming_normal_(m.weight) + nn.init.constant_(m.bias, 0) diff --git a/pseudo_labeler.py b/pseudo_labeler.py new file mode 100644 index 0000000..37ee847 --- /dev/null +++ b/pseudo_labeler.py @@ -0,0 +1,338 @@ +import math + +import torch +import torch.nn.functional as F +import tqdm +from scipy.optimize import linear_sum_assignment + +from model.utils import tanh_clip +from utils import to_one_hot + + +class BasePseudoLabeler(object): + def __init__(self, num_classes): + self.num_classes = num_classes + + def pseudo_label_tgt(self, src_test_collection, tgt_test_collection): + raise NotImplementedError + + +class KMeansPseudoLabeler(BasePseudoLabeler): + def __init__(self, num_classes, batch_size=4096, eps=0.0005): + super().__init__(num_classes) + self.batch_size = batch_size + self.eps = eps + self.init_centers = None + self.centers = None + self.stop = False + + @staticmethod + def get_dist(point_a, point_b, cross=False): + point_a = F.normalize(point_a, dim=1) + point_b = F.normalize(point_b, dim=1) + if not cross: + return 0.5 * (torch.tensor(1.0).cuda() - torch.sum(point_a * point_b, dim=1)) + else: + assert (point_a.size(1) == point_b.size(1)) + return 0.5 * (torch.tensor(1.0).cuda() - torch.mm(point_a, point_b.transpose(0, 1))) + + def get_src_centers(self, src_features, src_true_labels): + centers = 0 + refs = torch.LongTensor(range(self.num_classes)).unsqueeze(1).cuda() + num_batches = src_features.size(0) // self.batch_size + 1 + src_index = 0 + for i in range(num_batches): + cur_len = min(self.batch_size, src_features.size(0) - src_index) + cur_features = src_features.narrow(0, src_index, cur_len) + cur_true_labels = src_true_labels.narrow(0, src_index, cur_len) + + cur_true_labels = cur_true_labels.unsqueeze(0).expand(self.num_classes, -1) + mask = (cur_true_labels == refs).unsqueeze(2).float() + cur_features = cur_features.unsqueeze(0) + + centers += torch.sum(cur_features * mask, dim=1) + src_index += cur_len + + return centers + + def clustering_stop(self, centers): + if centers is None: + self.stop = False + else: + dist = self.get_dist(centers, self.centers) + dist = torch.mean(dist, dim=0) + print('dist %.4f' % dist.item()) + self.stop = dist.item() < self.eps + + def assign_labels(self, feats): + dists = self.get_dist(feats, self.centers, cross=True) + labels = torch.min(dists, dim=1)[1] + return dists, labels + + def align_centers(self): + cost = self.get_dist(self.centers, self.init_centers, cross=True) + cost = cost.cpu().numpy() + _, col_ind = linear_sum_assignment(cost) + return col_ind + + def pseudo_label_tgt(self, src_test_collection, tgt_test_collection): + """ + pseudo label target samples. + Args: + src_test_collection['features']: (n_src, n_rkhs) + tgt_test_collection['features']: (n_tgt, n_rkhs) + + Returns: + tgt_pseudo_label : (n_tgt, num_classes) contains pseudo label of entire target samples + """ + src_features = src_test_collection['features'] + tgt_features = tgt_test_collection['features'] + + src_true_labels = src_test_collection['true_labels'] + + assert src_features.size(1) == tgt_features.size(1) + + src_centers = self.get_src_centers(src_features, src_true_labels) + self.init_centers = src_centers + self.centers = src_centers + + centers = None + self.stop = False + + refs = torch.LongTensor(range(self.num_classes)).unsqueeze(1).cuda() + num_samples = tgt_features.size(0) + num_split = math.ceil(1.0 * num_samples / self.batch_size) + + while True: + self.clustering_stop(centers) + if centers is not None: + self.centers = centers + if self.stop: break + + centers = 0 + count = 0 + start = 0 + + for _ in range(num_split): + cur_len = min(self.batch_size, num_samples - start) + cur_feature = tgt_features.narrow(0, start, cur_len) + dist2center, labels = self.assign_labels(cur_feature) + labels_one_hot = to_one_hot(labels, self.num_classes) + count += torch.sum(labels_one_hot, dim=0) + labels = labels.unsqueeze(0) + mask = (labels == refs).unsqueeze(2).float() + reshaped_feature = cur_feature.unsqueeze(0) + + # update centers + centers += torch.sum(reshaped_feature * mask, dim=1) + start += cur_len + + mask = (count.unsqueeze(1) > 0).float() + centers = mask * centers + (1 - mask) * self.init_centers + + dist2center = [] + start = 0 + for N in range(num_split): + cur_len = min(self.batch_size, num_samples - start) + cur_feature = tgt_features.narrow(0, start, cur_len) + cur_dist2center, _ = self.assign_labels(cur_feature) + + dist2center += [cur_dist2center] + start += cur_len + + tgt_dist2center = torch.cat(dist2center, dim=0) + + cluster2label = self.align_centers() + # reorder the centers + self.centers = self.centers[cluster2label, :] + # re-label the data according to the index + num_samples = len(tgt_features) + for k in range(num_samples): + tgt_dist2center[k] = tgt_dist2center[k][cluster2label] + + return torch.tensor(1.0).cuda() - tgt_dist2center #torch.softmax(torch.tensor(1.0).cuda() - tgt_dist2center, dim=1) + + +class ClassifierPseudoLabeler(BasePseudoLabeler): + def __init__(self, num_classes): + super().__init__(num_classes) + + def pseudo_label_tgt(self, src_test_collection, tgt_test_collection): + del src_test_collection + tgt_logits = tgt_test_collection['logits'] + tgt_pseudo_labels = F.softmax(tgt_logits, dim=1) + # tgt_pseudo_confidences = torch.max(tgt_pseudo_labels, dim=1)[0] + # return tgt_pseudo_labels, tgt_pseudo_confidences + return tgt_pseudo_labels + + +class InfoPseudoLabeler(BasePseudoLabeler): + def __init__(self, num_classes, batch_size=4096, tclip=20., normalize=True): + super().__init__(num_classes) + self.batch_size = batch_size + self.tclip = tclip + self.normalize = normalize + + def pseudo_label_tgt(self, src_test_collection, tgt_test_collection): + """ + pseudo label target samples. + Args: + src_test_collection: (n_src, n_rkhs) + tgt_test_collection: (n_tgt, n_rkhs) + + Returns: + tgt_pseudo_label : (n_tgt, num_classes) contains pseudo label of entire target samples + """ + src_features = src_test_collection['features'] + tgt_features = tgt_test_collection['features'] + src_true_labels = src_test_collection['true_labels'] + + n_src = src_features.size(0) + n_tgt = tgt_features.size(0) + + assert src_features.size(1) == tgt_features.size(1) + n_rkhs = src_features.size(1) + + num_batches = (n_src + n_tgt) // self.batch_size + 1 + src_batch_sizes = [n_src // num_batches + 1] * (n_src % num_batches) \ + + [n_src // num_batches] * (num_batches - n_src % num_batches) + tgt_batch_sizes = [n_tgt // num_batches + 1] * (n_tgt % num_batches) \ + + [n_tgt // num_batches] * (num_batches - n_tgt % num_batches) + + src_perm_indices = torch.randperm(n_src).cuda() + tgt_perm_indices = torch.randperm(n_tgt).cuda() + + tgt_pseudo_labels = torch.zeros(n_tgt, self.num_classes).cuda() + + src_index = 0 + tgt_index = 0 + + for i in tqdm.tqdm(range(num_batches), desc='Target pseudo labeling', leave=False, ascii=True): + src_batch_indices = src_perm_indices[src_index:src_index + src_batch_sizes[i]] + tgt_batch_indices = tgt_perm_indices[tgt_index:tgt_index + tgt_batch_sizes[i]] + src_index += src_batch_sizes[i] + tgt_index += tgt_batch_sizes[i] + src_batch_features = src_features[src_batch_indices] + tgt_batch_features = tgt_features[tgt_batch_indices] + src_batch_true_labels = src_true_labels[src_batch_indices] + + if self.normalize: + src_batch_features = F.normalize(src_batch_features, dim=1) + tgt_batch_features = F.normalize(tgt_batch_features, dim=1) + raw_scores = torch.mm(tgt_batch_features, src_batch_features.transpose(0, 1)).float() + + if self.normalize: + raw_scores *= self.tclip + else: + raw_scores = raw_scores / n_rkhs ** 0.5 + raw_scores = tanh_clip(raw_scores, clip_val=self.tclip) + + prop_scores = F.softmax(raw_scores, dim=1) + + src_one_hot_label = to_one_hot(src_batch_true_labels, self.num_classes) + + tgt_batch_pseudo_label = torch.mm(prop_scores, src_one_hot_label) + + # balance class + src_class_count = torch.sum(src_one_hot_label, dim=0) + src_class_count = torch.max(src_class_count, torch.ones_like(src_class_count).cuda()) + tgt_batch_pseudo_label /= src_class_count + tgt_batch_pseudo_label = F.normalize(tgt_batch_pseudo_label, p=1, dim=1) + + tgt_pseudo_labels[tgt_batch_indices] = tgt_batch_pseudo_label + + tgt_pseudo_confidences = torch.max(tgt_pseudo_labels, dim=1)[0] + + return tgt_pseudo_labels, tgt_pseudo_confidences + + +class PropagatePseudoLabeler(BasePseudoLabeler): + def __init__(self, num_classes, batch_size=4096, tclip=20., normalize=False): + super().__init__(num_classes) + self.batch_size = batch_size + self.tclip = tclip + self.normalize = normalize + + def pseudo_label_tgt(self, src_test_collection, tgt_test_collection): + """ + pseudo label target samples. + Args: + src_test_collection: (n_src, n_rkhs) + tgt_test_collection: (n_tgt, n_rkhs) + + Returns: + tgt_pseudo_label : (n_tgt, num_classes) contains pseudo label of entire target samples + """ + src_features = src_test_collection['features'] + tgt_features = tgt_test_collection['features'] + src_true_labels = src_test_collection['true_labels'] + + n_src = src_features.size(0) + n_tgt = tgt_features.size(0) + + assert src_features.size(1) == tgt_features.size(1) + n_rkhs = src_features.size(1) + + num_batches = (n_src + n_tgt) // self.batch_size + 1 + src_batch_sizes = [n_src // num_batches + 1] * (n_src % num_batches) \ + + [n_src // num_batches] * (num_batches - n_src % num_batches) + tgt_batch_sizes = [n_tgt // num_batches + 1] * (n_tgt % num_batches) \ + + [n_tgt // num_batches] * (num_batches - n_tgt % num_batches) + + src_perm_indices = torch.randperm(n_src).cuda() + tgt_perm_indices = torch.randperm(n_tgt).cuda() + + tgt_pseudo_labels = torch.zeros(n_tgt, self.num_classes).cuda() + + src_index = 0 + tgt_index = 0 + + for i in tqdm.tqdm(range(num_batches), desc='Target pseudo labeling', leave=False, ascii=True): + src_batch_indices = src_perm_indices[src_index:src_index + src_batch_sizes[i]] + tgt_batch_indices = tgt_perm_indices[tgt_index:tgt_index + tgt_batch_sizes[i]] + src_index += src_batch_sizes[i] + tgt_index += tgt_batch_sizes[i] + src_batch_features = src_features[src_batch_indices] + tgt_batch_features = tgt_features[tgt_batch_indices] + src_batch_true_labels = src_true_labels[src_batch_indices] + + n_src_batch = src_batch_features.size(0) + n_tgt_batch = tgt_batch_features.size(0) + + batch_features = torch.cat([src_batch_features, tgt_batch_features], dim=0) + + if self.normalize: + batch_features = F.normalize(batch_features, dim=1) + + raw_scores = torch.mm(batch_features, batch_features.transpose(0, 1)).float() + + if self.normalize: + raw_scores *= self.tclip + else: + raw_scores = raw_scores / n_rkhs ** 0.5 + raw_scores = tanh_clip(raw_scores, clip_val=self.tclip) + + prop_scores = F.softmax(raw_scores, dim=1) + + prop_ts = prop_scores[n_src_batch:, :n_src_batch] + prop_tt = prop_scores[n_src_batch:, n_src_batch:] + + src_one_hot_label = to_one_hot(src_batch_true_labels, self.num_classes) + + # initialize tgt pseudo label + # tgt_batch_pseudo_label = torch.ones(n_tgt_batch, self.num_classes).cuda() / self.num_classes + + # label propagation + # for _ in range(self.lp_iterations): + # tgt_batch_pseudo_label = torch.mm(prop_ts, src_one_hot_label) \ + # + torch.mm(prop_tt, tgt_batch_pseudo_label) + + tgt_batch_pseudo_label = torch.mm( + torch.inverse(torch.eye(n_tgt_batch).cuda() - prop_tt), + torch.mm(prop_ts, src_one_hot_label)) + + tgt_pseudo_labels[tgt_batch_indices] = tgt_batch_pseudo_label + + tgt_pseudo_confidences = torch.max(tgt_pseudo_labels, dim=1)[0] + + return tgt_pseudo_labels, tgt_pseudo_confidences diff --git a/pybind11/CMakeLists.txt b/pybind11/CMakeLists.txt new file mode 100644 index 0000000..85ecd90 --- /dev/null +++ b/pybind11/CMakeLists.txt @@ -0,0 +1,157 @@ +# 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) + +if (POLICY CMP0048) + # cmake warns if loaded from a min-3.0-required parent dir, so silence the warning: + cmake_policy(SET CMP0048 NEW) +endif() + +# CMake versions < 3.4.0 do not support try_compile/pthread checks without C as active language. +if(CMAKE_VERSION VERSION_LESS 3.4.0) + project(pybind11) +else() + project(pybind11 CXX) +endif() + +# 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}) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/tools") + +include(pybind11Tools) + +# 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 "") +set(PYTHON_VERSION_MAJOR ${PYTHON_VERSION_MAJOR} CACHE INTERNAL "") +set(PYTHON_VERSION_MINOR ${PYTHON_VERSION_MINOR} CACHE INTERNAL "") + +# NB: when adding a header don't forget to also add it to setup.py +set(PYBIND11_HEADERS + include/pybind11/detail/class.h + include/pybind11/detail/common.h + include/pybind11/detail/descr.h + include/pybind11/detail/init.h + include/pybind11/detail/internals.h + include/pybind11/detail/typeid.h + include/pybind11/attr.h + include/pybind11/buffer_info.h + include/pybind11/cast.h + include/pybind11/chrono.h + include/pybind11/common.h + include/pybind11/complex.h + include/pybind11/options.h + include/pybind11/eigen.h + include/pybind11/embed.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 +) +string(REPLACE "include/" "${CMAKE_CURRENT_SOURCE_DIR}/include/" + PYBIND11_HEADERS "${PYBIND11_HEADERS}") + +if (PYBIND11_TEST) + add_subdirectory(tests) +endif() + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +# extract project version from source +file(STRINGS "${PYBIND11_INCLUDE_DIR}/pybind11/detail/common.h" pybind11_version_defines + REGEX "#define PYBIND11_VERSION_(MAJOR|MINOR|PATCH) ") +foreach(ver ${pybind11_version_defines}) + if (ver MATCHES "#define PYBIND11_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$") + set(PYBIND11_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "") + endif() +endforeach() +set(${PROJECT_NAME}_VERSION ${PYBIND11_VERSION_MAJOR}.${PYBIND11_VERSION_MINOR}.${PYBIND11_VERSION_PATCH}) +message(STATUS "pybind11 v${${PROJECT_NAME}_VERSION}") + +option (USE_PYTHON_INCLUDE_DIR "Install pybind11 headers in Python include directory instead of default installation prefix" OFF) +if (USE_PYTHON_INCLUDE_DIR) + file(RELATIVE_PATH CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX} ${PYTHON_INCLUDE_DIRS}) +endif() + +if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) # CMake >= 3.0 + # Build an interface library target: + add_library(pybind11 INTERFACE) + add_library(pybind11::pybind11 ALIAS pybind11) # to match exported target + target_include_directories(pybind11 INTERFACE $ + $ + $) + target_compile_options(pybind11 INTERFACE $) + + add_library(module INTERFACE) + add_library(pybind11::module ALIAS module) + if(NOT MSVC) + target_compile_options(module INTERFACE -fvisibility=hidden) + endif() + target_link_libraries(module INTERFACE pybind11::pybind11) + if(WIN32 OR CYGWIN) + target_link_libraries(module INTERFACE $) + elseif(APPLE) + target_link_libraries(module INTERFACE "-undefined dynamic_lookup") + endif() + + add_library(embed INTERFACE) + add_library(pybind11::embed ALIAS embed) + target_link_libraries(embed INTERFACE pybind11::pybind11 $) +endif() + +if (PYBIND11_INSTALL) + install(DIRECTORY ${PYBIND11_INCLUDE_DIR}/pybind11 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + # GNUInstallDirs "DATADIR" wrong here; CMake search path wants "share". + set(PYBIND11_CMAKECONFIG_INSTALL_DIR "share/cmake/${PROJECT_NAME}" CACHE STRING "install path for pybind11Config.cmake") + + configure_package_config_file(tools/${PROJECT_NAME}Config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) + # Remove CMAKE_SIZEOF_VOID_P from ConfigVersion.cmake since the library does + # not depend on architecture specific settings or libraries. + set(_PYBIND11_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P}) + unset(CMAKE_SIZEOF_VOID_P) + write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + VERSION ${${PROJECT_NAME}_VERSION} + COMPATIBILITY AnyNewerVersion) + set(CMAKE_SIZEOF_VOID_P ${_PYBIND11_CMAKE_SIZEOF_VOID_P}) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + tools/FindPythonLibsNew.cmake + tools/pybind11Tools.cmake + DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) + + if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) + if(NOT PYBIND11_EXPORT_NAME) + set(PYBIND11_EXPORT_NAME "${PROJECT_NAME}Targets") + endif() + + install(TARGETS pybind11 module embed + EXPORT "${PYBIND11_EXPORT_NAME}") + if(PYBIND11_MASTER_PROJECT) + install(EXPORT "${PYBIND11_EXPORT_NAME}" + NAMESPACE "${PROJECT_NAME}::" + DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR}) + endif() + endif() +endif() diff --git a/pybind11/CONTRIBUTING.md b/pybind11/CONTRIBUTING.md new file mode 100644 index 0000000..01596d9 --- /dev/null +++ b/pybind11/CONTRIBUTING.md @@ -0,0 +1,49 @@ +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. +* Please run ``flake8`` and ``tools/check-style.sh`` to check your code matches + the project style. (Note that ``check-style.sh`` requires ``gawk``.) +* This project has a strong focus on providing general solutions using a + minimal amount of code, thus small pull requests are greatly preferred. + +### Licensing of contributions + +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. + +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/pybind11/ISSUE_TEMPLATE.md b/pybind11/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..75df399 --- /dev/null +++ b/pybind11/ISSUE_TEMPLATE.md @@ -0,0 +1,17 @@ +Make sure you've completed the following steps before submitting your issue -- thank you! + +1. Check if your question has already been answered in the [FAQ](http://pybind11.readthedocs.io/en/latest/faq.html) section. +2. Make sure you've read the [documentation](http://pybind11.readthedocs.io/en/latest/). Your issue may be addressed there. +3. If those resources didn't help and you only have a short question (not a bug report), consider asking in the [Gitter chat room](https://gitter.im/pybind/Lobby). +4. If you have a genuine bug report or a more complex question which is not answered in the previous items (or not suitable for chat), please fill in the details below. +5. Include a self-contained and minimal piece of code that reproduces the problem. If that's not possible, try to make the description as clear as possible. + +*After reading, remove this checklist and the template text in parentheses below.* + +## Issue description + +(Provide a short description, state the expected behavior and what actually happens.) + +## Reproducible example code + +(The code should be minimal, have 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 to diagnose the issue.) diff --git a/pybind11/LICENSE b/pybind11/LICENSE new file mode 100644 index 0000000..6f15578 --- /dev/null +++ b/pybind11/LICENSE @@ -0,0 +1,29 @@ +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. + +Please also refer to the file CONTRIBUTING.md, which clarifies licensing of +external contributions to this project including patches, pull requests, etc. diff --git a/pybind11/MANIFEST.in b/pybind11/MANIFEST.in new file mode 100644 index 0000000..6e57bae --- /dev/null +++ b/pybind11/MANIFEST.in @@ -0,0 +1,2 @@ +recursive-include include/pybind11 *.h +include LICENSE README.md CONTRIBUTING.md diff --git a/pybind11/README.md b/pybind11/README.md new file mode 100644 index 0000000..135f9e1 --- /dev/null +++ b/pybind11/README.md @@ -0,0 +1,127 @@ +![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=master)](http://pybind11.readthedocs.org/en/master/?badge=master) +[![Documentation Status](https://readthedocs.org/projects/pybind11/badge/?version=stable)](http://pybind11.readthedocs.org/en/stable/?badge=stable) +[![Gitter chat](https://img.shields.io/gitter/room/gitterHQ/gitter.svg)](https://gitter.im/pybind/Lobby) +[![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 ~4K lines of code and depend on +Python (2.7 or 3.x, or PyPy2.7 >= 5.7) 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/master](http://pybind11.readthedocs.org/en/master). +A PDF version of the manual is available +[here](https://media.readthedocs.org/pdf/pybind11/master/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 +- 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: + +- Python 2.7, 3.x, and PyPy (PyPy2.7 >= 5.7) are supported with an + implementation-agnostic interface. + +- 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](http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf) a binary + size reduction of **5.4x** and compile time reduction by **5.8x**. + +- Function signatures are precomputed at compile time (using ``constexpr``), + 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 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or newer) +2. GCC 4.8 or newer +3. Microsoft Visual Studio 2015 Update 3 or newer +4. Intel C++ compiler 17 or newer (16 with pybind11 v2.0 and 15 with pybind11 v2.0 and 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](http://rgl.epfl.ch/people/wjakob). +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, +Ivan Smirnov, and +Patrick Stewart. + +### 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/pybind11/docs/Doxyfile b/pybind11/docs/Doxyfile new file mode 100644 index 0000000..1b9d129 --- /dev/null +++ b/pybind11/docs/Doxyfile @@ -0,0 +1,20 @@ +PROJECT_NAME = pybind11 +INPUT = ../include/pybind11/ +RECURSIVE = YES + +GENERATE_HTML = NO +GENERATE_LATEX = NO +GENERATE_XML = YES +XML_OUTPUT = .build/doxygenxml +XML_PROGRAMLISTING = YES + +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +EXPAND_AS_DEFINED = PYBIND11_RUNTIME_EXCEPTION + +ALIASES = "rst=\verbatim embed:rst" +ALIASES += "endrst=\endverbatim" + +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = NO diff --git a/pybind11/docs/_static/theme_overrides.css b/pybind11/docs/_static/theme_overrides.css new file mode 100644 index 0000000..1071809 --- /dev/null +++ b/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/pybind11/docs/advanced/cast/chrono.rst b/pybind11/docs/advanced/cast/chrono.rst new file mode 100644 index 0000000..8c6b3d7 --- /dev/null +++ b/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/pybind11/docs/advanced/cast/custom.rst b/pybind11/docs/advanced/cast/custom.rst new file mode 100644 index 0000000..e4f99ac --- /dev/null +++ b/pybind11/docs/advanced/cast/custom.rst @@ -0,0 +1,91 @@ +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 + +.. note:: + + A ``type_caster`` defined with ``PYBIND11_TYPE_CASTER(T, ...)`` requires + that ``T`` is default-constructible (``value`` is first default constructed + and then ``load()`` assigns to it). + +.. 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/pybind11/docs/advanced/cast/eigen.rst b/pybind11/docs/advanced/cast/eigen.rst new file mode 100644 index 0000000..7cbeac0 --- /dev/null +++ b/pybind11/docs/advanced/cast/eigen.rst @@ -0,0 +1,310 @@ +Eigen +##### + +`Eigen `_ is C++ header-based library for dense and +sparse linear algebra. Due to its popularity and widespread adoption, pybind11 +provides transparent conversion and limited mapping support between Eigen and +Scientific Python linear algebra data types. + +To enable the built-in Eigen support you must include the optional header file +:file:`pybind11/eigen.h`. + +Pass-by-value +============= + +When binding a function with ordinary Eigen dense object arguments (for +example, ``Eigen::MatrixXd``), pybind11 will accept any input value that is +already (or convertible to) a ``numpy.ndarray`` with dimensions compatible with +the Eigen type, copy its values into a temporary Eigen variable of the +appropriate type, then call the function with this temporary variable. + +Sparse matrices are similarly copied to or from +``scipy.sparse.csr_matrix``/``scipy.sparse.csc_matrix`` objects. + +Pass-by-reference +================= + +One major limitation of the above is that every data conversion implicitly +involves a copy, which can be both expensive (for large matrices) and disallows +binding functions that change their (Matrix) arguments. Pybind11 allows you to +work around this by using Eigen's ``Eigen::Ref`` class much as you +would when writing a function taking a generic type in Eigen itself (subject to +some limitations discussed below). + +When calling a bound function accepting a ``Eigen::Ref`` +type, pybind11 will attempt to avoid copying by using an ``Eigen::Map`` object +that maps into the source ``numpy.ndarray`` data: this requires both that the +data types are the same (e.g. ``dtype='float64'`` and ``MatrixType::Scalar`` is +``double``); and that the storage is layout compatible. The latter limitation +is discussed in detail in the section below, and requires careful +consideration: by default, numpy matrices and eigen matrices are *not* storage +compatible. + +If the numpy matrix cannot be used as is (either because its types differ, e.g. +passing an array of integers to an Eigen parameter requiring doubles, or +because the storage is incompatible), pybind11 makes a temporary copy and +passes the copy instead. + +When a bound function parameter is instead ``Eigen::Ref`` (note the +lack of ``const``), pybind11 will only allow the function to be called if it +can be mapped *and* if the numpy array is writeable (that is +``a.flags.writeable`` is true). Any access (including modification) made to +the passed variable will be transparently carried out directly on the +``numpy.ndarray``. + +This means you can can write code such as the following and have it work as +expected: + +.. code-block:: cpp + + void scale_by_2(Eigen::Ref v) { + v *= 2; + } + +Note, however, that you will likely run into limitations due to numpy and +Eigen's difference default storage order for data; see the below section on +:ref:`storage_orders` for details on how to bind code that won't run into such +limitations. + +.. note:: + + Passing by reference is not supported for sparse types. + +Returning values to Python +========================== + +When returning an ordinary dense Eigen matrix type to numpy (e.g. +``Eigen::MatrixXd`` or ``Eigen::RowVectorXf``) pybind11 keeps the matrix and +returns a numpy array that directly references the Eigen matrix: no copy of the +data is performed. The numpy array will have ``array.flags.owndata`` set to +``False`` to indicate that it does not own the data, and the lifetime of the +stored Eigen matrix will be tied to the returned ``array``. + +If you bind a function with a non-reference, ``const`` return type (e.g. +``const Eigen::MatrixXd``), the same thing happens except that pybind11 also +sets the numpy array's ``writeable`` flag to false. + +If you return an lvalue reference or pointer, the usual pybind11 rules apply, +as dictated by the binding function's return value policy (see the +documentation on :ref:`return_value_policies` for full details). That means, +without an explicit return value policy, lvalue references will be copied and +pointers will be managed by pybind11. In order to avoid copying, you should +explicitly specify an appropriate return value policy, as in the following +example: + +.. code-block:: cpp + + class MyClass { + Eigen::MatrixXd big_mat = Eigen::MatrixXd::Zero(10000, 10000); + public: + Eigen::MatrixXd &getMatrix() { return big_mat; } + const Eigen::MatrixXd &viewMatrix() { return big_mat; } + }; + + // Later, in binding code: + py::class_(m, "MyClass") + .def(py::init<>()) + .def("copy_matrix", &MyClass::getMatrix) // Makes a copy! + .def("get_matrix", &MyClass::getMatrix, py::return_value_policy::reference_internal) + .def("view_matrix", &MyClass::viewMatrix, py::return_value_policy::reference_internal) + ; + +.. code-block:: python + + a = MyClass() + m = a.get_matrix() # flags.writeable = True, flags.owndata = False + v = a.view_matrix() # flags.writeable = False, flags.owndata = False + c = a.copy_matrix() # flags.writeable = True, flags.owndata = True + # m[5,6] and v[5,6] refer to the same element, c[5,6] does not. + +Note in this example that ``py::return_value_policy::reference_internal`` is +used to tie the life of the MyClass object to the life of the returned arrays. + +You may also return an ``Eigen::Ref``, ``Eigen::Map`` or other map-like Eigen +object (for example, the return value of ``matrix.block()`` and related +methods) that map into a dense Eigen type. When doing so, the default +behaviour of pybind11 is to simply reference the returned data: you must take +care to ensure that this data remains valid! You may ask pybind11 to +explicitly *copy* such a return value by using the +``py::return_value_policy::copy`` policy when binding the function. You may +also use ``py::return_value_policy::reference_internal`` or a +``py::keep_alive`` to ensure the data stays valid as long as the returned numpy +array does. + +When returning such a reference of map, pybind11 additionally respects the +readonly-status of the returned value, marking the numpy array as non-writeable +if the reference or map was itself read-only. + +.. note:: + + Sparse types are always copied when returned. + +.. _storage_orders: + +Storage orders +============== + +Passing arguments via ``Eigen::Ref`` has some limitations that you must be +aware of in order to effectively pass matrices by reference. First and +foremost is that the default ``Eigen::Ref`` class requires +contiguous storage along columns (for column-major types, the default in Eigen) +or rows if ``MatrixType`` is specifically an ``Eigen::RowMajor`` storage type. +The former, Eigen's default, is incompatible with ``numpy``'s default row-major +storage, and so you will not be able to pass numpy arrays to Eigen by reference +without making one of two changes. + +(Note that this does not apply to vectors (or column or row matrices): for such +types the "row-major" and "column-major" distinction is meaningless). + +The first approach is to change the use of ``Eigen::Ref`` to the +more general ``Eigen::Ref>`` (or similar type with a fully dynamic stride type in the +third template argument). Since this is a rather cumbersome type, pybind11 +provides a ``py::EigenDRef`` type alias for your convenience (along +with EigenDMap for the equivalent Map, and EigenDStride for just the stride +type). + +This type allows Eigen to map into any arbitrary storage order. This is not +the default in Eigen for performance reasons: contiguous storage allows +vectorization that cannot be done when storage is not known to be contiguous at +compile time. The default ``Eigen::Ref`` stride type allows non-contiguous +storage along the outer dimension (that is, the rows of a column-major matrix +or columns of a row-major matrix), but not along the inner dimension. + +This type, however, has the added benefit of also being able to map numpy array +slices. For example, the following (contrived) example uses Eigen with a numpy +slice to multiply by 2 all coefficients that are both on even rows (0, 2, 4, +...) and in columns 2, 5, or 8: + +.. code-block:: cpp + + m.def("scale", [](py::EigenDRef m, double c) { m *= c; }); + +.. code-block:: python + + # a = np.array(...) + scale_by_2(myarray[0::2, 2:9:3]) + +The second approach to avoid copying is more intrusive: rearranging the +underlying data types to not run into the non-contiguous storage problem in the +first place. In particular, that means using matrices with ``Eigen::RowMajor`` +storage, where appropriate, such as: + +.. code-block:: cpp + + using RowMatrixXd = Eigen::Matrix; + // Use RowMatrixXd instead of MatrixXd + +Now bound functions accepting ``Eigen::Ref`` arguments will be +callable with numpy's (default) arrays without involving a copying. + +You can, alternatively, change the storage order that numpy arrays use by +adding the ``order='F'`` option when creating an array: + +.. code-block:: python + + myarray = np.array(source, order='F') + +Such an object will be passable to a bound function accepting an +``Eigen::Ref`` (or similar column-major Eigen type). + +One major caveat with this approach, however, is that it is not entirely as +easy as simply flipping all Eigen or numpy usage from one to the other: some +operations may alter the storage order of a numpy array. For example, ``a2 = +array.transpose()`` results in ``a2`` being a view of ``array`` that references +the same data, but in the opposite storage order! + +While this approach allows fully optimized vectorized calculations in Eigen, it +cannot be used with array slices, unlike the first approach. + +When *returning* a matrix to Python (either a regular matrix, a reference via +``Eigen::Ref<>``, or a map/block into a matrix), no special storage +consideration is required: the created numpy array will have the required +stride that allows numpy to properly interpret the array, whatever its storage +order. + +Failing rather than copying +=========================== + +The default behaviour when binding ``Eigen::Ref`` eigen +references is to copy matrix values when passed a numpy array that does not +conform to the element type of ``MatrixType`` or does not have a compatible +stride layout. If you want to explicitly avoid copying in such a case, you +should bind arguments using the ``py::arg().noconvert()`` annotation (as +described in the :ref:`nonconverting_arguments` documentation). + +The following example shows an example of arguments that don't allow data +copying to take place: + +.. code-block:: cpp + + // The method and function to be bound: + class MyClass { + // ... + double some_method(const Eigen::Ref &matrix) { /* ... */ } + }; + float some_function(const Eigen::Ref &big, + const Eigen::Ref &small) { + // ... + } + + // The associated binding code: + using namespace pybind11::literals; // for "arg"_a + py::class_(m, "MyClass") + // ... other class definitions + .def("some_method", &MyClass::some_method, py::arg().noconvert()); + + m.def("some_function", &some_function, + "big"_a.noconvert(), // <- Don't allow copying for this arg + "small"_a // <- This one can be copied if needed + ); + +With the above binding code, attempting to call the the ``some_method(m)`` +method on a ``MyClass`` object, or attempting to call ``some_function(m, m2)`` +will raise a ``RuntimeError`` rather than making a temporary copy of the array. +It will, however, allow the ``m2`` argument to be copied into a temporary if +necessary. + +Note that explicitly specifying ``.noconvert()`` is not required for *mutable* +Eigen references (e.g. ``Eigen::Ref`` without ``const`` on the +``MatrixXd``): mutable references will never be called with a temporary copy. + +Vectors versus column/row matrices +================================== + +Eigen and numpy have fundamentally different notions of a vector. In Eigen, a +vector is simply a matrix with the number of columns or rows set to 1 at +compile time (for a column vector or row vector, respectively). Numpy, in +contrast, has comparable 2-dimensional 1xN and Nx1 arrays, but *also* has +1-dimensional arrays of size N. + +When passing a 2-dimensional 1xN or Nx1 array to Eigen, the Eigen type must +have matching dimensions: That is, you cannot pass a 2-dimensional Nx1 numpy +array to an Eigen value expecting a row vector, or a 1xN numpy array as a +column vector argument. + +On the other hand, pybind11 allows you to pass 1-dimensional arrays of length N +as Eigen parameters. If the Eigen type can hold a column vector of length N it +will be passed as such a column vector. If not, but the Eigen type constraints +will accept a row vector, it will be passed as a row vector. (The column +vector takes precedence when both are supported, for example, when passing a +1D numpy array to a MatrixXd argument). Note that the type need not be +expicitly a vector: it is permitted to pass a 1D numpy array of size 5 to an +Eigen ``Matrix``: you would end up with a 1x5 Eigen matrix. +Passing the same to an ``Eigen::MatrixXd`` would result in a 5x1 Eigen matrix. + +When returning an eigen vector to numpy, the conversion is ambiguous: a row +vector of length 4 could be returned as either a 1D array of length 4, or as a +2D array of size 1x4. When encoutering such a situation, pybind11 compromises +by considering the returned Eigen type: if it is a compile-time vector--that +is, the type has either the number of rows or columns set to 1 at compile +time--pybind11 converts to a 1D numpy array when returning the value. For +instances that are a vector only at run-time (e.g. ``MatrixXd``, +``Matrix``), pybind11 returns the vector as a 2D array to +numpy. If this isn't want you want, you can use ``array.reshape(...)`` to get +a view of the same data in the desired dimensions. + +.. 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/pybind11/docs/advanced/cast/functional.rst b/pybind11/docs/advanced/cast/functional.rst new file mode 100644 index 0000000..d9b4605 --- /dev/null +++ b/pybind11/docs/advanced/cast/functional.rst @@ -0,0 +1,109 @@ +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_MODULE(example, m) { + m.def("func_arg", &func_arg); + m.def("func_ret", &func_ret); + m.def("func_cpp", &func_cpp); + } + +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/pybind11/docs/advanced/cast/index.rst b/pybind11/docs/advanced/cast/index.rst new file mode 100644 index 0000000..54c1057 --- /dev/null +++ b/pybind11/docs/advanced/cast/index.rst @@ -0,0 +1,42 @@ +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 + strings + stl + functional + chrono + eigen + custom + diff --git a/pybind11/docs/advanced/cast/overview.rst b/pybind11/docs/advanced/cast/overview.rst new file mode 100644 index 0000000..b0e32a5 --- /dev/null +++ b/pybind11/docs/advanced/cast/overview.rst @@ -0,0 +1,165 @@ +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` | ++------------------------------------+---------------------------+-------------------------------+ +| ``char16_t`` | UTF-16 character literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``char32_t`` | UTF-32 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 char16_t *`` | UTF-16 string literal | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``const char32_t *`` | UTF-32 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::u16string`` | STL dynamic UTF-16 string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::u32string`` | STL dynamic UTF-32 string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::wstring`` | STL dynamic wide string | :file:`pybind11/pybind11.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::string_view``, | STL C++17 string views | :file:`pybind11/pybind11.h` | +| ``std::u16string_view``, etc. | | | ++------------------------------------+---------------------------+-------------------------------+ +| ``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::deque`` | STL double-ended queue | :file:`pybind11/stl.h` | ++------------------------------------+---------------------------+-------------------------------+ +| ``std::valarray`` | STL value 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::variant<...>`` | Type-safe union (C++17) | :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/pybind11/docs/advanced/cast/stl.rst b/pybind11/docs/advanced/cast/stl.rst new file mode 100644 index 0000000..e48409f --- /dev/null +++ b/pybind11/docs/advanced/cast/stl.rst @@ -0,0 +1,240 @@ +STL containers +############## + +Automatic conversion +==================== + +When including the additional header file :file:`pybind11/stl.h`, conversions +between ``std::vector<>``/``std::deque<>``/``std::list<>``/``std::array<>``, +``std::set<>``/``std::unordered_set<>``, and +``std::map<>``/``std::unordered_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_stl.cpp` contains a complete + example that demonstrates how to pass STL data types in more detail. + +.. _cpp17_container_casters: + +C++17 library containers +======================== + +The :file:`pybind11/stl.h` header also includes support for ``std::optional<>`` +and ``std::variant<>``. These require a C++17 compiler and standard library. +In C++14 mode, ``std::experimental::optional<>`` is supported if available. + +Various versions of these containers also exist for C++11 (e.g. in Boost). +pybind11 provides an easy way to specialize the ``type_caster`` for such +types: + +.. code-block:: cpp + + // `boost::optional` as an example -- can be any `std::optional`-like container + namespace pybind11 { namespace detail { + template + struct type_caster> : optional_caster> {}; + }} + +The above should be placed in a header file and included in all translation units +where automatic conversion is needed. Similarly, a specialization can be provided +for custom variant types: + +.. code-block:: cpp + + // `boost::variant` as an example -- can be any `std::variant`-like container + namespace pybind11 { namespace detail { + template + struct type_caster> : variant_caster> {}; + + // Specifies the function used to visit the variant -- `apply_visitor` instead of `visit` + template <> + struct visit_helper { + template + static auto call(Args &&...args) -> decltype(boost::apply_visitor(args...)) { + return boost::apply_visitor(args...); + } + }; + }} // namespace pybind11::detail + +The ``visit_helper`` specialization is not required if your ``name::variant`` provides +a ``name::visit()`` function. For any other function name, the specialization must be +included to tell pybind11 how to visit the variant. + +.. note:: + + pybind11 only supports the modern implementation of ``boost::variant`` + which makes use of variadic templates. This requires Boost 1.56 or newer. + Additionally, on Windows, MSVC 2017 is required because ``boost::variant`` + falls back to the old non-variadic implementation on MSVC 2015. + +.. _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 (typically via a +common header) 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 */ + // .... + +.. 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. + +.. _stl_bind: + +Binding STL containers +====================== + +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"); + +When binding STL containers pybind11 considers the types of the container's +elements to decide whether the container should be confined to the local module +(via the :ref:`module_local` feature). If the container element types are +anything other than already-bound custom types bound without +``py::module_local()`` the container binding will have ``py::module_local()`` +applied. This includes converting types such as numeric types, strings, Eigen +types; and types that have not yet been bound at the time of the stl container +binding. This module-local binding is designed to avoid potential conflicts +between module bindings (for example, from two separate modules each attempting +to bind ``std::vector`` as a python type). + +It is possible to override this behavior to force a definition to be either +module-local or global. To do so, you can pass the attributes +``py::module_local()`` (to make the binding module-local) or +``py::module_local(false)`` (to make the binding global) into the +``py::bind_vector`` or ``py::bind_map`` arguments: + +.. code-block:: cpp + + py::bind_vector>(m, "VectorInt", py::module_local(false)); + +Note, however, that such a global binding would make it impossible to load this +module at the same time as any other pybind module that also attempts to bind +the same container type (``std::vector`` in the above example). + +See :ref:`module_local` for more details on module-local bindings. + +.. seealso:: + + The file :file:`tests/test_stl_binders.cpp` shows how to use the + convenience STL container wrappers. diff --git a/pybind11/docs/advanced/cast/strings.rst b/pybind11/docs/advanced/cast/strings.rst new file mode 100644 index 0000000..e25701e --- /dev/null +++ b/pybind11/docs/advanced/cast/strings.rst @@ -0,0 +1,305 @@ +Strings, bytes and Unicode conversions +###################################### + +.. note:: + + This section discusses string handling in terms of Python 3 strings. For + Python 2.7, replace all occurrences of ``str`` with ``unicode`` and + ``bytes`` with ``str``. Python 2.7 users may find it best to use ``from + __future__ import unicode_literals`` to avoid unintentionally using ``str`` + instead of ``unicode``. + +Passing Python strings to C++ +============================= + +When a Python ``str`` is passed from Python to a C++ function that accepts +``std::string`` or ``char *`` as arguments, pybind11 will encode the Python +string to UTF-8. All Python ``str`` can be encoded in UTF-8, so this operation +does not fail. + +The C++ language is encoding agnostic. It is the responsibility of the +programmer to track encodings. It's often easiest to simply `use UTF-8 +everywhere `_. + +.. code-block:: c++ + + m.def("utf8_test", + [](const std::string &s) { + cout << "utf-8 is icing on the cake.\n"; + cout << s; + } + ); + m.def("utf8_charptr", + [](const char *s) { + cout << "My favorite food is\n"; + cout << s; + } + ); + +.. code-block:: python + + >>> utf8_test('🎂') + utf-8 is icing on the cake. + 🎂 + + >>> utf8_charptr('🍕') + My favorite food is + 🍕 + +.. note:: + + Some terminal emulators do not support UTF-8 or emoji fonts and may not + display the example above correctly. + +The results are the same whether the C++ function accepts arguments by value or +reference, and whether or not ``const`` is used. + +Passing bytes to C++ +-------------------- + +A Python ``bytes`` object will be passed to C++ functions that accept +``std::string`` or ``char*`` *without* conversion. On Python 3, in order to +make a function *only* accept ``bytes`` (and not ``str``), declare it as taking +a ``py::bytes`` argument. + + +Returning C++ strings to Python +=============================== + +When a C++ function returns a ``std::string`` or ``char*`` to a Python caller, +**pybind11 will assume that the string is valid UTF-8** and will decode it to a +native Python ``str``, using the same API as Python uses to perform +``bytes.decode('utf-8')``. If this implicit conversion fails, pybind11 will +raise a ``UnicodeDecodeError``. + +.. code-block:: c++ + + m.def("std_string_return", + []() { + return std::string("This string needs to be UTF-8 encoded"); + } + ); + +.. code-block:: python + + >>> isinstance(example.std_string_return(), str) + True + + +Because UTF-8 is inclusive of pure ASCII, there is never any issue with +returning a pure ASCII string to Python. If there is any possibility that the +string is not pure ASCII, it is necessary to ensure the encoding is valid +UTF-8. + +.. warning:: + + Implicit conversion assumes that a returned ``char *`` is null-terminated. + If there is no null terminator a buffer overrun will occur. + +Explicit conversions +-------------------- + +If some C++ code constructs a ``std::string`` that is not a UTF-8 string, one +can perform a explicit conversion and return a ``py::str`` object. Explicit +conversion has the same overhead as implicit conversion. + +.. code-block:: c++ + + // This uses the Python C API to convert Latin-1 to Unicode + m.def("str_output", + []() { + std::string s = "Send your r\xe9sum\xe9 to Alice in HR"; // Latin-1 + py::str py_s = PyUnicode_DecodeLatin1(s.data(), s.length()); + return py_s; + } + ); + +.. code-block:: python + + >>> str_output() + 'Send your résumé to Alice in HR' + +The `Python C API +`_ provides +several built-in codecs. + + +One could also use a third party encoding library such as libiconv to transcode +to UTF-8. + +Return C++ strings without conversion +------------------------------------- + +If the data in a C++ ``std::string`` does not represent text and should be +returned to Python as ``bytes``, then one can return the data as a +``py::bytes`` object. + +.. code-block:: c++ + + m.def("return_bytes", + []() { + std::string s("\xba\xd0\xba\xd0"); // Not valid UTF-8 + return py::bytes(s); // Return the data without transcoding + } + ); + +.. code-block:: python + + >>> example.return_bytes() + b'\xba\xd0\xba\xd0' + + +Note the asymmetry: pybind11 will convert ``bytes`` to ``std::string`` without +encoding, but cannot convert ``std::string`` back to ``bytes`` implicitly. + +.. code-block:: c++ + + m.def("asymmetry", + [](std::string s) { // Accepts str or bytes from Python + return s; // Looks harmless, but implicitly converts to str + } + ); + +.. code-block:: python + + >>> isinstance(example.asymmetry(b"have some bytes"), str) + True + + >>> example.asymmetry(b"\xba\xd0\xba\xd0") # invalid utf-8 as bytes + UnicodeDecodeError: 'utf-8' codec can't decode byte 0xba in position 0: invalid start byte + + +Wide character strings +====================== + +When a Python ``str`` is passed to a C++ function expecting ``std::wstring``, +``wchar_t*``, ``std::u16string`` or ``std::u32string``, the ``str`` will be +encoded to UTF-16 or UTF-32 depending on how the C++ compiler implements each +type, in the platform's native endianness. When strings of these types are +returned, they are assumed to contain valid UTF-16 or UTF-32, and will be +decoded to Python ``str``. + +.. code-block:: c++ + + #define UNICODE + #include + + m.def("set_window_text", + [](HWND hwnd, std::wstring s) { + // Call SetWindowText with null-terminated UTF-16 string + ::SetWindowText(hwnd, s.c_str()); + } + ); + m.def("get_window_text", + [](HWND hwnd) { + const int buffer_size = ::GetWindowTextLength(hwnd) + 1; + auto buffer = std::make_unique< wchar_t[] >(buffer_size); + + ::GetWindowText(hwnd, buffer.data(), buffer_size); + + std::wstring text(buffer.get()); + + // wstring will be converted to Python str + return text; + } + ); + +.. warning:: + + Wide character strings may not work as described on Python 2.7 or Python + 3.3 compiled with ``--enable-unicode=ucs2``. + +Strings in multibyte encodings such as Shift-JIS must transcoded to a +UTF-8/16/32 before being returned to Python. + + +Character literals +================== + +C++ functions that accept character literals as input will receive the first +character of a Python ``str`` as their input. If the string is longer than one +Unicode character, trailing characters will be ignored. + +When a character literal is returned from C++ (such as a ``char`` or a +``wchar_t``), it will be converted to a ``str`` that represents the single +character. + +.. code-block:: c++ + + m.def("pass_char", [](char c) { return c; }); + m.def("pass_wchar", [](wchar_t w) { return w; }); + +.. code-block:: python + + >>> example.pass_char('A') + 'A' + +While C++ will cast integers to character types (``char c = 0x65;``), pybind11 +does not convert Python integers to characters implicitly. The Python function +``chr()`` can be used to convert integers to characters. + +.. code-block:: python + + >>> example.pass_char(0x65) + TypeError + + >>> example.pass_char(chr(0x65)) + 'A' + +If the desire is to work with an 8-bit integer, use ``int8_t`` or ``uint8_t`` +as the argument type. + +Grapheme clusters +----------------- + +A single grapheme may be represented by two or more Unicode characters. For +example 'é' is usually represented as U+00E9 but can also be expressed as the +combining character sequence U+0065 U+0301 (that is, the letter 'e' followed by +a combining acute accent). The combining character will be lost if the +two-character sequence is passed as an argument, even though it renders as a +single grapheme. + +.. code-block:: python + + >>> example.pass_wchar('é') + 'é' + + >>> combining_e_acute = 'e' + '\u0301' + + >>> combining_e_acute + 'é' + + >>> combining_e_acute == 'é' + False + + >>> example.pass_wchar(combining_e_acute) + 'e' + +Normalizing combining characters before passing the character literal to C++ +may resolve *some* of these issues: + +.. code-block:: python + + >>> example.pass_wchar(unicodedata.normalize('NFC', combining_e_acute)) + 'é' + +In some languages (Thai for example), there are `graphemes that cannot be +expressed as a single Unicode code point +`_, so there is +no way to capture them in a C++ character type. + + +C++17 string views +================== + +C++17 string views are automatically supported when compiling in C++17 mode. +They follow the same rules for encoding and decoding as the corresponding STL +string type (for example, a ``std::u16string_view`` argument will be passed +UTF-16-encoded data, and a returned ``std::string_view`` will be decoded as +UTF-8). + +References +========== + +* `The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) `_ +* `C++ - Using STL Strings at Win32 API Boundaries `_ diff --git a/pybind11/docs/advanced/classes.rst b/pybind11/docs/advanced/classes.rst new file mode 100644 index 0000000..c7dbc67 --- /dev/null +++ b/pybind11/docs/advanced/classes.rst @@ -0,0 +1,1082 @@ +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_MODULE(example, m) { + py::class_(m, "Animal") + .def("go", &Animal::go); + + py::class_(m, "Dog") + .def(py::init<>()); + + m.def("call_go", &call_go); + } + +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 in C++ (must match Python name) */ + 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, which defines the name of function in Python. This is required +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: 2,3 + + PYBIND11_MODULE(example, m) { + py::class_(m, "Animal") + .def(py::init<>()) + .def("go", &Animal::go); + + py::class_(m, "Dog") + .def(py::init<>()); + + m.def("call_go", &call_go); + } + +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. + +Bindings should be made against the actual class, not the trampoline helper class. + +.. code-block:: cpp + :emphasize-lines: 3 + + py::class_(m, "Animal"); + .def(py::init<>()) + .def("go", &PyAnimal::go); /* <--- THIS IS WRONG, use &Animal::go */ + +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! ' + +If you are defining a custom constructor in a derived Python class, you *must* +ensure that you explicitly call the bound C++ constructor using ``__init__``, +*regardless* of whether it is a default constructor or not. Otherwise, the +memory for the C++ portion of the instance will be left uninitialized, which +will generally leave the C++ instance in an invalid state and cause undefined +behavior if the C++ instance is subsequently used. + +Here is an example: + +.. code-block:: python + + class Dachschund(Dog): + def __init__(self, name): + Dog.__init__(self) # Without this, undefined behavior may occur if the C++ portions are referenced. + self.name = name + def bark(self): + return "yap!" + +Note that a direct ``__init__`` constructor *should be called*, and ``super()`` +should not be used. For simple cases of linear inheritance, ``super()`` +may work, but once you begin mixing Python and C++ multiple inheritance, +things will fall apart due to differences between Python's MRO and C++'s +mechanisms. + +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 Animal { + public: + std::string go(int n_times) override { + std::string result; + for (int i=0; i class PyAnimal : public AnimalBase { + public: + 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 { + public: + 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_aliases: + +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_virtual_functions.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 of the appropriate arguments actually exists on the +C++ side. To extend this to more general cases, pybind11 makes it possible +to bind factory functions as constructors. For example, suppose you have a +class like this: + +.. code-block:: cpp + + class Example { + private: + Example(int); // private constructor + public: + // Factory function: + static Example create(int a) { return Example(a); } + }; + + py::class_(m, "Example") + .def(py::init(&Example::create)); + +While it is possible to create a straightforward binding of the static +``create`` method, it may sometimes be preferable to expose it as a constructor +on the Python side. This can be accomplished by calling ``.def(py::init(...))`` +with the function reference returning the new instance passed as an argument. +It is also possible to use this approach to bind a function returning a new +instance by raw pointer or by the holder (e.g. ``std::unique_ptr``). + +The following example shows the different approaches: + +.. code-block:: cpp + + class Example { + private: + Example(int); // private constructor + public: + // Factory function - returned by value: + static Example create(int a) { return Example(a); } + + // These constructors are publicly callable: + Example(double); + Example(int, int); + Example(std::string); + }; + + py::class_(m, "Example") + // Bind the factory function as a constructor: + .def(py::init(&Example::create)) + // Bind a lambda function returning a pointer wrapped in a holder: + .def(py::init([](std::string arg) { + return std::unique_ptr(new Example(arg)); + })) + // Return a raw pointer: + .def(py::init([](int a, int b) { return new Example(a, b); })) + // You can mix the above with regular C++ constructor bindings as well: + .def(py::init()) + ; + +When the constructor is invoked from Python, pybind11 will call the factory +function and store the resulting C++ instance in the Python instance. + +When combining factory functions constructors with :ref:`virtual function +trampolines ` there are two approaches. The first is to +add a constructor to the alias class that takes a base value by +rvalue-reference. If such a constructor is available, it will be used to +construct an alias instance from the value returned by the factory function. +The second option is to provide two factory functions to ``py::init()``: the +first will be invoked when no alias class is required (i.e. when the class is +being used but not inherited from in Python), and the second will be invoked +when an alias is required. + +You can also specify a single factory function that always returns an alias +instance: this will result in behaviour similar to ``py::init_alias<...>()``, +as described in the :ref:`extended trampoline class documentation +`. + +The following example shows the different factory approaches for a class with +an alias: + +.. code-block:: cpp + + #include + class Example { + public: + // ... + virtual ~Example() = default; + }; + class PyExample : public Example { + public: + using Example::Example; + PyExample(Example &&base) : Example(std::move(base)) {} + }; + py::class_(m, "Example") + // Returns an Example pointer. If a PyExample is needed, the Example + // instance will be moved via the extra constructor in PyExample, above. + .def(py::init([]() { return new Example(); })) + // Two callbacks: + .def(py::init([]() { return new Example(); } /* no alias needed */, + []() { return new PyExample(); } /* alias needed */)) + // *Always* returns an alias instance (like py::init_alias<>()) + .def(py::init([]() { return new PyExample(); })) + ; + +Brace initialization +-------------------- + +``pybind11::init<>`` internally uses C++11 brace initialization to call the +constructor of the target class. This means that it can be used to bind +*implicit* constructors as well: + +.. code-block:: cpp + + struct Aggregate { + int a; + std::string b; + }; + + py::class_(m, "Aggregate") + .def(py::init()); + +.. note:: + + Note that brace initialization preferentially invokes constructor overloads + taking a ``std::initializer_list``. In the rare event that this causes an + issue, you can work around it by using ``py::init(...)`` with a lambda + function that constructs the new object as desired. + +.. _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: + +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. + + To prevent runaway recursion, implicit conversions are non-reentrant: an + implicit conversion invoked as part of another implicit conversion of the + same type (i.e. from ``A`` to ``B``) will fail. + +.. _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. 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_MODULE(example, m) { + 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(py::self * float()) + .def("__repr__", &Vector2::toString); + } + +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: + +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, a ``py::pickle()`` definition 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; + }; + +Pickling support in Python is enabled by defining the ``__setstate__`` and +``__getstate__`` methods [#f3]_. For pybind11 classes, use ``py::pickle()`` +to bind these two functions: + +.. code-block:: cpp + + py::class_(m, "Pickleable") + .def(py::init()) + .def("value", &Pickleable::value) + .def("extra", &Pickleable::extra) + .def("setExtra", &Pickleable::setExtra) + .def(py::pickle( + [](const Pickleable &p) { // __getstate__ + /* Return a tuple that fully encodes the state of the object */ + return py::make_tuple(p.value(), p.extra()); + }, + [](py::tuple t) { // __setstate__ + if (t.size() != 2) + throw std::runtime_error("Invalid state!"); + + /* Create a new C++ instance */ + Pickleable p(t[0].cast()); + + /* Assign any additional state */ + p.setExtra(t[1].cast()); + + return p; + } + )); + +The ``__setstate__`` part of the ``py::picke()`` definition follows the same +rules as the single-argument version of ``py::init()``. The return type can be +a value, pointer or holder type. See :ref:`custom_constructors` for details. + +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. + +It is also permitted to inherit multiply from exported C++ classes in Python, +as well as inheriting from multiple Python and/or pybind11-exported classes. + +There is one caveat regarding the implementation of this feature: + +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`` to the class constructor: + +.. 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. + +.. _module_local: + +Module-local class bindings +=========================== + +When creating a binding for a class, pybind11 by default makes that binding +"global" across modules. What this means is that a type defined in one module +can be returned from any module resulting in the same Python type. For +example, this allows the following: + +.. code-block:: cpp + + // In the module1.cpp binding code for module1: + py::class_(m, "Pet") + .def(py::init()) + .def_readonly("name", &Pet::name); + +.. code-block:: cpp + + // In the module2.cpp binding code for module2: + m.def("create_pet", [](std::string name) { return new Pet(name); }); + +.. code-block:: pycon + + >>> from module1 import Pet + >>> from module2 import create_pet + >>> pet1 = Pet("Kitty") + >>> pet2 = create_pet("Doggy") + >>> pet2.name() + 'Doggy' + +When writing binding code for a library, this is usually desirable: this +allows, for example, splitting up a complex library into multiple Python +modules. + +In some cases, however, this can cause conflicts. For example, suppose two +unrelated modules make use of an external C++ library and each provide custom +bindings for one of that library's classes. This will result in an error when +a Python program attempts to import both modules (directly or indirectly) +because of conflicting definitions on the external type: + +.. code-block:: cpp + + // dogs.cpp + + // Binding for external library class: + py::class(m, "Pet") + .def("name", &pets::Pet::name); + + // Binding for local extension class: + py::class(m, "Dog") + .def(py::init()); + +.. code-block:: cpp + + // cats.cpp, in a completely separate project from the above dogs.cpp. + + // Binding for external library class: + py::class(m, "Pet") + .def("get_name", &pets::Pet::name); + + // Binding for local extending class: + py::class(m, "Cat") + .def(py::init()); + +.. code-block:: pycon + + >>> import cats + >>> import dogs + Traceback (most recent call last): + File "", line 1, in + ImportError: generic_type: type "Pet" is already registered! + +To get around this, you can tell pybind11 to keep the external class binding +localized to the module by passing the ``py::module_local()`` attribute into +the ``py::class_`` constructor: + +.. code-block:: cpp + + // Pet binding in dogs.cpp: + py::class(m, "Pet", py::module_local()) + .def("name", &pets::Pet::name); + +.. code-block:: cpp + + // Pet binding in cats.cpp: + py::class(m, "Pet", py::module_local()) + .def("get_name", &pets::Pet::name); + +This makes the Python-side ``dogs.Pet`` and ``cats.Pet`` into distinct classes, +avoiding the conflict and allowing both modules to be loaded. C++ code in the +``dogs`` module that casts or returns a ``Pet`` instance will result in a +``dogs.Pet`` Python instance, while C++ code in the ``cats`` module will result +in a ``cats.Pet`` Python instance. + +This does come with two caveats, however: First, external modules cannot return +or cast a ``Pet`` instance to Python (unless they also provide their own local +bindings). Second, from the Python point of view they are two distinct classes. + +Note that the locality only applies in the C++ -> Python direction. When +passing such a ``py::module_local`` type into a C++ function, the module-local +classes are still considered. This means that if the following function is +added to any module (including but not limited to the ``cats`` and ``dogs`` +modules above) it will be callable with either a ``dogs.Pet`` or ``cats.Pet`` +argument: + +.. code-block:: cpp + + m.def("pet_name", [](const pets::Pet &pet) { return pet.name(); }); + +For example, suppose the above function is added to each of ``cats.cpp``, +``dogs.cpp`` and ``frogs.cpp`` (where ``frogs.cpp`` is some other module that +does *not* bind ``Pets`` at all). + +.. code-block:: pycon + + >>> import cats, dogs, frogs # No error because of the added py::module_local() + >>> mycat, mydog = cats.Cat("Fluffy"), dogs.Dog("Rover") + >>> (cats.pet_name(mycat), dogs.pet_name(mydog)) + ('Fluffy', 'Rover') + >>> (cats.pet_name(mydog), dogs.pet_name(mycat), frogs.pet_name(mycat)) + ('Rover', 'Fluffy', 'Fluffy') + +It is possible to use ``py::module_local()`` registrations in one module even +if another module registers the same type globally: within the module with the +module-local definition, all C++ instances will be cast to the associated bound +Python type. In other modules any such values are converted to the global +Python type created elsewhere. + +.. note:: + + STL bindings (as provided via the optional :file:`pybind11/stl_bind.h` + header) apply ``py::module_local`` by default when the bound type might + conflict with other modules; see :ref:`stl_bind` for details. + +.. note:: + + The localization of the bound types is actually tied to the shared object + or binary generated by the compiler/linker. For typical modules created + with ``PYBIND11_MODULE()``, this distinction is not significant. It is + possible, however, when :ref:`embedding` to embed multiple modules in the + same binary (see :ref:`embedding_modules`). In such a case, the + localization will apply across all embedded modules within the same binary. + +.. seealso:: + + The file :file:`tests/test_local_bindings.cpp` contains additional examples + that demonstrate how ``py::module_local()`` works. + +Binding protected member functions +================================== + +It's normally not possible to expose ``protected`` member functions to Python: + +.. code-block:: cpp + + class A { + protected: + int foo() const { return 42; } + }; + + py::class_(m, "A") + .def("foo", &A::foo); // error: 'foo' is a protected member of 'A' + +On one hand, this is good because non-``public`` members aren't meant to be +accessed from the outside. But we may want to make use of ``protected`` +functions in derived Python classes. + +The following pattern makes this possible: + +.. code-block:: cpp + + class A { + protected: + int foo() const { return 42; } + }; + + class Publicist : public A { // helper type for exposing protected functions + public: + using A::foo; // inherited with different access modifier + }; + + py::class_(m, "A") // bind the primary class + .def("foo", &Publicist::foo); // expose protected methods via the publicist + +This works because ``&Publicist::foo`` is exactly the same function as +``&A::foo`` (same signature and address), just with a different access +modifier. The only purpose of the ``Publicist`` helper class is to make +the function name ``public``. + +If the intent is to expose ``protected`` ``virtual`` functions which can be +overridden in Python, the publicist pattern can be combined with the previously +described trampoline: + +.. code-block:: cpp + + class A { + public: + virtual ~A() = default; + + protected: + virtual int foo() const { return 42; } + }; + + class Trampoline : public A { + public: + int foo() const override { PYBIND11_OVERLOAD(int, A, foo, ); } + }; + + class Publicist : public A { + public: + using A::foo; + }; + + py::class_(m, "A") // <-- `Trampoline` here + .def("foo", &Publicist::foo); // <-- `Publicist` here, not `Trampoline`! + +.. note:: + + MSVC 2015 has a compiler bug (fixed in version 2017) which + requires a more explicit function binding in the form of + ``.def("foo", static_cast(&Publicist::foo));`` + where ``int (A::*)() const`` is the type of ``A::foo``. + +Custom automatic downcasters +============================ + +As explained in :ref:`inheritance`, pybind11 comes with built-in +understanding of the dynamic type of polymorphic objects in C++; that +is, returning a Pet to Python produces a Python object that knows it's +wrapping a Dog, if Pet has virtual methods and pybind11 knows about +Dog and this Pet is in fact a Dog. Sometimes, you might want to +provide this automatic downcasting behavior when creating bindings for +a class hierarchy that does not use standard C++ polymorphism, such as +LLVM [#f4]_. As long as there's some way to determine at runtime +whether a downcast is safe, you can proceed by specializing the +``pybind11::polymorphic_type_hook`` template: + +.. code-block:: cpp + + enum class PetKind { Cat, Dog, Zebra }; + struct Pet { // Not polymorphic: has no virtual methods + const PetKind kind; + int age = 0; + protected: + Pet(PetKind _kind) : kind(_kind) {} + }; + struct Dog : Pet { + Dog() : Pet(PetKind::Dog) {} + std::string sound = "woof!"; + std::string bark() const { return sound; } + }; + + namespace pybind11 { + template<> struct polymorphic_type_hook { + static const void *get(const Pet *src, const std::type_info*& type) { + // note that src may be nullptr + if (src && src->kind == PetKind::Dog) { + type = &typeid(Dog); + return static_cast(src); + } + return src; + } + }; + } // namespace pybind11 + +When pybind11 wants to convert a C++ pointer of type ``Base*`` to a +Python object, it calls ``polymorphic_type_hook::get()`` to +determine if a downcast is possible. The ``get()`` function should use +whatever runtime information is available to determine if its ``src`` +parameter is in fact an instance of some class ``Derived`` that +inherits from ``Base``. If it finds such a ``Derived``, it sets ``type += &typeid(Derived)`` and returns a pointer to the ``Derived`` object +that contains ``src``. Otherwise, it just returns ``src``, leaving +``type`` at its default value of nullptr. If you set ``type`` to a +type that pybind11 doesn't know about, no downcasting will occur, and +the original ``src`` pointer will be used with its static type +``Base*``. + +It is critical that the returned pointer and ``type`` argument of +``get()`` agree with each other: if ``type`` is set to something +non-null, the returned pointer must point to the start of an object +whose type is ``type``. If the hierarchy being exposed uses only +single inheritance, a simple ``return src;`` will achieve this just +fine, but in the general case, you must cast ``src`` to the +appropriate derived-class pointer (e.g. using +``static_cast(src)``) before allowing it to be returned as a +``void*``. + +.. [#f4] https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html + +.. note:: + + pybind11's standard support for downcasting objects whose types + have virtual methods is implemented using + ``polymorphic_type_hook`` too, using the standard C++ ability to + determine the most-derived type of a polymorphic object using + ``typeid()`` and to cast a base pointer to that most-derived type + (even if you don't know what it is) using ``dynamic_cast``. + +.. seealso:: + + The file :file:`tests/test_tagbased_polymorphic.cpp` contains a + more complete example, including a demonstration of how to provide + automatic downcasting for an entire class hierarchy without + writing one get() function for each class. diff --git a/pybind11/docs/advanced/embedding.rst b/pybind11/docs/advanced/embedding.rst new file mode 100644 index 0000000..3930316 --- /dev/null +++ b/pybind11/docs/advanced/embedding.rst @@ -0,0 +1,261 @@ +.. _embedding: + +Embedding the interpreter +######################### + +While pybind11 is mainly focused on extending Python using C++, it's also +possible to do the reverse: embed the Python interpreter into a C++ program. +All of the other documentation pages still apply here, so refer to them for +general pybind11 usage. This section will cover a few extra things required +for embedding. + +Getting started +=============== + +A basic executable with an embedded interpreter can be created with just a few +lines of CMake and the ``pybind11::embed`` target, as shown below. For more +information, see :doc:`/compiling`. + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.0) + project(example) + + find_package(pybind11 REQUIRED) # or `add_subdirectory(pybind11)` + + add_executable(example main.cpp) + target_link_libraries(example PRIVATE pybind11::embed) + +The essential structure of the ``main.cpp`` file looks like this: + +.. code-block:: cpp + + #include // everything needed for embedding + namespace py = pybind11; + + int main() { + py::scoped_interpreter guard{}; // start the interpreter and keep it alive + + py::print("Hello, World!"); // use the Python API + } + +The interpreter must be initialized before using any Python API, which includes +all the functions and classes in pybind11. The RAII guard class `scoped_interpreter` +takes care of the interpreter lifetime. After the guard is destroyed, the interpreter +shuts down and clears its memory. No Python functions can be called after this. + +Executing Python code +===================== + +There are a few different ways to run Python code. One option is to use `eval`, +`exec` or `eval_file`, as explained in :ref:`eval`. Here is a quick example in +the context of an executable with an embedded interpreter: + +.. code-block:: cpp + + #include + namespace py = pybind11; + + int main() { + py::scoped_interpreter guard{}; + + py::exec(R"( + kwargs = dict(name="World", number=42) + message = "Hello, {name}! The answer is {number}".format(**kwargs) + print(message) + )"); + } + +Alternatively, similar results can be achieved using pybind11's API (see +:doc:`/advanced/pycpp/index` for more details). + +.. code-block:: cpp + + #include + namespace py = pybind11; + using namespace py::literals; + + int main() { + py::scoped_interpreter guard{}; + + auto kwargs = py::dict("name"_a="World", "number"_a=42); + auto message = "Hello, {name}! The answer is {number}"_s.format(**kwargs); + py::print(message); + } + +The two approaches can also be combined: + +.. code-block:: cpp + + #include + #include + + namespace py = pybind11; + using namespace py::literals; + + int main() { + py::scoped_interpreter guard{}; + + auto locals = py::dict("name"_a="World", "number"_a=42); + py::exec(R"( + message = "Hello, {name}! The answer is {number}".format(**locals()) + )", py::globals(), locals); + + auto message = locals["message"].cast(); + std::cout << message; + } + +Importing modules +================= + +Python modules can be imported using `module::import()`: + +.. code-block:: cpp + + py::module sys = py::module::import("sys"); + py::print(sys.attr("path")); + +For convenience, the current working directory is included in ``sys.path`` when +embedding the interpreter. This makes it easy to import local Python files: + +.. code-block:: python + + """calc.py located in the working directory""" + + def add(i, j): + return i + j + + +.. code-block:: cpp + + py::module calc = py::module::import("calc"); + py::object result = calc.attr("add")(1, 2); + int n = result.cast(); + assert(n == 3); + +Modules can be reloaded using `module::reload()` if the source is modified e.g. +by an external process. This can be useful in scenarios where the application +imports a user defined data processing script which needs to be updated after +changes by the user. Note that this function does not reload modules recursively. + +.. _embedding_modules: + +Adding embedded modules +======================= + +Embedded binary modules can be added using the `PYBIND11_EMBEDDED_MODULE` macro. +Note that the definition must be placed at global scope. They can be imported +like any other module. + +.. code-block:: cpp + + #include + namespace py = pybind11; + + PYBIND11_EMBEDDED_MODULE(fast_calc, m) { + // `m` is a `py::module` which is used to bind functions and classes + m.def("add", [](int i, int j) { + return i + j; + }); + } + + int main() { + py::scoped_interpreter guard{}; + + auto fast_calc = py::module::import("fast_calc"); + auto result = fast_calc.attr("add")(1, 2).cast(); + assert(result == 3); + } + +Unlike extension modules where only a single binary module can be created, on +the embedded side an unlimited number of modules can be added using multiple +`PYBIND11_EMBEDDED_MODULE` definitions (as long as they have unique names). + +These modules are added to Python's list of builtins, so they can also be +imported in pure Python files loaded by the interpreter. Everything interacts +naturally: + +.. code-block:: python + + """py_module.py located in the working directory""" + import cpp_module + + a = cpp_module.a + b = a + 1 + + +.. code-block:: cpp + + #include + namespace py = pybind11; + + PYBIND11_EMBEDDED_MODULE(cpp_module, m) { + m.attr("a") = 1; + } + + int main() { + py::scoped_interpreter guard{}; + + auto py_module = py::module::import("py_module"); + + auto locals = py::dict("fmt"_a="{} + {} = {}", **py_module.attr("__dict__")); + assert(locals["a"].cast() == 1); + assert(locals["b"].cast() == 2); + + py::exec(R"( + c = a + b + message = fmt.format(a, b, c) + )", py::globals(), locals); + + assert(locals["c"].cast() == 3); + assert(locals["message"].cast() == "1 + 2 = 3"); + } + + +Interpreter lifetime +==================== + +The Python interpreter shuts down when `scoped_interpreter` is destroyed. After +this, creating a new instance will restart the interpreter. Alternatively, the +`initialize_interpreter` / `finalize_interpreter` pair of functions can be used +to directly set the state at any time. + +Modules created with pybind11 can be safely re-initialized after the interpreter +has been restarted. However, this may not apply to third-party extension modules. +The issue is that Python itself cannot completely unload extension modules and +there are several caveats with regard to interpreter restarting. In short, not +all memory may be freed, either due to Python reference cycles or user-created +global data. All the details can be found in the CPython documentation. + +.. warning:: + + Creating two concurrent `scoped_interpreter` guards is a fatal error. So is + calling `initialize_interpreter` for a second time after the interpreter + has already been initialized. + + Do not use the raw CPython API functions ``Py_Initialize`` and + ``Py_Finalize`` as these do not properly handle the lifetime of + pybind11's internal data. + + +Sub-interpreter support +======================= + +Creating multiple copies of `scoped_interpreter` is not possible because it +represents the main Python interpreter. Sub-interpreters are something different +and they do permit the existence of multiple interpreters. This is an advanced +feature of the CPython API and should be handled with care. pybind11 does not +currently offer a C++ interface for sub-interpreters, so refer to the CPython +documentation for all the details regarding this feature. + +We'll just mention a couple of caveats the sub-interpreters support in pybind11: + + 1. Sub-interpreters will not receive independent copies of embedded modules. + Instead, these are shared and modifications in one interpreter may be + reflected in another. + + 2. Managing multiple threads, multiple interpreters and the GIL can be + challenging and there are several caveats here, even within the pure + CPython API (please refer to the Python docs for details). As for + pybind11, keep in mind that `gil_scoped_release` and `gil_scoped_acquire` + do not take sub-interpreters into account. diff --git a/pybind11/docs/advanced/exceptions.rst b/pybind11/docs/advanced/exceptions.rst new file mode 100644 index 0000000..629af4a --- /dev/null +++ b/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 access 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 access in ``__getitem__``, | +| | ``__setitem__`` in dict-like | +| | objects, etc.) | ++--------------------------------------+--------------------------------------+ +| :class:`pybind11::error_already_set` | Indicates that the Python exception | +| | flag has already been set via Python | +| | API calls from C++ code; this C++ | +| | exception is used to propagate such | +| | a Python exception back to Python. | ++--------------------------------------+--------------------------------------+ + +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 explicitly (re-)thrown to delegate it to the other, + previously-declared existing exception translators. diff --git a/pybind11/docs/advanced/functions.rst b/pybind11/docs/advanced/functions.rst new file mode 100644 index 0000000..4d28f06 --- /dev/null +++ b/pybind11/docs/advanced/functions.rst @@ -0,0 +1,498 @@ +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: + +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` | **Default policy.** This policy falls back to the policy | +| | :enum:`return_value_policy::take_ownership` when the return value is a | +| | pointer. Otherwise, it uses :enum:`return_value_policy::move` or | +| | :enum:`return_value_policy::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 uninitialized 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 or ensure a certain state +for the function call. + +Keep alive +---------- + +In general, this policy is required when the C++ object is any kind of container +and another object is being added to the container. ``keep_alive`` +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. + +When the nurse is not a pybind11-registered type, the implementation internally +relies on the ability to create a *weak reference* to the nurse object. When +the nurse object is not a pybind11-registered type and 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>()); + +For consistency, the argument indexing is identical for constructors. Index +``1`` still refers to the implicit ``this`` pointer, i.e. the object which is +being constructed. Index ``0`` refers to the return type which is presumed to +be ``void`` when a constructor is viewed like a function. The following example +ties the lifetime of the constructor element to the constructed object: + +.. code-block:: cpp + + py::class_(m, "Nurse") + .def(py::init(), 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. + +Call guard +---------- + +The ``call_guard`` policy allows any scope guard type ``T`` to be placed +around the function call. For example, this definition: + +.. code-block:: cpp + + m.def("foo", foo, py::call_guard()); + +is equivalent to the following pseudocode: + +.. code-block:: cpp + + m.def("foo", [](args...) { + T scope_guard; + return foo(args...); // forwarded arguments + }); + +The only requirement is that ``T`` is default-constructible, but otherwise any +scope guard will work. This is very useful in combination with `gil_scoped_release`. +See :ref:`gil`. + +Multiple guards can also be specified as ``py::call_guard``. The +constructor order is left to right and destruction happens in reverse. + +.. seealso:: + + The file :file:`tests/test_call_policies.cpp` contains a complete example + that demonstrates using `keep_alive` and `call_guard` 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=" << std::string(py::str(item.first)) << ", " + << "value=" << std::string(py::str(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``. + +You may also use just one or the other, and may combine these with other +arguments as long as the ``py::args`` and ``py::kwargs`` arguments are the last +arguments accepted by the function. + +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``. + +.. note:: + + When combining \*args or \*\*kwargs with :ref:`keyword_args` you should + *not* include ``py::arg`` tags for the ``py::args`` and ``py::kwargs`` + arguments. + +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); + +.. _nonconverting_arguments: + +Non-converting arguments +======================== + +Certain argument types may support conversion from one type to another. Some +examples of conversions are: + +* :ref:`implicit_conversions` declared using ``py::implicitly_convertible()`` +* Calling a method accepting a double with an integer argument +* Calling a ``std::complex`` argument with a non-complex python type + (for example, with a float). (Requires the optional ``pybind11/complex.h`` + header). +* Calling a function taking an Eigen matrix reference with a numpy array of the + wrong type or of an incompatible data layout. (Requires the optional + ``pybind11/eigen.h`` header). + +This behaviour is sometimes undesirable: the binding code may prefer to raise +an error rather than convert the argument. This behaviour can be obtained +through ``py::arg`` by calling the ``.noconvert()`` method of the ``py::arg`` +object, such as: + +.. code-block:: cpp + + m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert()); + m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f")); + +Attempting the call the second function (the one without ``.noconvert()``) with +an integer will succeed, but attempting to call the ``.noconvert()`` version +will fail with a ``TypeError``: + +.. code-block:: pycon + + >>> floats_preferred(4) + 2.0 + >>> floats_only(4) + Traceback (most recent call last): + File "", line 1, in + TypeError: floats_only(): incompatible function arguments. The following argument types are supported: + 1. (f: float) -> float + + Invoked with: 4 + +You may, of course, combine this with the :var:`_a` shorthand notation (see +:ref:`keyword_args`) and/or :ref:`default_args`. It is also permitted to omit +the argument name by using the ``py::arg()`` constructor without an argument +name, i.e. by specifying ``py::arg().noconvert()``. + +.. note:: + + When specifying ``py::arg`` options it is necessary to provide the same + number of options as the bound function has arguments. Thus if you want to + enable no-convert behaviour for just one of several arguments, you will + need to specify a ``py::arg()`` annotation for each argument with the + no-convert argument modified to ``py::arg().noconvert()``. + +.. _none_arguments: + +Allow/Prohibiting None arguments +================================ + +When a C++ type registered with :class:`py::class_` is passed as an argument to +a function taking the instance as pointer or shared holder (e.g. ``shared_ptr`` +or a custom, copyable holder as described in :ref:`smart_pointers`), pybind +allows ``None`` to be passed from Python which results in calling the C++ +function with ``nullptr`` (or an empty holder) for the argument. + +To explicitly enable or disable this behaviour, using the +``.none`` method of the :class:`py::arg` object: + +.. code-block:: cpp + + py::class_(m, "Dog").def(py::init<>()); + py::class_(m, "Cat").def(py::init<>()); + m.def("bark", [](Dog *dog) -> std::string { + if (dog) return "woof!"; /* Called with a Dog instance */ + else return "(no dog)"; /* Called with None, dog == nullptr */ + }, py::arg("dog").none(true)); + m.def("meow", [](Cat *cat) -> std::string { + // Can't be called with None argument + return "meow"; + }, py::arg("cat").none(false)); + +With the above, the Python call ``bark(None)`` will return the string ``"(no +dog)"``, while attempting to call ``meow(None)`` will raise a ``TypeError``: + +.. code-block:: pycon + + >>> from animals import Dog, Cat, bark, meow + >>> bark(Dog()) + 'woof!' + >>> meow(Cat()) + 'meow' + >>> bark(None) + '(no dog)' + >>> meow(None) + Traceback (most recent call last): + File "", line 1, in + TypeError: meow(): incompatible function arguments. The following argument types are supported: + 1. (cat: animals.Cat) -> str + + Invoked with: None + +The default behaviour when the tag is unspecified is to allow ``None``. + +Overload resolution order +========================= + +When a function or method with multiple overloads is called from Python, +pybind11 determines which overload to call in two passes. The first pass +attempts to call each overload without allowing argument conversion (as if +every argument had been specified as ``py::arg().noconvert()`` as described +above). + +If no overload succeeds in the no-conversion first pass, a second pass is +attempted in which argument conversion is allowed (except where prohibited via +an explicit ``py::arg().noconvert()`` attribute in the function definition). + +If the second pass also fails a ``TypeError`` is raised. + +Within each pass, overloads are tried in the order they were registered with +pybind11. + +What this means in practice is that pybind11 will prefer any overload that does +not require conversion of arguments to an overload that does, but otherwise prefers +earlier-defined overloads to later-defined ones. + +.. note:: + + pybind11 does *not* further prioritize based on the number/pattern of + overloaded arguments. That is, pybind11 does not prioritize a function + requiring one conversion over one requiring three, but only prioritizes + overloads requiring no conversion at all to overloads that require + conversion of at least one argument. diff --git a/pybind11/docs/advanced/misc.rst b/pybind11/docs/advanced/misc.rst new file mode 100644 index 0000000..5b38ec7 --- /dev/null +++ b/pybind11/docs/advanced/misc.rst @@ -0,0 +1,306 @@ +Miscellaneous +############# + +.. _macro_notes: + +General notes regarding convenience macros +========================================== + +pybind11 provides a few convenience macros such as +: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; for +example, consider: + +.. code-block:: cpp + + PYBIND11_OVERLOAD(MyReturnType, Class, func) + +The limitation of the C preprocessor interprets this as five arguments (with new +arguments beginning after each comma) rather than three. To get around this, +there are two alternatives: you can use a type alias, or you can wrap the type +using the ``PYBIND11_TYPE`` macro: + +.. code-block:: cpp + + // Version 1: using a type alias + using ReturnType = MyReturnType; + using ClassType = Class; + PYBIND11_OVERLOAD(ReturnType, ClassType, func); + + // Version 2: using the PYBIND11_TYPE macro: + PYBIND11_OVERLOAD(PYBIND11_TYPE(MyReturnType), + PYBIND11_TYPE(Class), func) + +The ``PYBIND11_MAKE_OPAQUE`` macro does *not* require the above workarounds. + +.. _gil: + +Global Interpreter Lock (GIL) +============================= + +When calling a C++ function from Python, the GIL is always held. +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,31,32 + + 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_MODULE(example, m) { + 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); + }); + } + +The ``call_go`` wrapper can also be simplified using the `call_guard` policy +(see :ref:`call_policies`) which yields the same result: + +.. code-block:: cpp + + m.def("call_go", &call_go, py::call_guard()); + + +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 pybind11 code compiled with hidden-by-default symbol visibility (e.g. +via the command line flag ``-fvisibility=hidden`` on GCC/Clang), which is +required for proper pybind11 functionality, can interfere with the ability to +access types defined in another extension module. Working around this requires +manually exporting types that are accessed by multiple extension modules; +pybind11 provides a macro to do just this: + +.. code-block:: cpp + + class PYBIND11_EXPORT 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 + +Module Destructors +================== + +pybind11 does not provide an explicit mechanism to invoke cleanup code at +module destruction time. In rare cases where such functionality is required, it +is possible to emulate it using Python capsules or weak references with a +destruction callback. + +.. code-block:: cpp + + auto cleanup_callback = []() { + // perform cleanup here -- this function is called with the GIL held + }; + + m.add_object("_cleanup", py::capsule(cleanup_callback)); + +This approach has the potential downside that instances of classes exposed +within the module may still be alive when the cleanup callback is invoked +(whether this is acceptable will generally depend on the application). + +Alternatively, the capsule may also be stashed within a type object, which +ensures that it not called before all instances of that type have been +collected: + +.. code-block:: cpp + + auto cleanup_callback = []() { /* ... */ }; + m.attr("BaseClass").attr("_cleanup") = py::capsule(cleanup_callback); + +Both approaches also expose a potentially dangerous ``_cleanup`` attribute in +Python, which may be undesirable from an API standpoint (a premature explicit +call from Python might lead to undefined behavior). Yet another approach that +avoids this issue involves weak reference with a cleanup callback: + +.. code-block:: cpp + + // Register a callback function that is invoked when the BaseClass object is colelcted + py::cpp_function cleanup_callback( + [](py::handle weakref) { + // perform cleanup here -- this function is called with the GIL held + + weakref.dec_ref(); // release weak reference + } + ); + + // Create a weak reference with a cleanup callback and initially leak it + (void) py::weakref(m.attr("BaseClass"), cleanup_callback).release(); + +.. note:: + + PyPy (at least version 5.9) does not garbage collect objects when the + interpreter exits. An alternative approach (which also works on CPython) is to use + the :py:mod:`atexit` module [#f7]_, for example: + + .. code-block:: cpp + + auto atexit = py::module::import("atexit"); + atexit.attr("register")(py::cpp_function([]() { + // perform cleanup here -- this function is called with the GIL held + })); + + .. [#f7] https://docs.python.org/3/library/atexit.html + + +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_MODULE(example, m) { + py::options options; + options.disable_function_signatures(); + + m.def("add", [](int a, int b) { return a + b; }, "A function which adds two numbers"); + } + +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/pybind11/docs/advanced/pycpp/index.rst b/pybind11/docs/advanced/pycpp/index.rst new file mode 100644 index 0000000..6885bdc --- /dev/null +++ b/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/pybind11/docs/advanced/pycpp/numpy.rst b/pybind11/docs/advanced/pycpp/numpy.rst new file mode 100644 index 0000000..458f99e --- /dev/null +++ b/pybind11/docs/advanced/pycpp/numpy.rst @@ -0,0 +1,386 @@ +.. _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", py::buffer_protocol()) + .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.cols(), /* Strides (in bytes) for each index */ + sizeof(float) } + ); + }); + +Supporting the buffer protocol in a new type involves specifying the special +``py::buffer_protocol()`` tag in the ``py::class_`` constructor and calling the +``def_buffer()`` method with a lambda function that creates a +``py::buffer_info`` description record on demand describing a given matrix +instance. The contents of ``py::buffer_info`` mirror the Python buffer protocol +specification. + +.. code-block:: cpp + + struct buffer_info { + void *ptr; + ssize_t itemsize; + std::string format; + ssize_t 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", py::buffer_protocol()) + .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] / (py::ssize_t)sizeof(Scalar), + info.strides[rowMajor ? 1 : 0] / (py::ssize_t)sizeof(Scalar)); + + auto map = Eigen::Map( + static_cast(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 */ + py::format_descriptor::format(), /* Python struct-style format descriptor */ + 2, /* Number of dimensions */ + { m.rows(), m.cols() }, /* Buffer dimensions */ + { sizeof(Scalar) * (rowMajor ? m.cols() : 1), + sizeof(Scalar) * (rowMajor ? 1 : m.rows()) } + /* Strides (in bytes) for each index */ + ); + }) + +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, called in the plugin definition code, which +expects the type followed by field names: + +.. code-block:: cpp + + struct A { + int x; + double y; + }; + + struct B { + int z; + A a; + }; + + // ... + PYBIND11_MODULE(test, m) { + // ... + + 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 */ + } + +The structure should consist of fundamental arithmetic types, ``std::complex``, +previously registered substructures, and arrays of any of the above. Both C++ +arrays and ``std::array`` are supported. While there is a static assertion to +prevent many types of unsupported structures, it is still the user's +responsibility to use only "plain" structures that can be safely manipulated as +raw memory without violating invariants. + +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). + +.. note:: + + Only arithmetic, complex, and POD types passed by value or by ``const &`` + reference are vectorized; all other arguments are passed through as-is. + Functions taking rvalue reference arguments cannot be vectorized. + +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) { + py::buffer_info 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); + + py::buffer_info 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_MODULE(test, m) { + m.def("add_arrays", &add_arrays, "Add two NumPy arrays"); + } + +.. seealso:: + + The file :file:`tests/test_numpy_vectorize.cpp` contains a complete + example that demonstrates using :func:`vectorize` in more detail. + +Direct access +============= + +For performance reasons, particularly when dealing with very large arrays, it +is often desirable to directly access array elements without internal checking +of dimensions and bounds on every access when indices are known to be already +valid. To avoid such checks, the ``array`` class and ``array_t`` template +class offer an unchecked proxy object that can be used for this unchecked +access through the ``unchecked`` and ``mutable_unchecked`` methods, +where ``N`` gives the required dimensionality of the array: + +.. code-block:: cpp + + m.def("sum_3d", [](py::array_t x) { + auto r = x.unchecked<3>(); // x must have ndim = 3; can be non-writeable + double sum = 0; + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t k = 0; k < r.shape(2); k++) + sum += r(i, j, k); + return sum; + }); + m.def("increment_3d", [](py::array_t x) { + auto r = x.mutable_unchecked<3>(); // Will throw if ndim != 3 or flags.writeable is false + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t k = 0; k < r.shape(2); k++) + r(i, j, k) += 1.0; + }, py::arg().noconvert()); + +To obtain the proxy from an ``array`` object, you must specify both the data +type and number of dimensions as template arguments, such as ``auto r = +myarray.mutable_unchecked()``. + +If the number of dimensions is not known at compile time, you can omit the +dimensions template parameter (i.e. calling ``arr_t.unchecked()`` or +``arr.unchecked()``. This will give you a proxy object that works in the +same way, but results in less optimizable code and thus a small efficiency +loss in tight loops. + +Note that the returned proxy object directly references the array's data, and +only reads its shape, strides, and writeable flag when constructed. You must +take care to ensure that the referenced array is not destroyed or reshaped for +the duration of the returned object, typically by limiting the scope of the +returned instance. + +The returned proxy object supports some of the same methods as ``py::array`` so +that it can be used as a drop-in replacement for some existing, index-checked +uses of ``py::array``: + +- ``r.ndim()`` returns the number of dimensions + +- ``r.data(1, 2, ...)`` and ``r.mutable_data(1, 2, ...)``` returns a pointer to + the ``const T`` or ``T`` data, respectively, at the given indices. The + latter is only available to proxies obtained via ``a.mutable_unchecked()``. + +- ``itemsize()`` returns the size of an item in bytes, i.e. ``sizeof(T)``. + +- ``ndim()`` returns the number of dimensions. + +- ``shape(n)`` returns the size of dimension ``n`` + +- ``size()`` returns the total number of elements (i.e. the product of the shapes). + +- ``nbytes()`` returns the number of bytes used by the referenced elements + (i.e. ``itemsize()`` times ``size()``). + +.. seealso:: + + The file :file:`tests/test_numpy_array.cpp` contains additional examples + demonstrating the use of this feature. + +Ellipsis +======== + +Python 3 provides a convenient ``...`` ellipsis notation that is often used to +slice multidimensional arrays. For instance, the following snippet extracts the +middle dimensions of a tensor with the first and last index set to zero. + +.. code-block:: python + + a = # a NumPy array + b = a[0, ..., 0] + +The function ``py::ellipsis()`` function can be used to perform the same +operation on the C++ side: + +.. code-block:: cpp + + py::array a = /* A NumPy array */; + py::array b = a[py::make_tuple(0, py::ellipsis(), 0)]; diff --git a/pybind11/docs/advanced/pycpp/object.rst b/pybind11/docs/advanced/pycpp/object.rst new file mode 100644 index 0000000..117131e --- /dev/null +++ b/pybind11/docs/advanced/pycpp/object.rst @@ -0,0 +1,170 @@ +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`. + +.. _python_libs: + +Accessing Python libraries from C++ +=================================== + +It is also possible to import objects defined in the Python standard +library or available in the current Python environment (``sys.path``) and work +with these in C++. + +This example obtains a reference to the Python ``Decimal`` class. + +.. code-block:: cpp + + // Equivalent to "from decimal import Decimal" + py::object Decimal = py::module::import("decimal").attr("Decimal"); + +.. code-block:: cpp + + // Try to import scipy + py::object scipy = py::module::import("scipy"); + return scipy.attr("__version__"); + +.. _calling_python_functions: + +Calling Python functions +======================== + +It is also possible to call Python classes, functions and methods +via ``operator()``. + +.. code-block:: cpp + + // Construct a Python object of class Decimal + py::object pi = Decimal("3.14159"); + +.. code-block:: cpp + + // Use Python to make our directories + py::object os = py::module::import("os"); + py::object makedirs = os.attr("makedirs"); + makedirs("/tmp/path/to/somewhere"); + +One can convert the result obtained from Python to a pure C++ version +if a ``py::class_`` or type conversion is defined. + +.. code-block:: cpp + + py::function f = <...>; + py::object result_py = f(1234, "hello", some_instance); + MyClass &result = result_py.cast(); + +.. _calling_python_methods: + +Calling Python methods +======================== + +To call an object's method, one can again use ``.attr`` to obtain access to the +Python method. + +.. code-block:: cpp + + // Calculate e^π in decimal + py::object exp_pi = pi.attr("exp")(); + py::print(py::str(exp_pi)); + +In the example above ``pi.attr("exp")`` is a *bound method*: it will always call +the method for that same instance of the class. Alternately one can create an +*unbound method* via the Python class (instead of instance) and pass the ``self`` +object explicitly, followed by other arguments. + +.. code-block:: cpp + + py::object decimal_exp = Decimal.attr("exp"); + + // Compute the e^n for n=0..4 + for (int n = 0; n < 5; n++) { + py::print(decimal_exp(Decimal(n)); + } + +Keyword arguments +================= + +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 namespace pybind11::literals; // to bring in the `_a` literal + f(1234, "say"_a="hello", "to"_a=some_instance); // keyword call in C++ + +Unpacking arguments +=================== + +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_pytypes.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/pybind11/docs/advanced/pycpp/utilities.rst b/pybind11/docs/advanced/pycpp/utilities.rst new file mode 100644 index 0000000..369e7c9 --- /dev/null +++ b/pybind11/docs/advanced/pycpp/utilities.rst @@ -0,0 +1,144 @@ +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 <- + +.. _ostream_redirect: + +Capturing standard output from ostream +====================================== + +Often, a library will use the streams ``std::cout`` and ``std::cerr`` to print, +but this does not play well with Python's standard ``sys.stdout`` and ``sys.stderr`` +redirection. Replacing a library's printing with `py::print ` may not +be feasible. This can be fixed using a guard around the library function that +redirects output to the corresponding Python streams: + +.. code-block:: cpp + + #include + + ... + + // Add a scoped redirect for your noisy code + m.def("noisy_func", []() { + py::scoped_ostream_redirect stream( + std::cout, // std::ostream& + py::module::import("sys").attr("stdout") // Python output + ); + call_noisy_func(); + }); + +This method respects flushes on the output streams and will flush if needed +when the scoped guard is destroyed. This allows the output to be redirected in +real time, such as to a Jupyter notebook. The two arguments, the C++ stream and +the Python output, are optional, and default to standard output if not given. An +extra type, `py::scoped_estream_redirect `, is identical +except for defaulting to ``std::cerr`` and ``sys.stderr``; this can be useful with +`py::call_guard`, which allows multiple items, but uses the default constructor: + +.. code-block:: py + + // Alternative: Call single function using call guard + m.def("noisy_func", &call_noisy_function, + py::call_guard()); + +The redirection can also be done in Python with the addition of a context +manager, using the `py::add_ostream_redirect() ` function: + +.. code-block:: cpp + + py::add_ostream_redirect(m, "ostream_redirect"); + +The name in Python defaults to ``ostream_redirect`` if no name is passed. This +creates the following context manager in Python: + +.. code-block:: python + + with ostream_redirect(stdout=True, stderr=True): + noisy_function() + +It defaults to redirecting both streams, though you can use the keyword +arguments to disable one of the streams if needed. + +.. note:: + + The above methods will not redirect C-level output to file descriptors, such + as ``fprintf``. For those cases, you'll need to redirect the file + descriptors either directly in C or with Python's ``os.dup2`` function + in an operating-system dependent way. + +.. _eval: + +Evaluating Python expressions from strings and files +==================================================== + +pybind11 provides the `eval`, `exec` and `eval_file` functions to evaluate +Python expressions and statements. The following example illustrates how they +can be used. + +.. 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::exec( + "print('Hello')\n" + "print('world!');", + scope); + + // Evaluate the statements in an separate Python file on disk + py::eval_file("script.py", scope); + +C++11 raw string literals are also supported and quite handy for this purpose. +The only requirement is that the first statement must be on a new line following +the raw string delimiter ``R"(``, ensuring all lines have common leading indent: + +.. code-block:: cpp + + py::exec(R"( + x = get_answer() + if x == 42: + print('Hello World!') + else: + print('Bye!') + )", scope + ); + +.. note:: + + `eval` and `eval_file` accept a template parameter that describes how the + string/file 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``). `eval` defaults to ``eval_expr``, + `eval_file` defaults to ``eval_statements`` and `exec` is just a shortcut + for ``eval``. diff --git a/pybind11/docs/advanced/smart_ptrs.rst b/pybind11/docs/advanced/smart_ptrs.rst new file mode 100644 index 0000000..da57748 --- /dev/null +++ b/pybind11/docs/advanced/smart_ptrs.rst @@ -0,0 +1,173 @@ +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_MODULE(example, m) { + py::class_>(m, "Child"); + + py::class_>(m, "Parent") + .def(py::init<>()) + .def("get_child", &Parent::get_child); + } + +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 +top namespace 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. + +The macro also accepts a third optional boolean parameter that is set to false +by default. Specify + +.. code-block:: cpp + + PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr, true); + +if ``SmartPtr`` can always be initialized from a ``T*`` pointer without the +risk of inconsistencies (such as multiple independent ``SmartPtr`` instances +believing that they are the sole owner of the ``T*`` pointer). A common +situation where ``true`` should be passed is when the ``T`` instances use +*intrusive* reference counting. + +Please take a look at the :ref:`macro_notes` before using this feature. + +By default, pybind11 assumes that your custom smart pointer has a standard +interface, i.e. provides a ``.get()`` member function to access the underlying +raw pointer. If this is not the case, pybind11's ``holder_helper`` must be +specialized: + +.. code-block:: cpp + + // Always needed for custom holder types + PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr); + + // Only needed if the type's `.get()` goes by another name + namespace pybind11 { namespace detail { + template + struct holder_helper> { // <-- specialization + static const T *get(const SmartPtr &p) { return p.getPointer(); } + }; + }} + +The above specialization informs pybind11 that the custom ``SmartPtr`` class +provides ``.get()`` functionality via ``.getPointer()``. + +.. 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/pybind11/docs/basics.rst b/pybind11/docs/basics.rst new file mode 100644 index 0000000..447250e --- /dev/null +++ b/pybind11/docs/basics.rst @@ -0,0 +1,293 @@ +.. _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 check -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 check + +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. + +.. _simple_example: + +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; + } + + PYBIND11_MODULE(example, m) { + m.doc() = "pybind11 example plugin"; // optional module docstring + + m.def("add", &add, "A function which adds two numbers"); + } + +.. [#f1] In practice, implementation and binding code will generally be located + in separate files. + +The :func:`PYBIND11_MODULE` macro creates a function that will be called when an +``import`` statement is issued from within Python. The module name (``example``) +is given as the first macro argument (it should not be in quotes). The second +argument (``m``) defines a variable of type :class:`py::module ` which +is the main interface for creating bindings. The method :func:`module::def` +generates binding code that exposes the ``add()`` function to Python. + +.. 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 and there are no intermediate (magic) translation steps. +On Linux, the above example can be compiled using the following command: + +.. code-block:: bash + + $ c++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix` + +For more details on the required compiler flags on Linux and MacOS, see +:ref:`building_manually`. For complete cross-platform compilation instructions, +refer to the :ref:`compiling` page. + +The `python_example`_ and `cmake_example`_ repositories are also a good place +to start. They are both complete project examples with cross-platform build +systems. The only difference between the two is that `python_example`_ uses +Python's ``setuptools`` to build the module, while `cmake_example`_ uses CMake +(which may be preferable for existing C++ projects). + +.. _python_example: https://github.com/pybind/python_example +.. _cmake_example: https://github.com/pybind/cmake_example + +Building the above C++ code will produce a binary module file that can be +imported to Python. Assuming that the compiled module 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) +are automatically converted when assigned as attributes, and can be explicitly +converted using the function ``py::cast``. + +.. code-block:: cpp + + PYBIND11_MODULE(example, m) { + m.attr("the_answer") = 42; + py::object world = py::cast("World"); + m.attr("what") = world; + } + +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/pybind11/docs/benchmark.py b/pybind11/docs/benchmark.py new file mode 100644 index 0000000..6dc0604 --- /dev/null +++ b/pybind11/docs/benchmark.py @@ -0,0 +1,88 @@ +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_MODULE(example, m) {\n" + result += bindings + 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/pybind11/docs/benchmark.rst b/pybind11/docs/benchmark.rst new file mode 100644 index 0000000..59d533d --- /dev/null +++ b/pybind11/docs/benchmark.rst @@ -0,0 +1,97 @@ +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_MODULE(example, m) { + ... + 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) + ... + } + +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/pybind11/docs/changelog.rst b/pybind11/docs/changelog.rst new file mode 100644 index 0000000..606be41 --- /dev/null +++ b/pybind11/docs/changelog.rst @@ -0,0 +1,1094 @@ +.. _changelog: + +Changelog +######### + +Starting with version 1.8.0, pybind11 releases use a `semantic versioning +`_ policy. + +v2.3.0 (Not yet released) +----------------------------------------------------- + +* Significantly reduced module binary size (10-20%) when compiled in C++11 mode + with GCC/Clang, or in any mode with MSVC. Function signatures are now always + precomputed at compile time (this was previously only available in C++14 mode + for non-MSVC compilers). + `#934 `_. + +* Add basic support for tag-based static polymorphism, where classes + provide a method to returns the desired type of an instance. + `#1326 `_. + +* Added support for write only properties. + `#1144 `_. + +* Python type wrappers (``py::handle``, ``py::object``, etc.) + now support map Python's number protocol onto C++ arithmetic + operators such as ``operator+``, ``operator/=``, etc. + `#1511 `_. + +* A number of improvements related to enumerations: + + 1. The ``enum_`` implementation was rewritten from scratch to reduce + code bloat. Rather than instantiating a full implementation for each + enumeration, most code is now contained in a generic base class. + `#1511 `_. + + 2. The ``value()`` method of ``py::enum_`` now accepts an optional + docstring that will be shown in the documentation of the associated + enumeration. `#1160 `_. + + 3. check for already existing enum value and throw an error if present. + `#1453 `_. + +* added ``py::ellipsis()`` method for slicing of multidimensional NumPy arrays + `#1502 `_. + +* ``pybind11_add_module()``: allow including Python as a ``SYSTEM`` include path. + `#1416 `_. + +* ``pybind11/stl.h`` does not convert strings to ``vector`` anymore. + `#1258 `_. + +v2.2.4 (September 11, 2018) +----------------------------------------------------- + +* Use new Python 3.7 Thread Specific Storage (TSS) implementation if available. + `#1454 `_, + `#1517 `_. + +* Fixes for newer MSVC versions and C++17 mode. + `#1347 `_, + `#1462 `_. + +* Propagate return value policies to type-specific casters + when casting STL containers. + `#1455 `_. + +* Allow ostream-redirection of more than 1024 characters. + `#1479 `_. + +* Set ``Py_DEBUG`` define when compiling against a debug Python build. + `#1438 `_. + +* Untangle integer logic in number type caster to work for custom + types that may only be castable to a restricted set of builtin types. + `#1442 `_. + +* CMake build system: Remember Python version in cache file. + `#1434 `_. + +* Fix for custom smart pointers: use ``std::addressof`` to obtain holder + address instead of ``operator&``. + `#1435 `_. + +* Properly report exceptions thrown during module initialization. + `#1362 `_. + +* Fixed a segmentation fault when creating empty-shaped NumPy array. + `#1371 `_. + +* The version of Intel C++ compiler must be >= 2017, and this is now checked by + the header files. `#1363 `_. + +* A few minor typo fixes and improvements to the test suite, and + patches that silence compiler warnings. + +v2.2.3 (April 29, 2018) +----------------------------------------------------- + +* The pybind11 header location detection was replaced by a new implementation + that no longer depends on ``pip`` internals (the recently released ``pip`` + 10 has restricted access to this API). + `#1190 `_. + +* Small adjustment to an implementation detail to work around a compiler segmentation fault in Clang 3.3/3.4. + `#1350 `_. + +* The minimal supported version of the Intel compiler was >= 17.0 since + pybind11 v2.1. This check is now explicit, and a compile-time error is raised + if the compiler meet the requirement. + `#1363 `_. + +* Fixed an endianness-related fault in the test suite. + `#1287 `_. + +v2.2.2 (February 7, 2018) +----------------------------------------------------- + +* Fixed a segfault when combining embedded interpreter + shutdown/reinitialization with external loaded pybind11 modules. + `#1092 `_. + +* Eigen support: fixed a bug where Nx1/1xN numpy inputs couldn't be passed as + arguments to Eigen vectors (which for Eigen are simply compile-time fixed + Nx1/1xN matrices). + `#1106 `_. + +* Clarified to license by moving the licensing of contributions from + ``LICENSE`` into ``CONTRIBUTING.md``: the licensing of contributions is not + actually part of the software license as distributed. This isn't meant to be + a substantial change in the licensing of the project, but addresses concerns + that the clause made the license non-standard. + `#1109 `_. + +* Fixed a regression introduced in 2.1 that broke binding functions with lvalue + character literal arguments. + `#1128 `_. + +* MSVC: fix for compilation failures under /permissive-, and added the flag to + the appveyor test suite. + `#1155 `_. + +* Fixed ``__qualname__`` generation, and in turn, fixes how class names + (especially nested class names) are shown in generated docstrings. + `#1171 `_. + +* Updated the FAQ with a suggested project citation reference. + `#1189 `_. + +* Added fixes for deprecation warnings when compiled under C++17 with + ``-Wdeprecated`` turned on, and add ``-Wdeprecated`` to the test suite + compilation flags. + `#1191 `_. + +* Fixed outdated PyPI URLs in ``setup.py``. + `#1213 `_. + +* Fixed a refcount leak for arguments that end up in a ``py::args`` argument + for functions with both fixed positional and ``py::args`` arguments. + `#1216 `_. + +* Fixed a potential segfault resulting from possible premature destruction of + ``py::args``/``py::kwargs`` arguments with overloaded functions. + `#1223 `_. + +* Fixed ``del map[item]`` for a ``stl_bind.h`` bound stl map. + `#1229 `_. + +* Fixed a regression from v2.1.x where the aggregate initialization could + unintentionally end up at a constructor taking a templated + ``std::initializer_list`` argument. + `#1249 `_. + +* Fixed an issue where calling a function with a keep_alive policy on the same + nurse/patient pair would cause the internal patient storage to needlessly + grow (unboundedly, if the nurse is long-lived). + `#1251 `_. + +* Various other minor fixes. + +v2.2.1 (September 14, 2017) +----------------------------------------------------- + +* Added ``py::module::reload()`` member function for reloading a module. + `#1040 `_. + +* Fixed a reference leak in the number converter. + `#1078 `_. + +* Fixed compilation with Clang on host GCC < 5 (old libstdc++ which isn't fully + C++11 compliant). `#1062 `_. + +* Fixed a regression where the automatic ``std::vector`` caster would + fail to compile. The same fix also applies to any container which returns + element proxies instead of references. + `#1053 `_. + +* Fixed a regression where the ``py::keep_alive`` policy could not be applied + to constructors. `#1065 `_. + +* Fixed a nullptr dereference when loading a ``py::module_local`` type + that's only registered in an external module. + `#1058 `_. + +* Fixed implicit conversion of accessors to types derived from ``py::object``. + `#1076 `_. + +* The ``name`` in ``PYBIND11_MODULE(name, variable)`` can now be a macro. + `#1082 `_. + +* Relaxed overly strict ``py::pickle()`` check for matching get and set types. + `#1064 `_. + +* Conversion errors now try to be more informative when it's likely that + a missing header is the cause (e.g. forgetting ````). + `#1077 `_. + +v2.2.0 (August 31, 2017) +----------------------------------------------------- + +* Support for embedding the Python interpreter. See the + :doc:`documentation page ` for a + full overview of the new features. + `#774 `_, + `#889 `_, + `#892 `_, + `#920 `_. + + .. code-block:: cpp + + #include + namespace py = pybind11; + + int main() { + py::scoped_interpreter guard{}; // start the interpreter and keep it alive + + py::print("Hello, World!"); // use the Python API + } + +* Support for inheriting from multiple C++ bases in Python. + `#693 `_. + + .. code-block:: python + + from cpp_module import CppBase1, CppBase2 + + class PyDerived(CppBase1, CppBase2): + def __init__(self): + CppBase1.__init__(self) # C++ bases must be initialized explicitly + CppBase2.__init__(self) + +* ``PYBIND11_MODULE`` is now the preferred way to create module entry points. + ``PYBIND11_PLUGIN`` is deprecated. See :ref:`macros` for details. + `#879 `_. + + .. code-block:: cpp + + // new + PYBIND11_MODULE(example, m) { + m.def("add", [](int a, int b) { return a + b; }); + } + + // old + PYBIND11_PLUGIN(example) { + py::module m("example"); + m.def("add", [](int a, int b) { return a + b; }); + return m.ptr(); + } + +* pybind11's headers and build system now more strictly enforce hidden symbol + visibility for extension modules. This should be seamless for most users, + but see the :doc:`upgrade` if you use a custom build system. + `#995 `_. + +* Support for ``py::module_local`` types which allow multiple modules to + export the same C++ types without conflicts. This is useful for opaque + types like ``std::vector``. ``py::bind_vector`` and ``py::bind_map`` + now default to ``py::module_local`` if their elements are builtins or + local types. See :ref:`module_local` for details. + `#949 `_, + `#981 `_, + `#995 `_, + `#997 `_. + +* Custom constructors can now be added very easily using lambdas or factory + functions which return a class instance by value, pointer or holder. This + supersedes the old placement-new ``__init__`` technique. + See :ref:`custom_constructors` for details. + `#805 `_, + `#1014 `_. + + .. code-block:: cpp + + struct Example { + Example(std::string); + }; + + py::class_(m, "Example") + .def(py::init()) // existing constructor + .def(py::init([](int n) { // custom constructor + return std::make_unique(std::to_string(n)); + })); + +* Similarly to custom constructors, pickling support functions are now bound + using the ``py::pickle()`` adaptor which improves type safety. See the + :doc:`upgrade` and :ref:`pickling` for details. + `#1038 `_. + +* Builtin support for converting C++17 standard library types and general + conversion improvements: + + 1. C++17 ``std::variant`` is supported right out of the box. C++11/14 + equivalents (e.g. ``boost::variant``) can also be added with a simple + user-defined specialization. See :ref:`cpp17_container_casters` for details. + `#811 `_, + `#845 `_, + `#989 `_. + + 2. Out-of-the-box support for C++17 ``std::string_view``. + `#906 `_. + + 3. Improved compatibility of the builtin ``optional`` converter. + `#874 `_. + + 4. The ``bool`` converter now accepts ``numpy.bool_`` and types which + define ``__bool__`` (Python 3.x) or ``__nonzero__`` (Python 2.7). + `#925 `_. + + 5. C++-to-Python casters are now more efficient and move elements out + of rvalue containers whenever possible. + `#851 `_, + `#936 `_, + `#938 `_. + + 6. Fixed ``bytes`` to ``std::string/char*`` conversion on Python 3. + `#817 `_. + + 7. Fixed lifetime of temporary C++ objects created in Python-to-C++ conversions. + `#924 `_. + +* Scope guard call policy for RAII types, e.g. ``py::call_guard()``, + ``py::call_guard()``. See :ref:`call_policies` for details. + `#740 `_. + +* Utility for redirecting C++ streams to Python (e.g. ``std::cout`` -> + ``sys.stdout``). Scope guard ``py::scoped_ostream_redirect`` in C++ and + a context manager in Python. See :ref:`ostream_redirect`. + `#1009 `_. + +* Improved handling of types and exceptions across module boundaries. + `#915 `_, + `#951 `_, + `#995 `_. + +* Fixed destruction order of ``py::keep_alive`` nurse/patient objects + in reference cycles. + `#856 `_. + +* Numpy and buffer protocol related improvements: + + 1. Support for negative strides in Python buffer objects/numpy arrays. This + required changing integers from unsigned to signed for the related C++ APIs. + Note: If you have compiler warnings enabled, you may notice some new conversion + warnings after upgrading. These can be resolved with ``static_cast``. + `#782 `_. + + 2. Support ``std::complex`` and arrays inside ``PYBIND11_NUMPY_DTYPE``. + `#831 `_, + `#832 `_. + + 3. Support for constructing ``py::buffer_info`` and ``py::arrays`` using + arbitrary containers or iterators instead of requiring a ``std::vector``. + `#788 `_, + `#822 `_, + `#860 `_. + + 4. Explicitly check numpy version and require >= 1.7.0. + `#819 `_. + +* Support for allowing/prohibiting ``None`` for specific arguments and improved + ``None`` overload resolution order. See :ref:`none_arguments` for details. + `#843 `_. + `#859 `_. + +* Added ``py::exec()`` as a shortcut for ``py::eval()`` + and support for C++11 raw string literals as input. See :ref:`eval`. + `#766 `_, + `#827 `_. + +* ``py::vectorize()`` ignores non-vectorizable arguments and supports + member functions. + `#762 `_. + +* Support for bound methods as callbacks (``pybind11/functional.h``). + `#815 `_. + +* Allow aliasing pybind11 methods: ``cls.attr("foo") = cls.attr("bar")``. + `#802 `_. + +* Don't allow mixed static/non-static overloads. + `#804 `_. + +* Fixed overriding static properties in derived classes. + `#784 `_. + +* Improved deduction of member functions of a derived class when its bases + aren't registered with pybind11. + `#855 `_. + + .. code-block:: cpp + + struct Base { + int foo() { return 42; } + } + + struct Derived : Base {} + + // Now works, but previously required also binding `Base` + py::class_(m, "Derived") + .def("foo", &Derived::foo); // function is actually from `Base` + +* The implementation of ``py::init<>`` now uses C++11 brace initialization + syntax to construct instances, which permits binding implicit constructors of + aggregate types. `#1015 `_. + + .. code-block:: cpp + + struct Aggregate { + int a; + std::string b; + }; + + py::class_(m, "Aggregate") + .def(py::init()); + +* Fixed issues with multiple inheritance with offset base/derived pointers. + `#812 `_, + `#866 `_, + `#960 `_. + +* Fixed reference leak of type objects. + `#1030 `_. + +* Improved support for the ``/std:c++14`` and ``/std:c++latest`` modes + on MSVC 2017. + `#841 `_, + `#999 `_. + +* Fixed detection of private operator new on MSVC. + `#893 `_, + `#918 `_. + +* Intel C++ compiler compatibility fixes. + `#937 `_. + +* Fixed implicit conversion of `py::enum_` to integer types on Python 2.7. + `#821 `_. + +* Added ``py::hash`` to fetch the hash value of Python objects, and + ``.def(hash(py::self))`` to provide the C++ ``std::hash`` as the Python + ``__hash__`` method. + `#1034 `_. + +* Fixed ``__truediv__`` on Python 2 and ``__itruediv__`` on Python 3. + `#867 `_. + +* ``py::capsule`` objects now support the ``name`` attribute. This is useful + for interfacing with ``scipy.LowLevelCallable``. + `#902 `_. + +* Fixed ``py::make_iterator``'s ``__next__()`` for past-the-end calls. + `#897 `_. + +* Added ``error_already_set::matches()`` for checking Python exceptions. + `#772 `_. + +* Deprecated ``py::error_already_set::clear()``. It's no longer needed + following a simplification of the ``py::error_already_set`` class. + `#954 `_. + +* Deprecated ``py::handle::operator==()`` in favor of ``py::handle::is()`` + `#825 `_. + +* Deprecated ``py::object::borrowed``/``py::object::stolen``. + Use ``py::object::borrowed_t{}``/``py::object::stolen_t{}`` instead. + `#771 `_. + +* Changed internal data structure versioning to avoid conflicts between + modules compiled with different revisions of pybind11. + `#1012 `_. + +* Additional compile-time and run-time error checking and more informative messages. + `#786 `_, + `#794 `_, + `#803 `_. + +* Various minor improvements and fixes. + `#764 `_, + `#791 `_, + `#795 `_, + `#840 `_, + `#844 `_, + `#846 `_, + `#849 `_, + `#858 `_, + `#862 `_, + `#871 `_, + `#872 `_, + `#881 `_, + `#888 `_, + `#899 `_, + `#928 `_, + `#931 `_, + `#944 `_, + `#950 `_, + `#952 `_, + `#962 `_, + `#965 `_, + `#970 `_, + `#978 `_, + `#979 `_, + `#986 `_, + `#1020 `_, + `#1027 `_, + `#1037 `_. + +* Testing improvements. + `#798 `_, + `#882 `_, + `#898 `_, + `#900 `_, + `#921 `_, + `#923 `_, + `#963 `_. + +v2.1.1 (April 7, 2017) +----------------------------------------------------- + +* Fixed minimum version requirement for MSVC 2015u3 + `#773 `_. + +v2.1.0 (March 22, 2017) +----------------------------------------------------- + +* pybind11 now performs function overload resolution in two phases. The first + phase only considers exact type matches, while the second allows for implicit + conversions to take place. A special ``noconvert()`` syntax can be used to + completely disable implicit conversions for specific arguments. + `#643 `_, + `#634 `_, + `#650 `_. + +* Fixed a regression where static properties no longer worked with classes + using multiple inheritance. The ``py::metaclass`` attribute is no longer + necessary (and deprecated as of this release) when binding classes with + static properties. + `#679 `_, + +* Classes bound using ``pybind11`` can now use custom metaclasses. + `#679 `_, + +* ``py::args`` and ``py::kwargs`` can now be mixed with other positional + arguments when binding functions using pybind11. + `#611 `_. + +* Improved support for C++11 unicode string and character types; added + extensive documentation regarding pybind11's string conversion behavior. + `#624 `_, + `#636 `_, + `#715 `_. + +* pybind11 can now avoid expensive copies when converting Eigen arrays to NumPy + arrays (and vice versa). `#610 `_. + +* The "fast path" in ``py::vectorize`` now works for any full-size group of C or + F-contiguous arrays. The non-fast path is also faster since it no longer performs + copies of the input arguments (except when type conversions are necessary). + `#610 `_. + +* Added fast, unchecked access to NumPy arrays via a proxy object. + `#746 `_. + +* Transparent support for class-specific ``operator new`` and + ``operator delete`` implementations. + `#755 `_. + +* Slimmer and more efficient STL-compatible iterator interface for sequence types. + `#662 `_. + +* Improved custom holder type support. + `#607 `_. + +* ``nullptr`` to ``None`` conversion fixed in various builtin type casters. + `#732 `_. + +* ``enum_`` now exposes its members via a special ``__members__`` attribute. + `#666 `_. + +* ``std::vector`` bindings created using ``stl_bind.h`` can now optionally + implement the buffer protocol. `#488 `_. + +* Automated C++ reference documentation using doxygen and breathe. + `#598 `_. + +* Added minimum compiler version assertions. + `#727 `_. + +* Improved compatibility with C++1z. + `#677 `_. + +* Improved ``py::capsule`` API. Can be used to implement cleanup + callbacks that are involved at module destruction time. + `#752 `_. + +* Various minor improvements and fixes. + `#595 `_, + `#588 `_, + `#589 `_, + `#603 `_, + `#619 `_, + `#648 `_, + `#695 `_, + `#720 `_, + `#723 `_, + `#729 `_, + `#724 `_, + `#742 `_, + `#753 `_. + +v2.0.1 (Jan 4, 2017) +----------------------------------------------------- + +* Fix pointer to reference error in type_caster on MSVC + `#583 `_. + +* Fixed a segmentation in the test suite due to a typo + `cd7eac `_. + +v2.0.0 (Jan 1, 2017) +----------------------------------------------------- + +* Fixed a reference counting regression affecting types with custom metaclasses + (introduced in v2.0.0-rc1). + `#571 `_. + +* Quenched a CMake policy warning. + `#570 `_. + +v2.0.0-rc1 (Dec 23, 2016) +----------------------------------------------------- + +The pybind11 developers are excited to issue a release candidate of pybind11 +with a subsequent v2.0.0 release planned in early January next year. + +An incredible amount of effort by went into pybind11 over the last ~5 months, +leading to a release that is jam-packed with exciting new features and numerous +usability improvements. The following list links PRs or individual commits +whenever applicable. + +Happy Christmas! + +* Support for binding C++ class hierarchies that make use of multiple + inheritance. `#410 `_. + +* PyPy support: pybind11 now supports nightly builds of PyPy and will + interoperate with the future 5.7 release. No code changes are necessary, + everything "just" works as usual. Note that we only target the Python 2.7 + branch for now; support for 3.x will be added once its ``cpyext`` extension + support catches up. A few minor features remain unsupported for the time + being (notably dynamic attributes in custom types). + `#527 `_. + +* Significant work on the documentation -- in particular, the monolithic + ``advanced.rst`` file was restructured into a easier to read hierarchical + organization. `#448 `_. + +* Many NumPy-related improvements: + + 1. Object-oriented API to access and modify NumPy ``ndarray`` instances, + replicating much of the corresponding NumPy C API functionality. + `#402 `_. + + 2. NumPy array ``dtype`` array descriptors are now first-class citizens and + are exposed via a new class ``py::dtype``. + + 3. Structured dtypes can be registered using the ``PYBIND11_NUMPY_DTYPE()`` + macro. Special ``array`` constructors accepting dtype objects were also + added. + + One potential caveat involving this change: format descriptor strings + should now be accessed via ``format_descriptor::format()`` (however, for + compatibility purposes, the old syntax ``format_descriptor::value`` will + still work for non-structured data types). `#308 + `_. + + 4. Further improvements to support structured dtypes throughout the system. + `#472 `_, + `#474 `_, + `#459 `_, + `#453 `_, + `#452 `_, and + `#505 `_. + + 5. Fast access operators. `#497 `_. + + 6. Constructors for arrays whose storage is owned by another object. + `#440 `_. + + 7. 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. + + 8. Added buffer/NumPy support for ``char[N]`` and ``std::array`` types. + + 9. Added ``memoryview`` wrapper type which is constructible from ``buffer_info``. + +* Eigen: many additional conversions and support for non-contiguous + arrays/slices. + `#427 `_, + `#315 `_, + `#316 `_, + `#312 `_, and + `#267 `_ + +* Incompatible changes in ``class_<...>::class_()``: + + 1. Declarations of types that provide access via the buffer protocol must + now include the ``py::buffer_protocol()`` annotation as an argument to + the ``class_`` constructor. + + 2. Declarations of types that require a custom metaclass (i.e. all classes + which include static properties via commands such as + ``def_readwrite_static()``) must now include the ``py::metaclass()`` + annotation as an argument to the ``class_`` constructor. + + These two changes were necessary to make type definitions in pybind11 + future-proof, and to support PyPy via its cpyext mechanism. `#527 + `_. + + + 3. This version of pybind11 uses a redesigned mechanism for instantiating + trampoline classes that are used to override virtual methods from within + Python. This led to the following user-visible syntax change: instead of + + .. code-block:: cpp + + py::class_("MyClass") + .alias() + .... + + write + + .. code-block:: cpp + + py::class_("MyClass") + .... + + Importantly, both the original and the trampoline class are now + specified as an arguments (in arbitrary order) to the ``py::class_`` + template, and the ``alias<..>()`` call is gone. The new scheme has zero + overhead in cases when Python doesn't override any functions of the + underlying C++ class. `rev. 86d825 + `_. + +* Added ``eval`` and ``eval_file`` functions for evaluating expressions and + statements from a string or file. `rev. 0d3fc3 + `_. + +* pybind11 can now create types with a modifiable dictionary. + `#437 `_ and + `#444 `_. + +* Support for translation of arbitrary C++ exceptions to Python counterparts. + `#296 `_ and + `#273 `_. + +* Report full backtraces through mixed C++/Python code, better reporting for + import errors, fixed GIL management in exception processing. + `#537 `_, + `#494 `_, + `rev. e72d95 `_, and + `rev. 099d6e `_. + +* Support for bit-level operations, comparisons, and serialization of C++ + enumerations. `#503 `_, + `#508 `_, + `#380 `_, + `#309 `_. + `#311 `_. + +* The ``class_`` constructor now accepts its template arguments in any order. + `#385 `_. + +* Attribute and item accessors now have a more complete interface which makes + it possible to chain attributes as in + ``obj.attr("a")[key].attr("b").attr("method")(1, 2, 3)``. `#425 + `_. + +* Major redesign of the default and conversion constructors in ``pytypes.h``. + `#464 `_. + +* Added built-in support for ``std::shared_ptr`` holder type. It is no longer + necessary to to include a declaration of the form + ``PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr)`` (though continuing to + do so won't cause an error). + `#454 `_. + +* New ``py::overload_cast`` casting operator to select among multiple possible + overloads of a function. An example: + + .. code-block:: cpp + + py::class_(m, "Pet") + .def("set", py::overload_cast(&Pet::set), "Set the pet's age") + .def("set", py::overload_cast(&Pet::set), "Set the pet's name"); + + This feature only works on C++14-capable compilers. + `#541 `_. + +* C++ types are automatically cast to Python types, e.g. when assigning + them as an attribute. For instance, the following is now legal: + + .. code-block:: cpp + + py::module m = /* ... */ + m.attr("constant") = 123; + + (Previously, a ``py::cast`` call was necessary to avoid a compilation error.) + `#551 `_. + +* Redesigned ``pytest``-based test suite. `#321 `_. + +* Instance tracking to detect reference leaks in test suite. `#324 `_ + +* pybind11 can now distinguish between multiple different instances that are + located at the same memory address, but which have different types. + `#329 `_. + +* Improved logic in ``move`` return value policy. + `#510 `_, + `#297 `_. + +* Generalized unpacking API to permit calling Python functions from C++ using + notation such as ``foo(a1, a2, *args, "ka"_a=1, "kb"_a=2, **kwargs)``. `#372 `_. + +* ``py::print()`` function whose behavior matches that of the native Python + ``print()`` function. `#372 `_. + +* Added ``py::dict`` keyword constructor:``auto d = dict("number"_a=42, + "name"_a="World");``. `#372 `_. + +* Added ``py::str::format()`` method and ``_s`` literal: ``py::str s = "1 + 2 + = {}"_s.format(3);``. `#372 `_. + +* Added ``py::repr()`` function which is equivalent to Python's builtin + ``repr()``. `#333 `_. + +* Improved construction and destruction logic for holder types. It is now + possible to reference instances with smart pointer holder types without + constructing the holder if desired. The ``PYBIND11_DECLARE_HOLDER_TYPE`` + macro now accepts an optional second parameter to indicate whether the holder + type uses intrusive reference counting. + `#533 `_ and + `#561 `_. + +* Mapping a stateless C++ function to Python and back is now "for free" (i.e. + no extra indirections or argument conversion overheads). `rev. 954b79 + `_. + +* Bindings for ``std::valarray``. + `#545 `_. + +* Improved support for C++17 capable compilers. + `#562 `_. + +* Bindings for ``std::optional``. + `#475 `_, + `#476 `_, + `#479 `_, + `#499 `_, and + `#501 `_. + +* ``stl_bind.h``: general improvements and support for ``std::map`` and + ``std::unordered_map``. + `#490 `_, + `#282 `_, + `#235 `_. + +* The ``std::tuple``, ``std::pair``, ``std::list``, and ``std::vector`` type + casters now accept any Python sequence type as input. `rev. 107285 + `_. + +* Improved CMake Python detection on multi-architecture Linux. + `#532 `_. + +* Infrastructure to selectively disable or enable parts of the automatically + generated docstrings. `#486 `_. + +* ``reference`` and ``reference_internal`` are now the default return value + properties for static and non-static properties, respectively. `#473 + `_. (the previous defaults + were ``automatic``). `#473 `_. + +* Support for ``std::unique_ptr`` with non-default deleters or no deleter at + all (``py::nodelete``). `#384 `_. + +* Deprecated ``handle::call()`` method. The new syntax to call Python + functions is simply ``handle()``. It can also be invoked explicitly via + ``handle::operator()``, where ``X`` is an optional return value policy. + +* Print more informative error messages when ``make_tuple()`` or ``cast()`` + fail. `#262 `_. + +* Creation of holder types for classes deriving from + ``std::enable_shared_from_this<>`` now also works for ``const`` values. + `#260 `_. + +* ``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. + `#247 `_. + +* ``arg()`` now accepts a wider range of argument types for default values. + `#244 `_. + +* Support ``keep_alive`` where the nurse object may be ``None``. `#341 + `_. + +* Added constructors for ``str`` and ``bytes`` from zero-terminated char + pointers, and from char pointers and length. Added constructors for ``str`` + from ``bytes`` and for ``bytes`` from ``str``, which will perform UTF-8 + decoding/encoding as required. + +* Many other improvements of library internals without 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/pybind11/docs/classes.rst b/pybind11/docs/classes.rst new file mode 100644 index 0000000..1deec9b --- /dev/null +++ b/pybind11/docs/classes.rst @@ -0,0 +1,521 @@ +.. _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_MODULE(example, m) { + py::class_(m, "Pet") + .def(py::init()) + .def("setName", &Pet::setName) + .def("getName", &Pet::getName); + } + +: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) + + +.. [#f1] Stateless closures are those with an empty pair of brackets ``[]`` as the capture object. + +.. _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 ... + +Write only properties can be defined by passing ``nullptr`` as the +input for the read function. + +.. 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 and automatic downcasting +===================================== + +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!' + +The C++ classes defined above are regular non-polymorphic types with an +inheritance relationship. This is reflected in Python: + +.. code-block:: cpp + + // Return a base pointer to a derived instance + m.def("pet_store", []() { return std::unique_ptr(new Dog("Molly")); }); + +.. code-block:: pycon + + >>> p = example.pet_store() + >>> type(p) # `Dog` instance behind `Pet` pointer + Pet # no pointer downcasting for regular non-polymorphic types + >>> p.bark() + AttributeError: 'Pet' object has no attribute 'bark' + +The function returned a ``Dog`` instance, but because it's a non-polymorphic +type behind a base pointer, Python only sees a ``Pet``. In C++, a type is only +considered polymorphic if it has at least one virtual function and pybind11 +will automatically recognize this: + +.. code-block:: cpp + + struct PolymorphicPet { + virtual ~PolymorphicPet() = default; + }; + + struct PolymorphicDog : PolymorphicPet { + std::string bark() const { return "woof!"; } + }; + + // Same binding code + py::class_(m, "PolymorphicPet"); + py::class_(m, "PolymorphicDog") + .def(py::init<>()) + .def("bark", &PolymorphicDog::bark); + + // Again, return a base pointer to a derived instance + m.def("pet_store2", []() { return std::unique_ptr(new PolymorphicDog); }); + +.. code-block:: pycon + + >>> p = example.pet_store2() + >>> type(p) + PolymorphicDog # automatically downcast + >>> p.bark() + u'woof!' + +Given a pointer to a polymorphic base, pybind11 performs automatic downcasting +to the actual derived type. Note that this goes beyond the usual situation in +C++: we don't just get access to the virtual functions of the base, we get the +concrete derived type including functions and attributes that the base type may +not even be aware of. + +.. seealso:: + + For more information about polymorphic behavior see :ref:`overriding_virtuals`. + + +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 + +If you have a C++14 compatible compiler [#cpp14]_, you can use an alternative +syntax to cast the overloaded function: + +.. code-block:: cpp + + py::class_(m, "Pet") + .def("set", py::overload_cast(&Pet::set), "Set the pet's age") + .def("set", py::overload_cast(&Pet::set), "Set the pet's name"); + +Here, ``py::overload_cast`` only requires the parameter types to be specified. +The return type and class are deduced. This avoids the additional noise of +``void (Pet::*)()`` as seen in the raw cast. If a function is overloaded based +on constness, the ``py::const_`` tag should be used: + +.. code-block:: cpp + + struct Widget { + int foo(int x, float y); + int foo(int x, float y) const; + }; + + py::class_(m, "Widget") + .def("foo_mutable", py::overload_cast(&Widget::foo)) + .def("foo_const", py::overload_cast(&Widget::foo, py::const_)); + + +.. [#cpp14] A compiler which supports the ``-std=c++14`` flag + or Visual Studio 2015 Update 2 and newer. + +.. 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 + +The entries defined by the enumeration type are exposed in the ``__members__`` property: + +.. code-block:: pycon + + >>> Pet.Kind.__members__ + {'Dog': Kind.Dog, 'Cat': Kind.Cat} + +The ``name`` property returns the name of the enum value as a unicode string. + +.. note:: + + It is also possible to use ``str(enum)``, however these accomplish different + goals. The following shows how these two approaches differ. + + .. code-block:: pycon + + >>> p = Pet( "Lucy", Pet.Cat ) + >>> pet_type = p.type + >>> pet_type + Pet.Cat + >>> str(pet_type) + 'Pet.Cat' + >>> pet_type.name + 'Cat' + +.. 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. diff --git a/pybind11/docs/compiling.rst b/pybind11/docs/compiling.rst new file mode 100644 index 0000000..bbd7a2c --- /dev/null +++ b/pybind11/docs/compiling.rst @@ -0,0 +1,277 @@ +.. _compiling: + +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 the pybind11 project which +provides the ``pybind11_add_module`` function. It will take care of all the +details needed to build a Python extension module on any platform. + +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 + +pybind11_add_module +------------------- + +To ease the creation of Python extension modules, pybind11 provides a CMake +function with the following signature: + +.. code-block:: cmake + + pybind11_add_module( [MODULE | SHARED] [EXCLUDE_FROM_ALL] + [NO_EXTRAS] [SYSTEM] [THIN_LTO] source1 [source2 ...]) + +This function behaves very much like CMake's builtin ``add_library`` (in fact, +it's a wrapper function around that command). It will add a library target +called ```` to be built from the listed source files. In addition, it +will take care of all the Python-specific compiler and linker flags as well +as the OS- and Python-version-specific file extension. The produced target +```` can be further manipulated with regular CMake commands. + +``MODULE`` or ``SHARED`` may be given to specify the type of library. If no +type is given, ``MODULE`` is used by default which ensures the creation of a +Python-exclusive module. Specifying ``SHARED`` will create a more traditional +dynamic library which can also be linked from elsewhere. ``EXCLUDE_FROM_ALL`` +removes this target from the default build (see CMake docs for details). + +Since pybind11 is a template library, ``pybind11_add_module`` adds compiler +flags to ensure high quality code generation without bloat arising from long +symbol names and duplication of code in different translation units. It +sets default visibility to *hidden*, which is required for some pybind11 +features and functionality when attempting to load multiple pybind11 modules +compiled under different pybind11 versions. It also adds additional flags +enabling LTO (Link Time Optimization) and strip unneeded symbols. See the +:ref:`FAQ entry ` for a more detailed explanation. These +latter optimizations are never applied in ``Debug`` mode. If ``NO_EXTRAS`` is +given, they will always be disabled, even in ``Release`` mode. However, this +will result in code bloat and is generally not recommended. + +By default, pybind11 and Python headers will be included with ``-I``. In order +to include pybind11 as system library, e.g. to avoid warnings in downstream +code with warn-levels outside of pybind11's scope, set the option ``SYSTEM``. + +As stated above, LTO is enabled by default. Some newer compilers also support +different flavors of LTO such as `ThinLTO`_. Setting ``THIN_LTO`` will cause +the function to prefer this flavor if available. The function falls back to +regular LTO if ``-flto=thin`` is not available. + +.. _ThinLTO: http://clang.llvm.org/docs/ThinLTO.html + +Configuration variables +----------------------- + +By default, pybind11 will compile modules with the C++14 standard, if available +on the target compiler, falling back to C++11 if C++14 support is not +available. Note, however, that this default is subject to change: future +pybind11 releases are expected to migrate to newer C++ standards as they become +available. To override this, the standard flag can be given explicitly in +``PYBIND11_CPP_STANDARD``: + +.. code-block:: cmake + + # Use just one of these: + # GCC/clang: + set(PYBIND11_CPP_STANDARD -std=c++11) + set(PYBIND11_CPP_STANDARD -std=c++14) + set(PYBIND11_CPP_STANDARD -std=c++1z) # Experimental C++17 support + # MSVC: + set(PYBIND11_CPP_STANDARD /std:c++14) + set(PYBIND11_CPP_STANDARD /std:c++latest) # Enables some MSVC C++17 features + + add_subdirectory(pybind11) # or find_package(pybind11) + +Note that this and all other configuration variables must be set **before** the +call to ``add_subdirectory`` or ``find_package``. The variables can also be set +when calling CMake from the command line using the ``-D=`` flag. + +The target Python version can be selected by setting ``PYBIND11_PYTHON_VERSION`` +or an exact Python installation can be specified with ``PYTHON_EXECUTABLE``. +For example: + +.. code-block:: bash + + cmake -DPYBIND11_PYTHON_VERSION=3.6 .. + # or + cmake -DPYTHON_EXECUTABLE=path/to/python .. + +find_package vs. add_subdirectory +--------------------------------- + +For CMake-based projects that don't include the pybind11 repository internally, +an external installation can be detected through ``find_package(pybind11)``. +See the `Config file`_ docstring for details of relevant CMake variables. + +.. code-block:: cmake + + cmake_minimum_required(VERSION 2.8.12) + project(example) + + find_package(pybind11 REQUIRED) + pybind11_add_module(example example.cpp) + +Once detected, the aforementioned ``pybind11_add_module`` can be employed as +before. The function usage and configuration variables are identical no matter +if pybind11 is added as a subdirectory or found as an installed package. You +can refer to the same [cmake_example]_ repository for a full sample project +-- just swap out ``add_subdirectory`` for ``find_package``. + +.. _Config file: https://github.com/pybind/pybind11/blob/master/tools/pybind11Config.cmake.in + +Advanced: interface library target +---------------------------------- + +When using a version of CMake greater than 3.0, pybind11 can additionally +be used as a special *interface library* . The target ``pybind11::module`` +is available with pybind11 headers, Python headers and libraries as needed, +and C++ compile definitions attached. This target is suitable for linking +to an independently constructed (through ``add_library``, not +``pybind11_add_module``) target in the consuming project. + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.0) + project(example) + + find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11) + + add_library(example MODULE main.cpp) + target_link_libraries(example PRIVATE pybind11::module) + set_target_properties(example PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" + SUFFIX "${PYTHON_MODULE_EXTENSION}") + +.. warning:: + + Since pybind11 is a metatemplate library, it is crucial that certain + compiler flags are provided to ensure high quality code generation. In + contrast to the ``pybind11_add_module()`` command, the CMake interface + library only provides the *minimal* set of parameters to ensure that the + code using pybind11 compiles, but it does **not** pass these extra compiler + flags (i.e. this is up to you). + + These include Link Time Optimization (``-flto`` on GCC/Clang/ICPC, ``/GL`` + and ``/LTCG`` on Visual Studio) and .OBJ files with many sections on Visual + Studio (``/bigobj``). The :ref:`FAQ ` contains an + explanation on why these are needed. + +Embedding the Python interpreter +-------------------------------- + +In addition to extension modules, pybind11 also supports embedding Python into +a C++ executable or library. In CMake, simply link with the ``pybind11::embed`` +target. It provides everything needed to get the interpreter running. The Python +headers and libraries are attached to the target. Unlike ``pybind11::module``, +there is no need to manually set any additional properties here. For more +information about usage in C++, see :doc:`/advanced/embedding`. + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.0) + project(example) + + find_package(pybind11 REQUIRED) # or add_subdirectory(pybind11) + + add_executable(example main.cpp) + target_link_libraries(example PRIVATE pybind11::embed) + +.. _building_manually: + +Building manually +================= + +pybind11 is a header-only library, hence it is not necessary to link against +any special libraries and there are no intermediate (magic) translation steps. + +On Linux, you can compile an example such as the one given in +:ref:`simple_example` using the following command: + +.. code-block:: bash + + $ c++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix` + +The flags given here assume that you're using Python 3. For Python 2, just +change the executable appropriately (to ``python`` or ``python2``). + +The ``python3 -m pybind11 --includes`` command fetches the include paths for +both pybind11 and Python headers. This assumes that pybind11 has been installed +using ``pip`` or ``conda``. If it hasn't, you can also manually specify +``-I /include`` together with the Python includes path +``python3-config --includes``. + +Note that Python 2.7 modules don't use a special suffix, so you should simply +use ``example.so`` instead of ``example`python3-config --extension-suffix```. +Besides, the ``--extension-suffix`` option may or may not be available, depending +on the distribution; in the latter case, the module extension can be manually +set to ``.so``. + +On Mac OS: the build command is almost the same but it also requires passing +the ``-undefined dynamic_lookup`` flag so as to ignore missing symbols when +building the module: + +.. code-block:: bash + + $ c++ -O3 -Wall -shared -std=c++11 -undefined dynamic_lookup `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix` + +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 that works on all platforms including Windows. + +.. note:: + + On Linux and macOS, it's better to (intentionally) not link against + ``libpython``. The symbols will be resolved when the extension library + is loaded into a Python binary. This is preferable because you might + have several different installations of a given Python version (e.g. the + system-provided Python, and one that ships with a piece of commercial + software). In this way, the plugin will work with both versions, instead + of possibly importing a second Python library into a process that already + contains one (which will lead to a segfault). + +Generating binding code automatically +===================================== + +The ``Binder`` project is a tool for automatic generation of pybind11 binding +code by introspecting existing C++ codebases using LLVM/Clang. See the +[binder]_ documentation for details. + +.. [binder] http://cppbinder.readthedocs.io/en/latest/about.html diff --git a/pybind11/docs/conf.py b/pybind11/docs/conf.py new file mode 100644 index 0000000..9ae10f4 --- /dev/null +++ b/pybind11/docs/conf.py @@ -0,0 +1,332 @@ +#!/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 +import subprocess + +# 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 = ['breathe'] + +breathe_projects = {'pybind11': '.build/doxygenxml/'} +breathe_default_project = 'pybind11' +breathe_domain_by_extension = {'h': 'cpp'} + +# 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 = '2017, 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 = '2.3' +# The full version, including alpha/beta/rc tags. +release = '2.3.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 = 'any' + +# 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.txt 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' + + +def generate_doxygen_xml(app): + build_dir = os.path.join(app.confdir, '.build') + if not os.path.exists(build_dir): + os.mkdir(build_dir) + + try: + subprocess.call(['doxygen', '--version']) + retcode = subprocess.call(['doxygen'], cwd=app.confdir) + if retcode < 0: + sys.stderr.write("doxygen error code: {}\n".format(-retcode)) + except OSError as e: + sys.stderr.write("doxygen execution failed: {}\n".format(e)) + + +def setup(app): + """Add hook for building doxygen xml when needed""" + app.connect("builder-inited", generate_doxygen_xml) diff --git a/pybind11/docs/faq.rst b/pybind11/docs/faq.rst new file mode 100644 index 0000000..99a12cb --- /dev/null +++ b/pybind11/docs/faq.rst @@ -0,0 +1,295 @@ +Frequently asked questions +########################## + +"ImportError: dynamic module does not define init function" +=========================================================== + +1. Make sure that the name specified in PYBIND11_MODULE is identical to the +filename of the extension library (without prefixes such as .so) + +2. If the above did not fix the issue, 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 the first answer. + +"SystemError: dynamic module not initialized properly" +====================================================== + +See the first answer. + +The Python interpreter immediately crashes when importing my module +=================================================================== + +See 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_MODULE(example, m) { + init_ex1(m); + init_ex2(m); + /* ... */ + } + +: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_ex2(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. + +.. _`faq:hidden_visibility`: + +"‘SomeClass’ declared with greater visibility than the type of its field ‘SomeClass::member’ [-Wattributes]" +============================================================================================================ + +This error typically indicates that you are compiling without the required +``-fvisibility`` flag. pybind11 code internally forces hidden visibility on +all internal code, but if non-hidden (and thus *exported*) code attempts to +include a pybind type (for example, ``py::object`` or ``py::list``) you can run +into this warning. + +To avoid it, make sure you are specifying ``-fvisibility=hidden`` when +compiling pybind code. + +As to why ``-fvisibility=hidden`` is necessary, because pybind modules could +have been compiled under different versions of pybind itself, it is also +important that the symbols defined in one module do not clash with the +potentially-incompatible symbols defined in another. While Python extension +modules are usually loaded with localized symbols (under POSIX systems +typically using ``dlopen`` with the ``RTLD_LOCAL`` flag), this Python default +can be changed, but even if it isn't it is not always enough to guarantee +complete independence of the symbols involved when not using +``-fvisibility=hidden``. + +Additionally, ``-fvisiblity=hidden`` can deliver considerably binary size +savings. (See the following section for more details). + + +.. _`faq:symhidden`: + +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*, which has a +tremendous impact on the final binary size of the resulting extension library. +(On Visual Studio, symbols are already hidden by default, so nothing needs to +be done there.) + +In addition to decreasing binary size, ``-fvisibility=hidden`` also avoids +potential serious issues when loading multiple modules and is required for +proper pybind operation. See the previous FAQ entry for more details. + +Working with ancient Visual Studio 2008 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 2008. 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. + +Inconsistent detection of Python version in CMake and pybind11 +============================================================== + +The functions ``find_package(PythonInterp)`` and ``find_package(PythonLibs)`` provided by CMake +for Python version detection are not used by pybind11 due to unreliability and limitations that make +them unsuitable for pybind11's needs. Instead pybind provides its own, more reliable Python detection +CMake code. Conflicts can arise, however, when using pybind11 in a project that *also* uses the CMake +Python detection in a system with several Python versions installed. + +This difference may cause inconsistencies and errors if *both* mechanisms are used in the same project. Consider the following +Cmake code executed in a system with Python 2.7 and 3.x installed: + +.. code-block:: cmake + + find_package(PythonInterp) + find_package(PythonLibs) + find_package(pybind11) + +It will detect Python 2.7 and pybind11 will pick it as well. + +In contrast this code: + +.. code-block:: cmake + + find_package(pybind11) + find_package(PythonInterp) + find_package(PythonLibs) + +will detect Python 3.x for pybind11 and may crash on ``find_package(PythonLibs)`` afterwards. + +It is advised to avoid using ``find_package(PythonInterp)`` and ``find_package(PythonLibs)`` from CMake and rely +on pybind11 in detecting Python version. If this is not possible CMake machinery should be called *before* including pybind11. + +How to cite this project? +========================= + +We suggest the following BibTeX template to cite pybind11 in scientific +discourse: + +.. code-block:: bash + + @misc{pybind11, + author = {Wenzel Jakob and Jason Rhinelander and Dean Moldovan}, + year = {2017}, + note = {https://github.com/pybind/pybind11}, + title = {pybind11 -- Seamless operability between C++11 and Python} + } diff --git a/pybind11/docs/index.rst b/pybind11/docs/index.rst new file mode 100644 index 0000000..d236611 --- /dev/null +++ b/pybind11/docs/index.rst @@ -0,0 +1,47 @@ +.. only: not latex + + .. image:: pybind11-logo.png + +pybind11 --- Seamless operability between C++11 and Python +========================================================== + +.. only: not latex + + Contents: + +.. toctree:: + :maxdepth: 1 + + intro + changelog + upgrade + +.. 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/embedding + advanced/misc + +.. toctree:: + :caption: Extra Information + :maxdepth: 1 + + faq + benchmark + limitations + reference diff --git a/pybind11/docs/intro.rst b/pybind11/docs/intro.rst new file mode 100644 index 0000000..10e1799 --- /dev/null +++ b/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 ~4K lines of code and depend on +Python (2.7 or 3.x, or PyPy2.7 >= 5.7) 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 +- 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: + +- Python 2.7, 3.x, and PyPy (PyPy2.7 >= 5.7) are supported with an + implementation-agnostic interface. + +- 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**. + +- Function signatures are precomputed at compile time (using ``constexpr``), + 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 4.8 or newer +3. Microsoft Visual Studio 2015 or newer +4. Intel C++ compiler v17 or newer (v16 with pybind11 v2.0 and v15 with pybind11 v2.0 and a `workaround `_ ) diff --git a/pybind11/docs/limitations.rst b/pybind11/docs/limitations.rst new file mode 100644 index 0000000..a1a4f1a --- /dev/null +++ b/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/pybind11/docs/pybind11-logo.png b/pybind11/docs/pybind11-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4cbad54f797d3ced04d4048f282df5e4336d4af4 GIT binary patch literal 58510 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pybind11/docs/pybind11_vs_boost_python2.png b/pybind11/docs/pybind11_vs_boost_python2.png new file mode 100644 index 0000000000000000000000000000000000000000..9f17272c50663957d6ae6d8e23fdd5a15757e71f GIT binary patch literal 41121 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 BtT6xp literal 0 HcmV?d00001 diff --git a/pybind11/docs/pybind11_vs_boost_python2.svg b/pybind11/docs/pybind11_vs_boost_python2.svg new file mode 100644 index 0000000..5ed6530 --- /dev/null +++ b/pybind11/docs/pybind11_vs_boost_python2.svg @@ -0,0 +1,427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pybind11/docs/reference.rst b/pybind11/docs/reference.rst new file mode 100644 index 0000000..3f74849 --- /dev/null +++ b/pybind11/docs/reference.rst @@ -0,0 +1,102 @@ +.. _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: + +Macros +====== + +.. doxygendefine:: PYBIND11_MODULE + +.. _core_types: + +Convenience classes for arbitrary Python types +============================================== + +Common member functions +----------------------- + +.. doxygenclass:: object_api + :members: + +Without reference counting +-------------------------- + +.. doxygenclass:: handle + :members: + +With reference counting +----------------------- + +.. doxygenclass:: object + :members: + +.. doxygenfunction:: reinterpret_borrow + +.. doxygenfunction:: reinterpret_steal + +Convenience classes for specific Python types +============================================= + +.. doxygenclass:: module + :members: + +.. doxygengroup:: pytypes + :members: + +.. _extras: + +Passing extra arguments to ``def`` or ``class_`` +================================================ + +.. doxygengroup:: annotations + :members: + +Embedding the interpreter +========================= + +.. doxygendefine:: PYBIND11_EMBEDDED_MODULE + +.. doxygenfunction:: initialize_interpreter + +.. doxygenfunction:: finalize_interpreter + +.. doxygenclass:: scoped_interpreter + +Redirecting C++ streams +======================= + +.. doxygenclass:: scoped_ostream_redirect + +.. doxygenclass:: scoped_estream_redirect + +.. doxygenfunction:: add_ostream_redirect + +Python built-in functions +========================= + +.. doxygengroup:: python_builtins + :members: + +Exceptions +========== + +.. doxygenclass:: error_already_set + :members: + +.. doxygenclass:: builtin_exception + :members: + + +Literals +======== + +.. doxygennamespace:: literals diff --git a/pybind11/docs/release.rst b/pybind11/docs/release.rst new file mode 100644 index 0000000..b31bbe9 --- /dev/null +++ b/pybind11/docs/release.rst @@ -0,0 +1,25 @@ +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 ``PYBIND11_VERSION_MAJOR`` etc. in ``include/pybind11/detail/common.h``. + - Ensure that all the information in ``setup.py`` is up-to-date. + - 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 + - download release package from Github: ``wget https://github.com/pybind/pybind11/archive/vX.Y.Z.tar.gz`` + - compute checksum: ``shasum -a 256 vX.Y.Z.tar.gz`` + - change version number and checksum in ``recipe/meta.yml`` +- 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/pybind11/docs/requirements.txt b/pybind11/docs/requirements.txt new file mode 100644 index 0000000..3818fe8 --- /dev/null +++ b/pybind11/docs/requirements.txt @@ -0,0 +1 @@ +breathe == 4.5.0 diff --git a/pybind11/docs/upgrade.rst b/pybind11/docs/upgrade.rst new file mode 100644 index 0000000..3f56973 --- /dev/null +++ b/pybind11/docs/upgrade.rst @@ -0,0 +1,404 @@ +Upgrade guide +############# + +This is a companion guide to the :doc:`changelog`. While the changelog briefly +lists all of the new features, improvements and bug fixes, this upgrade guide +focuses only the subset which directly impacts your experience when upgrading +to a new version. But it goes into more detail. This includes things like +deprecated APIs and their replacements, build system changes, general code +modernization and other useful information. + + +v2.2 +==== + +Deprecation of the ``PYBIND11_PLUGIN`` macro +-------------------------------------------- + +``PYBIND11_MODULE`` is now the preferred way to create module entry points. +The old macro emits a compile-time deprecation warning. + +.. code-block:: cpp + + // old + PYBIND11_PLUGIN(example) { + py::module m("example", "documentation string"); + + m.def("add", [](int a, int b) { return a + b; }); + + return m.ptr(); + } + + // new + PYBIND11_MODULE(example, m) { + m.doc() = "documentation string"; // optional + + m.def("add", [](int a, int b) { return a + b; }); + } + + +New API for defining custom constructors and pickling functions +--------------------------------------------------------------- + +The old placement-new custom constructors have been deprecated. The new approach +uses ``py::init()`` and factory functions to greatly improve type safety. + +Placement-new can be called accidentally with an incompatible type (without any +compiler errors or warnings), or it can initialize the same object multiple times +if not careful with the Python-side ``__init__`` calls. The new-style custom +constructors prevent such mistakes. See :ref:`custom_constructors` for details. + +.. code-block:: cpp + + // old -- deprecated (runtime warning shown only in debug mode) + py::class(m, "Foo") + .def("__init__", [](Foo &self, ...) { + new (&self) Foo(...); // uses placement-new + }); + + // new + py::class(m, "Foo") + .def(py::init([](...) { // Note: no `self` argument + return new Foo(...); // return by raw pointer + // or: return std::make_unique(...); // return by holder + // or: return Foo(...); // return by value (move constructor) + })); + +Mirroring the custom constructor changes, ``py::pickle()`` is now the preferred +way to get and set object state. See :ref:`pickling` for details. + +.. code-block:: cpp + + // old -- deprecated (runtime warning shown only in debug mode) + py::class(m, "Foo") + ... + .def("__getstate__", [](const Foo &self) { + return py::make_tuple(self.value1(), self.value2(), ...); + }) + .def("__setstate__", [](Foo &self, py::tuple t) { + new (&self) Foo(t[0].cast(), ...); + }); + + // new + py::class(m, "Foo") + ... + .def(py::pickle( + [](const Foo &self) { // __getstate__ + return py::make_tuple(f.value1(), f.value2(), ...); // unchanged + }, + [](py::tuple t) { // __setstate__, note: no `self` argument + return new Foo(t[0].cast(), ...); + // or: return std::make_unique(...); // return by holder + // or: return Foo(...); // return by value (move constructor) + } + )); + +For both the constructors and pickling, warnings are shown at module +initialization time (on import, not when the functions are called). +They're only visible when compiled in debug mode. Sample warning: + +.. code-block:: none + + pybind11-bound class 'mymodule.Foo' is using an old-style placement-new '__init__' + which has been deprecated. See the upgrade guide in pybind11's docs. + + +Stricter enforcement of hidden symbol visibility for pybind11 modules +--------------------------------------------------------------------- + +pybind11 now tries to actively enforce hidden symbol visibility for modules. +If you're using either one of pybind11's :doc:`CMake or Python build systems +` (the two example repositories) and you haven't been exporting any +symbols, there's nothing to be concerned about. All the changes have been done +transparently in the background. If you were building manually or relied on +specific default visibility, read on. + +Setting default symbol visibility to *hidden* has always been recommended for +pybind11 (see :ref:`faq:symhidden`). On Linux and macOS, hidden symbol +visibility (in conjunction with the ``strip`` utility) yields much smaller +module binaries. `CPython's extension docs`_ also recommend hiding symbols +by default, with the goal of avoiding symbol name clashes between modules. +Starting with v2.2, pybind11 enforces this more strictly: (1) by declaring +all symbols inside the ``pybind11`` namespace as hidden and (2) by including +the ``-fvisibility=hidden`` flag on Linux and macOS (only for extension +modules, not for embedding the interpreter). + +.. _CPython's extension docs: https://docs.python.org/3/extending/extending.html#providing-a-c-api-for-an-extension-module + +The namespace-scope hidden visibility is done automatically in pybind11's +headers and it's generally transparent to users. It ensures that: + +* Modules compiled with different pybind11 versions don't clash with each other. + +* Some new features, like ``py::module_local`` bindings, can work as intended. + +The ``-fvisibility=hidden`` flag applies the same visibility to user bindings +outside of the ``pybind11`` namespace. It's now set automatic by pybind11's +CMake and Python build systems, but this needs to be done manually by users +of other build systems. Adding this flag: + +* Minimizes the chances of symbol conflicts between modules. E.g. if two + unrelated modules were statically linked to different (ABI-incompatible) + versions of the same third-party library, a symbol clash would be likely + (and would end with unpredictable results). + +* Produces smaller binaries on Linux and macOS, as pointed out previously. + +Within pybind11's CMake build system, ``pybind11_add_module`` has always been +setting the ``-fvisibility=hidden`` flag in release mode. From now on, it's +being applied unconditionally, even in debug mode and it can no longer be opted +out of with the ``NO_EXTRAS`` option. The ``pybind11::module`` target now also +adds this flag to it's interface. The ``pybind11::embed`` target is unchanged. + +The most significant change here is for the ``pybind11::module`` target. If you +were previously relying on default visibility, i.e. if your Python module was +doubling as a shared library with dependents, you'll need to either export +symbols manually (recommended for cross-platform libraries) or factor out the +shared library (and have the Python module link to it like the other +dependents). As a temporary workaround, you can also restore default visibility +using the CMake code below, but this is not recommended in the long run: + +.. code-block:: cmake + + target_link_libraries(mymodule PRIVATE pybind11::module) + + add_library(restore_default_visibility INTERFACE) + target_compile_options(restore_default_visibility INTERFACE -fvisibility=default) + target_link_libraries(mymodule PRIVATE restore_default_visibility) + + +Local STL container bindings +---------------------------- + +Previous pybind11 versions could only bind types globally -- all pybind11 +modules, even unrelated ones, would have access to the same exported types. +However, this would also result in a conflict if two modules exported the +same C++ type, which is especially problematic for very common types, e.g. +``std::vector``. :ref:`module_local` were added to resolve this (see +that section for a complete usage guide). + +``py::class_`` still defaults to global bindings (because these types are +usually unique across modules), however in order to avoid clashes of opaque +types, ``py::bind_vector`` and ``py::bind_map`` will now bind STL containers +as ``py::module_local`` if their elements are: builtins (``int``, ``float``, +etc.), not bound using ``py::class_``, or bound as ``py::module_local``. For +example, this change allows multiple modules to bind ``std::vector`` +without causing conflicts. See :ref:`stl_bind` for more details. + +When upgrading to this version, if you have multiple modules which depend on +a single global binding of an STL container, note that all modules can still +accept foreign ``py::module_local`` types in the direction of Python-to-C++. +The locality only affects the C++-to-Python direction. If this is needed in +multiple modules, you'll need to either: + +* Add a copy of the same STL binding to all of the modules which need it. + +* Restore the global status of that single binding by marking it + ``py::module_local(false)``. + +The latter is an easy workaround, but in the long run it would be best to +localize all common type bindings in order to avoid conflicts with +third-party modules. + + +Negative strides for Python buffer objects and numpy arrays +----------------------------------------------------------- + +Support for negative strides required changing the integer type from unsigned +to signed in the interfaces of ``py::buffer_info`` and ``py::array``. If you +have compiler warnings enabled, you may notice some new conversion warnings +after upgrading. These can be resolved using ``static_cast``. + + +Deprecation of some ``py::object`` APIs +--------------------------------------- + +To compare ``py::object`` instances by pointer, you should now use +``obj1.is(obj2)`` which is equivalent to ``obj1 is obj2`` in Python. +Previously, pybind11 used ``operator==`` for this (``obj1 == obj2``), but +that could be confusing and is now deprecated (so that it can eventually +be replaced with proper rich object comparison in a future release). + +For classes which inherit from ``py::object``, ``borrowed`` and ``stolen`` +were previously available as protected constructor tags. Now the types +should be used directly instead: ``borrowed_t{}`` and ``stolen_t{}`` +(`#771 `_). + + +Stricter compile-time error checking +------------------------------------ + +Some error checks have been moved from run time to compile time. Notably, +automatic conversion of ``std::shared_ptr`` is not possible when ``T`` is +not directly registered with ``py::class_`` (e.g. ``std::shared_ptr`` +or ``std::shared_ptr>`` are not automatically convertible). +Attempting to bind a function with such arguments now results in a compile-time +error instead of waiting to fail at run time. + +``py::init<...>()`` constructor definitions are also stricter and now prevent +bindings which could cause unexpected behavior: + +.. code-block:: cpp + + struct Example { + Example(int &); + }; + + py::class_(m, "Example") + .def(py::init()); // OK, exact match + // .def(py::init()); // compile-time error, mismatch + +A non-``const`` lvalue reference is not allowed to bind to an rvalue. However, +note that a constructor taking ``const T &`` can still be registered using +``py::init()`` because a ``const`` lvalue reference can bind to an rvalue. + +v2.1 +==== + +Minimum compiler versions are enforced at compile time +------------------------------------------------------ + +The minimums also apply to v2.0 but the check is now explicit and a compile-time +error is raised if the compiler does not meet the requirements: + +* GCC >= 4.8 +* clang >= 3.3 (appleclang >= 5.0) +* MSVC >= 2015u3 +* Intel C++ >= 15.0 + + +The ``py::metaclass`` attribute is not required for static properties +--------------------------------------------------------------------- + +Binding classes with static properties is now possible by default. The +zero-parameter version of ``py::metaclass()`` is deprecated. However, a new +one-parameter ``py::metaclass(python_type)`` version was added for rare +cases when a custom metaclass is needed to override pybind11's default. + +.. code-block:: cpp + + // old -- emits a deprecation warning + py::class_(m, "Foo", py::metaclass()) + .def_property_readonly_static("foo", ...); + + // new -- static properties work without the attribute + py::class_(m, "Foo") + .def_property_readonly_static("foo", ...); + + // new -- advanced feature, override pybind11's default metaclass + py::class_(m, "Bar", py::metaclass(custom_python_type)) + ... + + +v2.0 +==== + +Breaking changes in ``py::class_`` +---------------------------------- + +These changes were necessary to make type definitions in pybind11 +future-proof, to support PyPy via its ``cpyext`` mechanism (`#527 +`_), and to improve efficiency +(`rev. 86d825 `_). + +1. Declarations of types that provide access via the buffer protocol must + now include the ``py::buffer_protocol()`` annotation as an argument to + the ``py::class_`` constructor. + + .. code-block:: cpp + + py::class_("Matrix", py::buffer_protocol()) + .def(py::init<...>()) + .def_buffer(...); + +2. Classes which include static properties (e.g. ``def_readwrite_static()``) + must now include the ``py::metaclass()`` attribute. Note: this requirement + has since been removed in v2.1. If you're upgrading from 1.x, it's + recommended to skip directly to v2.1 or newer. + +3. This version of pybind11 uses a redesigned mechanism for instantiating + trampoline classes that are used to override virtual methods from within + Python. This led to the following user-visible syntax change: + + .. code-block:: cpp + + // old v1.x syntax + py::class_("MyClass") + .alias() + ... + + // new v2.x syntax + py::class_("MyClass") + ... + + Importantly, both the original and the trampoline class are now specified + as arguments to the ``py::class_`` template, and the ``alias<..>()`` call + is gone. The new scheme has zero overhead in cases when Python doesn't + override any functions of the underlying C++ class. + `rev. 86d825 `_. + + The class type must be the first template argument given to ``py::class_`` + while the trampoline can be mixed in arbitrary order with other arguments + (see the following section). + + +Deprecation of the ``py::base()`` attribute +---------------------------------------------- + +``py::base()`` was deprecated in favor of specifying ``T`` as a template +argument to ``py::class_``. This new syntax also supports multiple inheritance. +Note that, while the type being exported must be the first argument in the +``py::class_`` template, the order of the following types (bases, +holder and/or trampoline) is not important. + +.. code-block:: cpp + + // old v1.x + py::class_("Derived", py::base()); + + // new v2.x + py::class_("Derived"); + + // new -- multiple inheritance + py::class_("Derived"); + + // new -- apart from `Derived` the argument order can be arbitrary + py::class_("Derived"); + + +Out-of-the-box support for ``std::shared_ptr`` +---------------------------------------------- + +The relevant type caster is now built in, so it's no longer necessary to +include a declaration of the form: + +.. code-block:: cpp + + PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr) + +Continuing to do so won’t cause an error or even a deprecation warning, +but it's completely redundant. + + +Deprecation of a few ``py::object`` APIs +---------------------------------------- + +All of the old-style calls emit deprecation warnings. + ++---------------------------------------+---------------------------------------------+ +| Old syntax | New syntax | ++=======================================+=============================================+ +| ``obj.call(args...)`` | ``obj(args...)`` | ++---------------------------------------+---------------------------------------------+ +| ``obj.str()`` | ``py::str(obj)`` | ++---------------------------------------+---------------------------------------------+ +| ``auto l = py::list(obj); l.check()`` | ``py::isinstance(obj)`` | ++---------------------------------------+---------------------------------------------+ +| ``py::object(ptr, true)`` | ``py::reinterpret_borrow(ptr)`` | ++---------------------------------------+---------------------------------------------+ +| ``py::object(ptr, false)`` | ``py::reinterpret_steal(ptr)`` | ++---------------------------------------+---------------------------------------------+ +| ``if (obj.attr("foo"))`` | ``if (py::hasattr(obj, "foo"))`` | ++---------------------------------------+---------------------------------------------+ +| ``if (obj["bar"])`` | ``if (obj.contains("bar"))`` | ++---------------------------------------+---------------------------------------------+ diff --git a/pybind11/include/pybind11/attr.h b/pybind11/include/pybind11/attr.h new file mode 100644 index 0000000..8732cfe --- /dev/null +++ b/pybind11/include/pybind11/attr.h @@ -0,0 +1,492 @@ +/* + pybind11/attr.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_NAMESPACE) + +/// \addtogroup annotations +/// @{ + +/// 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 which enables the buffer protocol for a type +struct buffer_protocol { }; + +/// Annotation which requests that a special metaclass is created for a type +struct metaclass { + handle value; + + PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.") + metaclass() {} + + /// Override pybind11's default metaclass + explicit metaclass(handle value) : value(value) { } +}; + +/// Annotation that marks a class as local to the module: +struct module_local { const bool value; constexpr module_local(bool v = true) : value(v) { } }; + +/// Annotation to mark enums as an arithmetic type +struct arithmetic { }; + +/** \rst + A call policy which places one or more guard variables (``Ts...``) around the function call. + + For example, this definition: + + .. code-block:: cpp + + m.def("foo", foo, py::call_guard()); + + is equivalent to the following pseudocode: + + .. code-block:: cpp + + m.def("foo", [](args...) { + T scope_guard; + return foo(args...); // forwarded arguments + }); + \endrst */ +template struct call_guard; + +template <> struct call_guard<> { using type = detail::void_type; }; + +template +struct call_guard { + static_assert(std::is_default_constructible::value, + "The guard type must be default constructible"); + + using type = T; +}; + +template +struct call_guard { + struct type { + T guard{}; // Compose multiple guard types with left-to-right default-constructor order + typename call_guard::type next{}; + }; +}; + +/// @} annotations + +NAMESPACE_BEGIN(detail) +/* Forward declarations */ +enum op_id : int; +enum op_type : int; +struct undefined_t; +template struct op_; +inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, 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 + bool convert : 1; ///< True if the argument is allowed to convert when loading + bool none : 1; ///< True if None is allowed when loading + + argument_record(const char *name, const char *descr, handle value, bool convert, bool none) + : name(name), descr(descr), value(value), convert(convert), none(none) { } +}; + +/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.) +struct function_record { + function_record() + : is_constructor(false), is_new_style_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_call &) = 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 new-style `__init__` defined in `detail/init.h` + bool is_new_style_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 (including py::args and/or py::kwargs, if present) + std::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() + : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false), module_local(false) { } + + /// 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; + + /// What is the alignment of the underlying C++ type? + size_t type_align = 0; + + /// How large is the type's holder? + size_t holder_size = 0; + + /// The global operator new can be overridden with a class-specific variant + void *(*operator_new)(size_t) = nullptr; + + /// Function pointer to class_<..>::init_instance + void (*init_instance)(instance *, const void *) = nullptr; + + /// Function pointer to class_<..>::dealloc + void (*dealloc)(detail::value_and_holder &) = nullptr; + + /// List of base classes of the newly created type + list bases; + + /// Optional docstring + const char *doc = nullptr; + + /// Custom metaclass (optional) + handle metaclass; + + /// Multiple inheritance marker + bool multiple_inheritance : 1; + + /// Does the class manage a __dict__? + bool dynamic_attr : 1; + + /// Does the class implement the buffer protocol? + bool buffer_protocol : 1; + + /// Is the default (unique_ptr) holder type used? + bool default_holder : 1; + + /// Is the class definition local to the module shared object? + bool module_local : 1; + + 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 + "\""); + } + + if (default_holder != base_info->default_holder) { + std::string tname(base.name()); + detail::clean_type_id(tname); + pybind11_fail("generic_type: type \"" + std::string(name) + "\" " + + (default_holder ? "does not have" : "has") + + " a non-default holder type while its base \"" + tname + "\" " + + (base_info->default_holder ? "does not" : "does")); + } + + bases.append((PyObject *) base_info->type); + + if (base_info->type->tp_dictoffset != 0) + dynamic_attr = true; + + if (caster) + base_info->implicit_casts.emplace_back(type, caster); + } +}; + +inline function_call::function_call(const function_record &f, handle p) : + func(f), parent(p) { + args.reserve(f.nargs); + args_convert.reserve(f.nargs); +} + +/// Tag for a new-style `__init__` defined in `detail/init.h` +struct is_new_style_constructor { }; + +/** + * 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(function_call &) { } + static void postcall(function_call &, 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; } +}; + +template <> struct process_attribute : process_attribute_default { + static void init(const is_new_style_constructor &, function_record *r) { r->is_new_style_constructor = 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(), true /*convert*/, false /*none not allowed*/); + r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none); + } +}; + +/// 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 /*descr*/, handle() /*parent*/, true /*convert*/, false /*none not allowed*/); + + if (!a.value) { +#if !defined(NDEBUG) + std::string descr("'"); + if (a.name) descr += std::string(a.name) + ": "; + descr += 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 '" + (std::string) r->name + "'"; + } + pybind11_fail("arg(): could not convert default argument " + + descr + " into a Python object (type not registered yet?)"); +#else + pybind11_fail("arg(): could not convert default 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(), !a.flag_noconvert, a.flag_none); + } +}; + +/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees that) +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; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const module_local &l, type_record *r) { r->module_local = l.value; } +}; + +/// Process an 'arithmetic' attribute for enums (does nothing here) +template <> +struct process_attribute : process_attribute_default {}; + +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(function_call &call) { keep_alive_impl(Nurse, Patient, call, handle()); } + template = 0> + static void postcall(function_call &, handle) { } + template = 0> + static void precall(function_call &) { } + template = 0> + static void postcall(function_call &call, handle ret) { keep_alive_impl(Nurse, Patient, call, 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(function_call &call) { + int unused[] = { 0, (process_attribute::type>::precall(call), 0) ... }; + ignore_unused(unused); + } + static void postcall(function_call &call, handle fn_ret) { + int unused[] = { 0, (process_attribute::type>::postcall(call, fn_ret), 0) ... }; + ignore_unused(unused); + } +}; + +template +using is_call_guard = is_instantiation; + +/// Extract the ``type`` from the first `call_guard` in `Extras...` (or `void_type` if none found) +template +using extract_guard_t = typename exactly_one_t, Extra...>::type; + +/// 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, bool has_args, bool has_kwargs) { + return named == 0 || (self + named + has_args + has_kwargs) == nargs; +} + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/pybind11/include/pybind11/buffer_info.h b/pybind11/include/pybind11/buffer_info.h new file mode 100644 index 0000000..9f072fa --- /dev/null +++ b/pybind11/include/pybind11/buffer_info.h @@ -0,0 +1,108 @@ +/* + pybind11/buffer_info.h: Python buffer object interface + + 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 "detail/common.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +/// Information record describing a Python buffer object +struct buffer_info { + void *ptr = nullptr; // Pointer to the underlying storage + ssize_t itemsize = 0; // Size of individual items in bytes + ssize_t size = 0; // Total number of entries + std::string format; // For homogeneous buffers, this should be set to format_descriptor::format() + ssize_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, ssize_t itemsize, const std::string &format, ssize_t ndim, + detail::any_container shape_in, detail::any_container strides_in) + : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), + shape(std::move(shape_in)), strides(std::move(strides_in)) { + if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) + pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); + for (size_t i = 0; i < (size_t) ndim; ++i) + size *= shape[i]; + } + + template + buffer_info(T *ptr, detail::any_container shape_in, detail::any_container strides_in) + : buffer_info(private_ctr_tag(), ptr, sizeof(T), format_descriptor::format(), static_cast(shape_in->size()), std::move(shape_in), std::move(strides_in)) { } + + buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size) + : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}) { } + + template + buffer_info(T *ptr, ssize_t size) + : buffer_info(ptr, sizeof(T), format_descriptor::format(), size) { } + + explicit buffer_info(Py_buffer *view, bool ownview = true) + : buffer_info(view->buf, view->itemsize, view->format, view->ndim, + {view->shape, view->shape + view->ndim}, {view->strides, view->strides + view->ndim}) { + this->view = view; + this->ownview = ownview; + } + + 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: + struct private_ctr_tag { }; + + buffer_info(private_ctr_tag, void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, + detail::any_container &&shape_in, detail::any_container &&strides_in) + : buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in)) { } + + Py_buffer *view = nullptr; + bool ownview = false; +}; + +NAMESPACE_BEGIN(detail) + +template struct compare_buffer_info { + static bool compare(const buffer_info& b) { + return b.format == format_descriptor::format() && b.itemsize == (ssize_t) sizeof(T); + } +}; + +template struct compare_buffer_info::value>> { + static bool compare(const buffer_info& b) { + return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor::value || + ((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned::value ? "L" : "l")) || + ((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned::value ? "N" : "n"))); + } +}; + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/pybind11/include/pybind11/cast.h b/pybind11/include/pybind11/cast.h new file mode 100644 index 0000000..80abb2b --- /dev/null +++ b/pybind11/include/pybind11/cast.h @@ -0,0 +1,2128 @@ +/* + 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 "detail/typeid.h" +#include "detail/descr.h" +#include "detail/internals.h" +#include +#include +#include +#include + +#if defined(PYBIND11_CPP17) +# if defined(__has_include) +# if __has_include() +# define PYBIND11_HAS_STRING_VIEW +# endif +# elif defined(_MSC_VER) +# define PYBIND11_HAS_STRING_VIEW +# endif +#endif +#ifdef PYBIND11_HAS_STRING_VIEW +#include +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +/// A life support system for temporary objects created by `type_caster::load()`. +/// Adding a patient will keep it alive up until the enclosing function returns. +class loader_life_support { +public: + /// A new patient frame is created when a function is entered + loader_life_support() { + get_internals().loader_patient_stack.push_back(nullptr); + } + + /// ... and destroyed after it returns + ~loader_life_support() { + auto &stack = get_internals().loader_patient_stack; + if (stack.empty()) + pybind11_fail("loader_life_support: internal error"); + + auto ptr = stack.back(); + stack.pop_back(); + Py_CLEAR(ptr); + + // A heuristic to reduce the stack's capacity (e.g. after long recursive calls) + if (stack.capacity() > 16 && stack.size() != 0 && stack.capacity() / stack.size() > 2) + stack.shrink_to_fit(); + } + + /// This can only be used inside a pybind11-bound function, either by `argument_loader` + /// at argument preparation time or by `py::cast()` at execution time. + PYBIND11_NOINLINE static void add_patient(handle h) { + auto &stack = get_internals().loader_patient_stack; + if (stack.empty()) + throw cast_error("When called outside a bound function, py::cast() cannot " + "do Python -> C++ conversions which require the creation " + "of temporary values"); + + auto &list_ptr = stack.back(); + if (list_ptr == nullptr) { + list_ptr = PyList_New(1); + if (!list_ptr) + pybind11_fail("loader_life_support: error allocating list"); + PyList_SET_ITEM(list_ptr, 0, h.inc_ref().ptr()); + } else { + auto result = PyList_Append(list_ptr, h.ptr()); + if (result == -1) + pybind11_fail("loader_life_support: error adding patient"); + } + } +}; + +// Gets the cache entry for the given type, creating it if necessary. The return value is the pair +// returned by emplace, i.e. an iterator for the entry and a bool set to `true` if the entry was +// just created. +inline std::pair all_type_info_get_cache(PyTypeObject *type); + +// Populates a just-created cache entry. +PYBIND11_NOINLINE inline void all_type_info_populate(PyTypeObject *t, std::vector &bases) { + std::vector check; + for (handle parent : reinterpret_borrow(t->tp_bases)) + check.push_back((PyTypeObject *) parent.ptr()); + + auto const &type_dict = get_internals().registered_types_py; + for (size_t i = 0; i < check.size(); i++) { + auto type = check[i]; + // Ignore Python2 old-style class super type: + if (!PyType_Check((PyObject *) type)) continue; + + // Check `type` in the current set of registered python types: + auto it = type_dict.find(type); + if (it != type_dict.end()) { + // We found a cache entry for it, so it's either pybind-registered or has pre-computed + // pybind bases, but we have to make sure we haven't already seen the type(s) before: we + // want to follow Python/virtual C++ rules that there should only be one instance of a + // common base. + for (auto *tinfo : it->second) { + // NB: Could use a second set here, rather than doing a linear search, but since + // having a large number of immediate pybind11-registered types seems fairly + // unlikely, that probably isn't worthwhile. + bool found = false; + for (auto *known : bases) { + if (known == tinfo) { found = true; break; } + } + if (!found) bases.push_back(tinfo); + } + } + else if (type->tp_bases) { + // It's some python type, so keep follow its bases classes to look for one or more + // registered types + if (i + 1 == check.size()) { + // When we're at the end, we can pop off the current element to avoid growing + // `check` when adding just one base (which is typical--i.e. when there is no + // multiple inheritance) + check.pop_back(); + i--; + } + for (handle parent : reinterpret_borrow(type->tp_bases)) + check.push_back((PyTypeObject *) parent.ptr()); + } + } +} + +/** + * Extracts vector of type_info pointers of pybind-registered roots of the given Python type. Will + * be just 1 pybind type for the Python type of a pybind-registered class, or for any Python-side + * derived class that uses single inheritance. Will contain as many types as required for a Python + * class that uses multiple inheritance to inherit (directly or indirectly) from multiple + * pybind-registered classes. Will be empty if neither the type nor any base classes are + * pybind-registered. + * + * The value is cached for the lifetime of the Python type. + */ +inline const std::vector &all_type_info(PyTypeObject *type) { + auto ins = all_type_info_get_cache(type); + if (ins.second) + // New cache entry: populate it + all_type_info_populate(type, ins.first->second); + + return ins.first->second; +} + +/** + * Gets a single pybind11 type info for a python type. Returns nullptr if neither the type nor any + * ancestors are pybind11-registered. Throws an exception if there are multiple bases--use + * `all_type_info` instead if you want to support multiple bases. + */ +PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) { + auto &bases = all_type_info(type); + if (bases.size() == 0) + return nullptr; + if (bases.size() > 1) + pybind11_fail("pybind11::detail::get_type_info: type has multiple pybind11-registered bases"); + return bases.front(); +} + +inline detail::type_info *get_local_type_info(const std::type_index &tp) { + auto &locals = registered_local_types_cpp(); + auto it = locals.find(tp); + if (it != locals.end()) + return it->second; + return nullptr; +} + +inline detail::type_info *get_global_type_info(const std::type_index &tp) { + auto &types = get_internals().registered_types_cpp; + auto it = types.find(tp); + if (it != types.end()) + return it->second; + return nullptr; +} + +/// Return the type info for a given C++ type; on lookup failure can either throw or return nullptr. +PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_index &tp, + bool throw_if_missing = false) { + if (auto ltype = get_local_type_info(tp)) + return ltype; + if (auto gtype = get_global_type_info(tp)) + return gtype; + + 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); +} + +struct value_and_holder { + instance *inst; + size_t index; + const detail::type_info *type; + void **vh; + + // Main constructor for a found value/holder: + value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index) : + inst{i}, index{index}, type{type}, + vh{inst->simple_layout ? inst->simple_value_holder : &inst->nonsimple.values_and_holders[vpos]} + {} + + // Default constructor (used to signal a value-and-holder not found by get_value_and_holder()) + value_and_holder() : inst{nullptr} {} + + // Used for past-the-end iterator + value_and_holder(size_t index) : index{index} {} + + template V *&value_ptr() const { + return reinterpret_cast(vh[0]); + } + // True if this `value_and_holder` has a non-null value pointer + explicit operator bool() const { return value_ptr(); } + + template H &holder() const { + return reinterpret_cast(vh[1]); + } + bool holder_constructed() const { + return inst->simple_layout + ? inst->simple_holder_constructed + : inst->nonsimple.status[index] & instance::status_holder_constructed; + } + void set_holder_constructed(bool v = true) { + if (inst->simple_layout) + inst->simple_holder_constructed = v; + else if (v) + inst->nonsimple.status[index] |= instance::status_holder_constructed; + else + inst->nonsimple.status[index] &= (uint8_t) ~instance::status_holder_constructed; + } + bool instance_registered() const { + return inst->simple_layout + ? inst->simple_instance_registered + : inst->nonsimple.status[index] & instance::status_instance_registered; + } + void set_instance_registered(bool v = true) { + if (inst->simple_layout) + inst->simple_instance_registered = v; + else if (v) + inst->nonsimple.status[index] |= instance::status_instance_registered; + else + inst->nonsimple.status[index] &= (uint8_t) ~instance::status_instance_registered; + } +}; + +// Container for accessing and iterating over an instance's values/holders +struct values_and_holders { +private: + instance *inst; + using type_vec = std::vector; + const type_vec &tinfo; + +public: + values_and_holders(instance *inst) : inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {} + + struct iterator { + private: + instance *inst; + const type_vec *types; + value_and_holder curr; + friend struct values_and_holders; + iterator(instance *inst, const type_vec *tinfo) + : inst{inst}, types{tinfo}, + curr(inst /* instance */, + types->empty() ? nullptr : (*types)[0] /* type info */, + 0, /* vpos: (non-simple types only): the first vptr comes first */ + 0 /* index */) + {} + // Past-the-end iterator: + iterator(size_t end) : curr(end) {} + public: + bool operator==(const iterator &other) { return curr.index == other.curr.index; } + bool operator!=(const iterator &other) { return curr.index != other.curr.index; } + iterator &operator++() { + if (!inst->simple_layout) + curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs; + ++curr.index; + curr.type = curr.index < types->size() ? (*types)[curr.index] : nullptr; + return *this; + } + value_and_holder &operator*() { return curr; } + value_and_holder *operator->() { return &curr; } + }; + + iterator begin() { return iterator(inst, &tinfo); } + iterator end() { return iterator(tinfo.size()); } + + iterator find(const type_info *find_type) { + auto it = begin(), endit = end(); + while (it != endit && it->type != find_type) ++it; + return it; + } + + size_t size() { return tinfo.size(); } +}; + +/** + * Extracts C++ value and holder pointer references from an instance (which may contain multiple + * values/holders for python-side multiple inheritance) that match the given type. Throws an error + * if the given type (or ValueType, if omitted) is not a pybind11 base of the given instance. If + * `find_type` is omitted (or explicitly specified as nullptr) the first value/holder are returned, + * regardless of type (and the resulting .type will be nullptr). + * + * The returned object should be short-lived: in particular, it must not outlive the called-upon + * instance. + */ +PYBIND11_NOINLINE inline value_and_holder instance::get_value_and_holder(const type_info *find_type /*= nullptr default in common.h*/, bool throw_if_missing /*= true in common.h*/) { + // Optimize common case: + if (!find_type || Py_TYPE(this) == find_type->type) + return value_and_holder(this, find_type, 0, 0); + + detail::values_and_holders vhs(this); + auto it = vhs.find(find_type); + if (it != vhs.end()) + return *it; + + if (!throw_if_missing) + return value_and_holder(); + +#if defined(NDEBUG) + pybind11_fail("pybind11::detail::instance::get_value_and_holder: " + "type is not a pybind11 base of the given instance " + "(compile in debug mode for type details)"); +#else + pybind11_fail("pybind11::detail::instance::get_value_and_holder: `" + + std::string(find_type->type->tp_name) + "' is not a pybind11 base of the given `" + + std::string(Py_TYPE(this)->tp_name) + "' instance"); +#endif +} + +PYBIND11_NOINLINE inline void instance::allocate_layout() { + auto &tinfo = all_type_info(Py_TYPE(this)); + + const size_t n_types = tinfo.size(); + + if (n_types == 0) + pybind11_fail("instance allocation failed: new instance has no pybind11-registered base types"); + + simple_layout = + n_types == 1 && tinfo.front()->holder_size_in_ptrs <= instance_simple_holder_in_ptrs(); + + // Simple path: no python-side multiple inheritance, and a small-enough holder + if (simple_layout) { + simple_value_holder[0] = nullptr; + simple_holder_constructed = false; + simple_instance_registered = false; + } + else { // multiple base types or a too-large holder + // Allocate space to hold: [v1*][h1][v2*][h2]...[bb...] where [vN*] is a value pointer, + // [hN] is the (uninitialized) holder instance for value N, and [bb...] is a set of bool + // values that tracks whether each associated holder has been initialized. Each [block] is + // padded, if necessary, to an integer multiple of sizeof(void *). + size_t space = 0; + for (auto t : tinfo) { + space += 1; // value pointer + space += t->holder_size_in_ptrs; // holder instance + } + size_t flags_at = space; + space += size_in_ptrs(n_types); // status bytes (holder_constructed and instance_registered) + + // Allocate space for flags, values, and holders, and initialize it to 0 (flags and values, + // in particular, need to be 0). Use Python's memory allocation functions: in Python 3.6 + // they default to using pymalloc, which is designed to be efficient for small allocations + // like the one we're doing here; in earlier versions (and for larger allocations) they are + // just wrappers around malloc. +#if PY_VERSION_HEX >= 0x03050000 + nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *)); + if (!nonsimple.values_and_holders) throw std::bad_alloc(); +#else + nonsimple.values_and_holders = (void **) PyMem_New(void *, space); + if (!nonsimple.values_and_holders) throw std::bad_alloc(); + std::memset(nonsimple.values_and_holders, 0, space * sizeof(void *)); +#endif + nonsimple.status = reinterpret_cast(&nonsimple.values_and_holders[flags_at]); + } + owned = true; +} + +PYBIND11_NOINLINE inline void instance::deallocate_layout() { + if (!simple_layout) + PyMem_Free(nonsimple.values_and_holders); +} + +PYBIND11_NOINLINE inline bool isinstance_generic(handle obj, const std::type_info &tp) { + handle type = detail::get_type_handle(tp, false); + if (!type) + return false; + return isinstance(obj, type); +} + +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 !defined(PYPY_VERSION) + 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; + } + } +#endif + + 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) { + for (auto vh : values_and_holders(it->second)) { + if (vh.type == type) + return handle((PyObject *) it->second); + } + } + return handle(); +} + +inline PyThreadState *get_thread_state_unchecked() { +#if defined(PYPY_VERSION) + return PyThreadState_GET(); +#elif 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 declarations +inline void keep_alive_impl(handle nurse, handle patient); +inline PyObject *make_new_instance(PyTypeObject *type); + +class type_caster_generic { +public: + PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info) + : typeinfo(get_type_info(type_info)), cpptype(&type_info) { } + + type_caster_generic(const type_info *typeinfo) + : typeinfo(typeinfo), cpptype(typeinfo ? typeinfo->cpptype : nullptr) { } + + bool load(handle src, bool convert) { + return load_impl(src, convert); + } + + PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent, + const detail::type_info *tinfo, + void *(*copy_constructor)(const void *), + void *(*move_constructor)(const void *), + const void *existing_holder = nullptr) { + if (!tinfo) // no type info: error will be set already + return handle(); + + void *src = const_cast(_src); + if (src == nullptr) + return none().release(); + + auto it_instances = get_internals().registered_instances.equal_range(src); + for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) { + for (auto instance_type : detail::all_type_info(Py_TYPE(it_i->second))) { + if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) + return handle((PyObject *) it_i->second).inc_ref(); + } + } + + auto inst = reinterpret_steal(make_new_instance(tinfo->type)); + auto wrapper = reinterpret_cast(inst.ptr()); + wrapper->owned = false; + void *&valueptr = values_and_holders(wrapper).begin()->value_ptr(); + + switch (policy) { + case return_value_policy::automatic: + case return_value_policy::take_ownership: + valueptr = src; + wrapper->owned = true; + break; + + case return_value_policy::automatic_reference: + case return_value_policy::reference: + valueptr = src; + wrapper->owned = false; + break; + + case return_value_policy::copy: + if (copy_constructor) + valueptr = 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) + valueptr = move_constructor(src); + else if (copy_constructor) + valueptr = 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: + valueptr = src; + wrapper->owned = false; + keep_alive_impl(inst, parent); + break; + + default: + throw cast_error("unhandled return_value_policy: should not happen!"); + } + + tinfo->init_instance(wrapper, existing_holder); + + return inst.release(); + } + + // Base methods for generic caster; there are overridden in copyable_holder_caster + void load_value(value_and_holder &&v_h) { + auto *&vptr = v_h.value_ptr(); + // Lazy allocation for unallocated values: + if (vptr == nullptr) { + auto *type = v_h.type ? v_h.type : typeinfo; + if (type->operator_new) { + vptr = type->operator_new(type->type_size); + } else { + #if defined(PYBIND11_CPP17) + if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + vptr = ::operator new(type->type_size, + (std::align_val_t) type->type_align); + else + #endif + vptr = ::operator new(type->type_size); + } + } + value = vptr; + } + bool try_implicit_casts(handle src, bool convert) { + 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; + } + } + return false; + } + bool try_direct_conversions(handle src) { + for (auto &converter : *typeinfo->direct_conversions) { + if (converter(src.ptr(), value)) + return true; + } + return false; + } + void check_holder_compat() {} + + PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) { + auto caster = type_caster_generic(ti); + if (caster.load(src, false)) + return caster.value; + return nullptr; + } + + /// Try to load with foreign typeinfo, if available. Used when there is no + /// native typeinfo, or when the native one wasn't able to produce a value. + PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) { + constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID; + const auto pytype = src.get_type(); + if (!hasattr(pytype, local_key)) + return false; + + type_info *foreign_typeinfo = reinterpret_borrow(getattr(pytype, local_key)); + // Only consider this foreign loader if actually foreign and is a loader of the correct cpp type + if (foreign_typeinfo->module_local_load == &local_load + || (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype))) + return false; + + if (auto result = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo)) { + value = result; + return true; + } + return false; + } + + // Implementation of `load`; this takes the type of `this` so that it can dispatch the relevant + // bits of code between here and copyable_holder_caster where the two classes need different + // logic (without having to resort to virtual inheritance). + template + PYBIND11_NOINLINE bool load_impl(handle src, bool convert) { + if (!src) return false; + if (!typeinfo) return try_load_foreign_module_local(src); + if (src.is_none()) { + // Defer accepting None to other overloads (if we aren't in convert mode): + if (!convert) return false; + value = nullptr; + return true; + } + + auto &this_ = static_cast(*this); + this_.check_holder_compat(); + + PyTypeObject *srctype = Py_TYPE(src.ptr()); + + // Case 1: If src is an exact type match for the target type then we can reinterpret_cast + // the instance's value pointer to the target type: + if (srctype == typeinfo->type) { + this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder()); + return true; + } + // Case 2: We have a derived class + else if (PyType_IsSubtype(srctype, typeinfo->type)) { + auto &bases = all_type_info(srctype); + bool no_cpp_mi = typeinfo->simple_type; + + // Case 2a: the python type is a Python-inherited derived class that inherits from just + // one simple (no MI) pybind11 class, or is an exact match, so the C++ instance is of + // the right type and we can use reinterpret_cast. + // (This is essentially the same as case 2b, but because not using multiple inheritance + // is extremely common, we handle it specially to avoid the loop iterator and type + // pointer lookup overhead) + if (bases.size() == 1 && (no_cpp_mi || bases.front()->type == typeinfo->type)) { + this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder()); + return true; + } + // Case 2b: the python type inherits from multiple C++ bases. Check the bases to see if + // we can find an exact match (or, for a simple C++ type, an inherited match); if so, we + // can safely reinterpret_cast to the relevant pointer. + else if (bases.size() > 1) { + for (auto base : bases) { + if (no_cpp_mi ? PyType_IsSubtype(base->type, typeinfo->type) : base->type == typeinfo->type) { + this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder(base)); + return true; + } + } + } + + // Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type match + // in the registered bases, above, so try implicit casting (needed for proper C++ casting + // when MI is involved). + if (this_.try_implicit_casts(src, convert)) + return true; + } + + // Perform an implicit conversion + if (convert) { + for (auto &converter : typeinfo->implicit_conversions) { + auto temp = reinterpret_steal(converter(src.ptr(), typeinfo->type)); + if (load_impl(temp, false)) { + loader_life_support::add_patient(temp); + return true; + } + } + if (this_.try_direct_conversions(src)) + return true; + } + + // Failed to match local typeinfo. Try again with global. + if (typeinfo->module_local) { + if (auto gtype = get_global_type_info(*typeinfo->cpptype)) { + typeinfo = gtype; + return load(src, false); + } + } + + // Global typeinfo has precedence over foreign module_local + return try_load_foreign_module_local(src); + } + + + // Called to do type lookup and wrap the pointer and type in a pair when a dynamic_cast + // isn't needed or can't be used. If the type is unknown, sets the error and returns a pair + // with .second = nullptr. (p.first = nullptr is not an error: it becomes None). + PYBIND11_NOINLINE static std::pair src_and_type( + const void *src, const std::type_info &cast_type, const std::type_info *rtti_type = nullptr) { + if (auto *tpi = get_type_info(cast_type)) + return {src, const_cast(tpi)}; + + // Not found, set error: + std::string tname = rtti_type ? rtti_type->name() : cast_type.name(); + detail::clean_type_id(tname); + std::string msg = "Unregistered type : " + tname; + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return {nullptr, nullptr}; + } + + const type_info *typeinfo = nullptr; + const std::type_info *cpptype = nullptr; + void *value = nullptr; +}; + +/** + * Determine suitable casting operator for pointer-or-lvalue-casting type casters. The type caster + * needs to provide `operator T*()` and `operator T&()` operators. + * + * If the type supports moving the value away via an `operator T&&() &&` method, it should use + * `movable_cast_op_type` instead. + */ +template +using cast_op_type = + conditional_t>::value, + typename std::add_pointer>::type, + typename std::add_lvalue_reference>::type>; + +/** + * Determine suitable casting operator for a type caster with a movable value. Such a type caster + * needs to provide `operator T*()`, `operator T&()`, and `operator T&&() &&`. The latter will be + * called in appropriate contexts where the value can be moved rather than copied. + * + * These operator are automatically provided when using the PYBIND11_TYPE_CASTER macro. + */ +template +using movable_cast_op_type = + conditional_t::type>::value, + typename std::add_pointer>::type, + conditional_t::value, + typename std::add_rvalue_reference>::type, + typename std::add_lvalue_reference>::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, + std::is_same + >::value>> : is_copy_constructible {}; + +#if !defined(PYBIND11_CPP17) +// Likewise for std::pair before C++17 (which mandates that the copy constructor not exist when the +// two types aren't themselves copy constructible). +template struct is_copy_constructible> + : all_of, is_copy_constructible> {}; +#endif + +NAMESPACE_END(detail) + +// polymorphic_type_hook::get(src, tinfo) determines whether the object pointed +// to by `src` actually is an instance of some class derived from `itype`. +// If so, it sets `tinfo` to point to the std::type_info representing that derived +// type, and returns a pointer to the start of the most-derived object of that type +// (in which `src` is a subobject; this will be the same address as `src` in most +// single inheritance cases). If not, or if `src` is nullptr, it simply returns `src` +// and leaves `tinfo` at its default value of nullptr. +// +// The default polymorphic_type_hook just returns src. A specialization for polymorphic +// types determines the runtime type of the passed object and adjusts the this-pointer +// appropriately via dynamic_cast. This is what enables a C++ Animal* to appear +// to Python as a Dog (if Dog inherits from Animal, Animal is polymorphic, Dog is +// registered with pybind11, and this Animal is in fact a Dog). +// +// You may specialize polymorphic_type_hook yourself for types that want to appear +// polymorphic to Python but do not use C++ RTTI. (This is a not uncommon pattern +// in performance-sensitive applications, used most notably in LLVM.) +template +struct polymorphic_type_hook +{ + static const void *get(const itype *src, const std::type_info*&) { return src; } +}; +template +struct polymorphic_type_hook::value>> +{ + static const void *get(const itype *src, const std::type_info*& type) { + type = src ? &typeid(*src) : nullptr; + return dynamic_cast(src); + } +}; + +NAMESPACE_BEGIN(detail) + +/// Generic type caster for objects stored on the heap +template class type_caster_base : public type_caster_generic { + using itype = intrinsic_t; + +public: + static constexpr auto name = _(); + + 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); + } + + // Returns a (pointer, type_info) pair taking care of necessary type lookup for a + // polymorphic type (using RTTI by default, but can be overridden by specializing + // polymorphic_type_hook). If the instance isn't derived, returns the base version. + static std::pair src_and_type(const itype *src) { + auto &cast_type = typeid(itype); + const std::type_info *instance_type = nullptr; + const void *vsrc = polymorphic_type_hook::get(src, instance_type); + if (instance_type && !same_type(cast_type, *instance_type)) { + // This is a base pointer to a derived type. If the derived type is registered + // with pybind11, we want to make the full derived object available. + // In the typical case where itype is polymorphic, we get the correct + // derived pointer (which may be != base pointer) by a dynamic_cast to + // most derived type. If itype is not polymorphic, we won't get here + // except via a user-provided specialization of polymorphic_type_hook, + // and the user has promised that no this-pointer adjustment is + // required in that case, so it's OK to use static_cast. + if (const auto *tpi = get_type_info(*instance_type)) + return {vsrc, tpi}; + } + // Otherwise we have either a nullptr, an `itype` pointer, or an unknown derived pointer, so + // don't do a cast + return type_caster_generic::src_and_type(src, cast_type, instance_type); + } + + static handle cast(const itype *src, return_value_policy policy, handle parent) { + auto st = src_and_type(src); + return type_caster_generic::cast( + st.first, policy, parent, st.second, + make_copy_constructor(src), make_move_constructor(src)); + } + + static handle cast_holder(const itype *src, const void *holder) { + auto st = src_and_type(src); + return type_caster_generic::cast( + st.first, return_value_policy::take_ownership, {}, st.second, + nullptr, nullptr, holder); + } + + template using cast_op_type = detail::cast_op_type; + + operator itype*() { return (type *) value; } + operator itype&() { if (!value) throw reference_cast_error(); return *((itype *) value); } + +protected: + using Constructor = void *(*)(const void *); + + /* Only enabled when the types are {copy,move}-constructible *and* when the type + does not have a private operator new implementation. */ + template ::value>> + static auto make_copy_constructor(const T *x) -> decltype(new T(*x), Constructor{}) { + return [](const void *arg) -> void * { + return new T(*reinterpret_cast(arg)); + }; + } + + template ::value>> + static auto make_move_constructor(const T *x) -> decltype(new T(std::move(*const_cast(x))), Constructor{}) { + return [](const void *arg) -> void * { + return new T(std::move(*const_cast(reinterpret_cast(arg)))); + }; + } + + 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::type> +cast_op(make_caster &&caster) { + return std::move(caster).operator + typename make_caster::template cast_op_type::type>(); +} + +template class type_caster> { +private: + using caster_t = make_caster; + caster_t subcaster; + using subcaster_cast_op_type = typename caster_t::template cast_op_type; + static_assert(std::is_same::type &, subcaster_cast_op_type>::value, + "std::reference_wrapper caster requires T to have a caster with an `T &` operator"); +public: + bool load(handle src, bool convert) { return subcaster.load(src, convert); } + static constexpr auto name = caster_t::name; + static handle cast(const std::reference_wrapper &src, return_value_policy policy, handle parent) { + // It is definitely wrong to take ownership of this pointer, so mask that rvp + if (policy == return_value_policy::take_ownership || policy == return_value_policy::automatic) + policy = return_value_policy::automatic_reference; + return caster_t::cast(&src.get(), policy, parent); + } + template using cast_op_type = std::reference_wrapper; + operator std::reference_wrapper() { return subcaster.operator subcaster_cast_op_type&(); } +}; + +#define PYBIND11_TYPE_CASTER(type, py_name) \ + protected: \ + type value; \ + public: \ + static constexpr auto name = py_name; \ + template >::value, int> = 0> \ + static handle cast(T_ *src, return_value_policy policy, handle parent) { \ + if (!src) return none().release(); \ + if (policy == return_value_policy::take_ownership) { \ + auto h = cast(std::move(*src), policy, parent); delete src; return h; \ + } else { \ + return cast(*src, policy, parent); \ + } \ + } \ + operator type*() { return &value; } \ + operator type&() { return value; } \ + operator type&&() && { return std::move(value); } \ + template using cast_op_type = pybind11::detail::movable_cast_op_type + + +template using is_std_char_type = any_of< + std::is_same, /* std::string */ + std::is_same, /* std::u16string */ + std::is_same, /* std::u32string */ + std::is_same /* std::wstring */ +>; + +template +struct type_caster::value && !is_std_char_type::value>> { + using _py_type_0 = conditional_t; + using _py_type_1 = conditional_t::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>; + using py_type = conditional_t::value, double, _py_type_1>; +public: + + bool load(handle src, bool convert) { + py_type py_value; + + if (!src) + return false; + + if (std::is_floating_point::value) { + if (convert || PyFloat_Check(src.ptr())) + py_value = (py_type) PyFloat_AsDouble(src.ptr()); + else + return false; + } else if (PyFloat_Check(src.ptr())) { + return false; + } else if (std::is_unsigned::value) { + py_value = as_unsigned(src.ptr()); + } else { // signed integer: + py_value = sizeof(T) <= sizeof(long) + ? (py_type) PyLong_AsLong(src.ptr()) + : (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr()); + } + + bool py_err = py_value == (py_type) -1 && PyErr_Occurred(); + if (py_err || (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()))) { + bool type_error = py_err && PyErr_ExceptionMatches( +#if PY_VERSION_HEX < 0x03000000 && !defined(PYPY_VERSION) + PyExc_SystemError +#else + PyExc_TypeError +#endif + ); + PyErr_Clear(); + if (type_error && convert && PyNumber_Check(src.ptr())) { + auto tmp = reinterpret_steal(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; + } + + template + static typename std::enable_if::value, handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyFloat_FromDouble((double) src); + } + + template + static typename std::enable_if::value && std::is_signed::value && (sizeof(U) <= sizeof(long)), handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PYBIND11_LONG_FROM_SIGNED((long) src); + } + + template + static typename std::enable_if::value && std::is_unsigned::value && (sizeof(U) <= sizeof(unsigned long)), handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PYBIND11_LONG_FROM_UNSIGNED((unsigned long) src); + } + + template + static typename std::enable_if::value && std::is_signed::value && (sizeof(U) > sizeof(long)), handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyLong_FromLongLong((long long) src); + } + + template + static typename std::enable_if::value && std::is_unsigned::value && (sizeof(U) > sizeof(unsigned long)), handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyLong_FromUnsignedLongLong((unsigned long long) src); + } + + PYBIND11_TYPE_CASTER(T, _::value>("int", "float")); +}; + +template struct void_caster { +public: + bool load(handle src, bool) { + if (src && src.is_none()) + return true; + 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 */ + auto &bases = all_type_info((PyTypeObject *) h.get_type().ptr()); + if (bases.size() == 1) { // Only allowing loading from a single-value type + value = values_and_holders(reinterpret_cast(h.ptr())).begin()->value_ptr(); + 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 constexpr auto name = _("capsule"); +private: + void *value = nullptr; +}; + +template <> class type_caster : public void_caster { }; + +template <> class type_caster { +public: + bool load(handle src, bool convert) { + 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 if (convert || !strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name)) { + // (allow non-implicit conversion for numpy booleans) + + Py_ssize_t res = -1; + if (src.is_none()) { + res = 0; // None is implicitly converted to False + } + #if defined(PYPY_VERSION) + // On PyPy, check that "__bool__" (or "__nonzero__" on Python 2.7) attr exists + else if (hasattr(src, PYBIND11_BOOL_ATTR)) { + res = PyObject_IsTrue(src.ptr()); + } + #else + // Alternate approach for CPython: this does the same as the above, but optimized + // using the CPython API so as to avoid an unneeded attribute lookup. + else if (auto tp_as_number = src.ptr()->ob_type->tp_as_number) { + if (PYBIND11_NB_BOOL(tp_as_number)) { + res = (*PYBIND11_NB_BOOL(tp_as_number))(src.ptr()); + } + } + #endif + if (res == 0 || res == 1) { + value = (bool) res; + return true; + } + } + 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")); +}; + +// Helper class for UTF-{8,16,32} C++ stl strings: +template struct string_caster { + using CharT = typename StringType::value_type; + + // Simplify life by being able to assume standard char sizes (the standard only guarantees + // minimums, but Python requires exact sizes) + static_assert(!std::is_same::value || sizeof(CharT) == 1, "Unsupported char size != 1"); + static_assert(!std::is_same::value || sizeof(CharT) == 2, "Unsupported char16_t size != 2"); + static_assert(!std::is_same::value || sizeof(CharT) == 4, "Unsupported char32_t size != 4"); + // wchar_t can be either 16 bits (Windows) or 32 (everywhere else) + static_assert(!std::is_same::value || sizeof(CharT) == 2 || sizeof(CharT) == 4, + "Unsupported wchar_t size != 2/4"); + static constexpr size_t UTF_N = 8 * sizeof(CharT); + + bool load(handle src, bool) { +#if PY_MAJOR_VERSION < 3 + object temp; +#endif + handle load_src = src; + if (!src) { + return false; + } else if (!PyUnicode_Check(load_src.ptr())) { +#if PY_MAJOR_VERSION >= 3 + return load_bytes(load_src); +#else + if (sizeof(CharT) == 1) { + return load_bytes(load_src); + } + + // The below is a guaranteed failure in Python 3 when PyUnicode_Check returns false + if (!PYBIND11_BYTES_CHECK(load_src.ptr())) + return false; + + temp = reinterpret_steal(PyUnicode_FromObject(load_src.ptr())); + if (!temp) { PyErr_Clear(); return false; } + load_src = temp; +#endif + } + + object utfNbytes = reinterpret_steal(PyUnicode_AsEncodedString( + load_src.ptr(), UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr)); + if (!utfNbytes) { PyErr_Clear(); return false; } + + const CharT *buffer = reinterpret_cast(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr())); + size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT); + if (UTF_N > 8) { buffer++; length--; } // Skip BOM for UTF-16/32 + value = StringType(buffer, length); + + // If we're loading a string_view we need to keep the encoded Python object alive: + if (IsView) + loader_life_support::add_patient(utfNbytes); + + return true; + } + + static handle cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) { + const char *buffer = reinterpret_cast(src.data()); + ssize_t nbytes = ssize_t(src.size() * sizeof(CharT)); + handle s = decode_utfN(buffer, nbytes); + if (!s) throw error_already_set(); + return s; + } + + PYBIND11_TYPE_CASTER(StringType, _(PYBIND11_STRING_NAME)); + +private: + static handle decode_utfN(const char *buffer, ssize_t nbytes) { +#if !defined(PYPY_VERSION) + return + UTF_N == 8 ? PyUnicode_DecodeUTF8(buffer, nbytes, nullptr) : + UTF_N == 16 ? PyUnicode_DecodeUTF16(buffer, nbytes, nullptr, nullptr) : + PyUnicode_DecodeUTF32(buffer, nbytes, nullptr, nullptr); +#else + // PyPy seems to have multiple problems related to PyUnicode_UTF*: the UTF8 version + // sometimes segfaults for unknown reasons, while the UTF16 and 32 versions require a + // non-const char * arguments, which is also a nuisance, so bypass the whole thing by just + // passing the encoding as a string value, which works properly: + return PyUnicode_Decode(buffer, nbytes, UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr); +#endif + } + + // When loading into a std::string or char*, accept a bytes object as-is (i.e. + // without any encoding/decoding attempt). For other C++ char sizes this is a no-op. + // which supports loading a unicode from a str, doesn't take this path. + template + bool load_bytes(enable_if_t src) { + if (PYBIND11_BYTES_CHECK(src.ptr())) { + // We were passed a Python 3 raw bytes; accept it into a std::string or char* + // without any encoding attempt. + const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr()); + if (bytes) { + value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr())); + return true; + } + } + + return false; + } + + template + bool load_bytes(enable_if_t) { return false; } +}; + +template +struct type_caster, enable_if_t::value>> + : string_caster> {}; + +#ifdef PYBIND11_HAS_STRING_VIEW +template +struct type_caster, enable_if_t::value>> + : string_caster, true> {}; +#endif + +// Type caster for C-style strings. We basically use a std::string type caster, but also add the +// ability to use None as a nullptr char* (which the string caster doesn't allow). +template struct type_caster::value>> { + using StringType = std::basic_string; + using StringCaster = type_caster; + StringCaster str_caster; + bool none = false; + CharT one_char = 0; +public: + bool load(handle src, bool convert) { + if (!src) return false; + if (src.is_none()) { + // Defer accepting None to other overloads (if we aren't in convert mode): + if (!convert) return false; + none = true; + return true; + } + return str_caster.load(src, convert); + } + + static handle cast(const CharT *src, return_value_policy policy, handle parent) { + if (src == nullptr) return pybind11::none().inc_ref(); + return StringCaster::cast(StringType(src), policy, parent); + } + + static handle cast(CharT src, return_value_policy policy, handle parent) { + if (std::is_same::value) { + handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr); + if (!s) throw error_already_set(); + return s; + } + return StringCaster::cast(StringType(1, src), policy, parent); + } + + operator CharT*() { return none ? nullptr : const_cast(static_cast(str_caster).c_str()); } + operator CharT&() { + if (none) + throw value_error("Cannot convert None to a character"); + + auto &value = static_cast(str_caster); + size_t str_len = value.size(); + if (str_len == 0) + throw value_error("Cannot convert empty string to a character"); + + // If we're in UTF-8 mode, we have two possible failures: one for a unicode character that + // is too high, and one for multiple unicode characters (caught later), so we need to figure + // out how long the first encoded character is in bytes to distinguish between these two + // errors. We also allow want to allow unicode characters U+0080 through U+00FF, as those + // can fit into a single char value. + if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) { + unsigned char v0 = static_cast(value[0]); + size_t char0_bytes = !(v0 & 0x80) ? 1 : // low bits only: 0-127 + (v0 & 0xE0) == 0xC0 ? 2 : // 0b110xxxxx - start of 2-byte sequence + (v0 & 0xF0) == 0xE0 ? 3 : // 0b1110xxxx - start of 3-byte sequence + 4; // 0b11110xxx - start of 4-byte sequence + + if (char0_bytes == str_len) { + // If we have a 128-255 value, we can decode it into a single char: + if (char0_bytes == 2 && (v0 & 0xFC) == 0xC0) { // 0x110000xx 0x10xxxxxx + one_char = static_cast(((v0 & 3) << 6) + (static_cast(value[1]) & 0x3F)); + return one_char; + } + // Otherwise we have a single character, but it's > U+00FF + throw value_error("Character code point not in range(0x100)"); + } + } + + // UTF-16 is much easier: we can only have a surrogate pair for values above U+FFFF, thus a + // surrogate pair with total length 2 instantly indicates a range error (but not a "your + // string was too long" error). + else if (StringCaster::UTF_N == 16 && str_len == 2) { + one_char = static_cast(value[0]); + if (one_char >= 0xD800 && one_char < 0xE000) + throw value_error("Character code point not in range(0x10000)"); + } + + if (str_len != 1) + throw value_error("Expected a character, but multi-character string found"); + + one_char = value[0]; + return one_char; + } + + static constexpr auto name = _(PYBIND11_STRING_NAME); + template using cast_op_type = pybind11::detail::cast_op_type<_T>; +}; + +// Base implementation for std::tuple and std::pair +template class Tuple, typename... Ts> class tuple_caster { + using type = Tuple; + static constexpr auto size = sizeof...(Ts); + using indices = make_index_sequence; +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{}); + } + + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + return cast_impl(std::forward(src), policy, parent, indices{}); + } + + static constexpr auto name = _("Tuple[") + concat(make_caster::name...) + _("]"); + + template using cast_op_type = type; + + operator type() & { return implicit_cast(indices{}); } + operator type() && { return std::move(*this).implicit_cast(indices{}); } + +protected: + template + type implicit_cast(index_sequence) & { return type(cast_op(std::get(subcasters))...); } + template + type implicit_cast(index_sequence) && { return type(cast_op(std::move(std::get(subcasters)))...); } + + 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(subcasters).load(seq[Is], convert)...}) + if (!r) + return false; + return true; + } + + /* Implementation: Convert a C++ tuple into a Python tuple */ + template + static handle cast_impl(T &&src, return_value_policy policy, handle parent, index_sequence) { + std::array entries{{ + reinterpret_steal(make_caster::cast(std::get(std::forward(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(); + } + + Tuple...> subcasters; +}; + +template class type_caster> + : public tuple_caster {}; + +template class type_caster> + : public tuple_caster {}; + +/// Helper class which abstracts away certain actions. Users can provide specializations for +/// custom holders, but it's only necessary if the type has a non-standard interface. +template +struct holder_helper { + static auto get(const T &p) -> decltype(p.get()) { return p.get(); } +}; + +/// Type caster for holder types like std::shared_ptr, etc. +template +struct copyable_holder_caster : public type_caster_base { +public: + using base = type_caster_base; + static_assert(std::is_base_of>::value, + "Holder classes are only supported for custom types"); + using base::base; + using base::cast; + using base::typeinfo; + using base::value; + + bool load(handle src, bool convert) { + return base::template load_impl>(src, convert); + } + + explicit operator type*() { return this->value; } + explicit operator type&() { return *(this->value); } + explicit operator holder_type*() { return std::addressof(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) { + const auto *ptr = holder_helper::get(src); + return type_caster_base::cast_holder(ptr, &src); + } + +protected: + friend class type_caster_generic; + void check_holder_compat() { + if (typeinfo->default_holder) + throw cast_error("Unable to load a custom holder type from a default-holder instance"); + } + + bool load_value(value_and_holder &&v_h) { + if (v_h.holder_constructed()) { + value = v_h.value_ptr(); + holder = v_h.template 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) { + copyable_holder_caster 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; + } + + static bool try_direct_conversions(handle) { return false; } + + + holder_type holder; +}; + +/// Specialize for the common std::shared_ptr, so users don't need to +template +class type_caster> : public copyable_holder_caster> { }; + +template +struct move_only_holder_caster { + static_assert(std::is_base_of, type_caster>::value, + "Holder classes are only supported for custom types"); + + static handle cast(holder_type &&src, return_value_policy, handle) { + auto *ptr = holder_helper::get(src); + return type_caster_base::cast_holder(ptr, std::addressof(src)); + } + static constexpr auto name = type_caster_base::name; +}; + +template +class type_caster> + : public move_only_holder_caster> { }; + +template +using type_caster_holder = conditional_t::value, + copyable_holder_caster, + move_only_holder_caster>; + +template struct always_construct_holder { static constexpr bool value = Value; }; + +/// 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 \ + struct always_construct_holder : always_construct_holder { }; \ + 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 constexpr auto name = _(); }; +template <> struct handle_type_name { static constexpr auto name = _(PYBIND11_BYTES_NAME); }; +template <> struct handle_type_name { static constexpr auto name = _("*args"); }; +template <> struct handle_type_name { static constexpr auto name = _("**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 using move_is_plain_type = satisfies_none_of; +template struct move_always : std::false_type {}; +template struct move_always, + negation>, + std::is_move_constructible, + std::is_same>().operator T&()), T&> +>::value>> : std::true_type {}; +template struct move_if_unreferenced : std::false_type {}; +template struct move_if_unreferenced, + negation>, + std::is_move_constructible, + std::is_same>().operator T&()), T&> +>::value>> : std::true_type {}; +template using move_never = none_of, move_if_unreferenced>; + +// 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 && + !std::is_same, void>::value +>; + +// When a value returned from a C++ function is being cast back to Python, we almost always want to +// force `policy = move`, regardless of the return value policy the function/method was declared +// with. +template struct return_value_policy_override { + static return_value_policy policy(return_value_policy p) { return p; } +}; + +template struct return_value_policy_override>::value, void>> { + static return_value_policy policy(return_value_policy p) { + return !std::is_lvalue_reference::value && + !std::is_pointer::value + ? return_value_policy::move : p; + } +}; + +// 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, 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) + +// Declared in pytypes.h: +template ::value, int>> +object object_or_cast(T &&o) { return pybind11::cast(std::forward(o)); } + +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() { return tuple(0); } + +template tuple make_tuple(Args&&... args_) { + constexpr size_t size = sizeof...(Args); + std::array args { + { reinterpret_steal(detail::make_caster::cast( + std::forward(args_), policy, nullptr))... } + }; + for (size_t i = 0; i < args.size(); i++) { + if (!args[i]) { +#if defined(NDEBUG) + throw cast_error("make_tuple(): unable to convert arguments to Python object (compile in debug mode for details)"); +#else + std::array argtypes { {type_id()...} }; + throw cast_error("make_tuple(): unable to convert argument of type '" + + argtypes[i] + "' 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; +} + +/// \ingroup annotations +/// Annotation for arguments +struct arg { + /// Constructs an argument with the name of the argument; if null or omitted, this is a positional argument. + constexpr explicit arg(const char *name = nullptr) : name(name), flag_noconvert(false), flag_none(true) { } + /// Assign a value to this argument + template arg_v operator=(T &&value) const; + /// Indicate that the type should not be converted in the type caster + arg &noconvert(bool flag = true) { flag_noconvert = flag; return *this; } + /// Indicates that the argument should/shouldn't allow None (e.g. for nullable pointer args) + arg &none(bool flag = true) { flag_none = flag; return *this; } + + const char *name; ///< If non-null, this is a named kwargs argument + bool flag_noconvert : 1; ///< If set, do not allow conversion (requires a supporting type caster!) + bool flag_none : 1; ///< If set (the default), allow None to be passed to this argument +}; + +/// \ingroup annotations +/// Annotation for arguments with values +struct arg_v : arg { +private: + template + arg_v(arg &&base, T &&x, const char *descr = nullptr) + : arg(base), + value(reinterpret_steal( + detail::make_caster::cast(x, return_value_policy::automatic, {}) + )), + descr(descr) +#if !defined(NDEBUG) + , type(type_id()) +#endif + { } + +public: + /// Direct construction with name, default, and description + template + arg_v(const char *name, T &&x, const char *descr = nullptr) + : arg_v(arg(name), std::forward(x), descr) { } + + /// Called internally when invoking `py::arg("a") = value` + template + arg_v(const arg &base, T &&x, const char *descr = nullptr) + : arg_v(arg(base), std::forward(x), descr) { } + + /// Same as `arg::noconvert()`, but returns *this as arg_v&, not arg& + arg_v &noconvert(bool flag = true) { arg::noconvert(flag); return *this; } + + /// Same as `arg::nonone()`, but returns *this as arg_v&, not arg& + arg_v &none(bool flag = true) { arg::none(flag); return *this; } + + /// The default value + object value; + /// The (optional) description of the default value + const char *descr; +#if !defined(NDEBUG) + /// The C++ type name of the default value (only available when compiled in debug mode) + std::string type; +#endif +}; + +template +arg_v arg::operator=(T &&value) const { return {std::move(*this), std::forward(value)}; } + +/// Alias for backward compatibility -- to be removed in version 2.0 +template using arg_t = arg_v; + +inline namespace literals { +/** \rst + String literal version of `arg` + \endrst */ +constexpr arg operator"" _a(const char *name, size_t) { return arg(name); } +} + +NAMESPACE_BEGIN(detail) + +// forward declaration (definition in attr.h) +struct function_record; + +/// Internal data associated with a single function call +struct function_call { + function_call(const function_record &f, handle p); // Implementation in attr.h + + /// The function data: + const function_record &func; + + /// Arguments passed to the function: + std::vector args; + + /// The `convert` value the arguments should be loaded with + std::vector args_convert; + + /// Extra references for the optional `py::args` and/or `py::kwargs` arguments (which, if + /// present, are also in `args` but without a reference). + object args_ref, kwargs_ref; + + /// The parent, if any + handle parent; + + /// If this is a call to an initializer, this argument contains `self` + handle init_self; +}; + + +/// Helper class which loads arguments for C++ functions called from Python +template +class argument_loader { + using indices = make_index_sequence; + + template using argument_is_args = std::is_same, args>; + template using argument_is_kwargs = std::is_same, kwargs>; + // Get args/kwargs argument positions relative to the end of the argument list: + static constexpr auto args_pos = constexpr_first() - (int) sizeof...(Args), + kwargs_pos = constexpr_first() - (int) sizeof...(Args); + + static constexpr bool args_kwargs_are_last = kwargs_pos >= - 1 && args_pos >= kwargs_pos - 1; + + static_assert(args_kwargs_are_last, "py::args/py::kwargs are only permitted as the last argument(s) of a function"); + +public: + static constexpr bool has_kwargs = kwargs_pos < 0; + static constexpr bool has_args = args_pos < 0; + + static constexpr auto arg_names = concat(type_descr(make_caster::name)...); + + bool load_args(function_call &call) { + return load_impl_sequence(call, indices{}); + } + + template + enable_if_t::value, Return> call(Func &&f) && { + return std::move(*this).template call_impl(std::forward(f), indices{}, Guard{}); + } + + template + enable_if_t::value, void_type> call(Func &&f) && { + std::move(*this).template call_impl(std::forward(f), indices{}, Guard{}); + return void_type(); + } + +private: + + static bool load_impl_sequence(function_call &, index_sequence<>) { return true; } + + template + bool load_impl_sequence(function_call &call, index_sequence) { + for (bool r : {std::get(argcasters).load(call.args[Is], call.args_convert[Is])...}) + if (!r) + return false; + return true; + } + + template + Return call_impl(Func &&f, index_sequence, Guard &&) { + return std::forward(f)(cast_op(std::move(std::get(argcasters)))...); + } + + std::tuple...> argcasters; +}; + +/// 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 (!a.name) +#if defined(NDEBUG) + nameless_argument_error(); +#else + nameless_argument_error(a.type); +#endif + + 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 nameless_argument_error() { + throw type_error("Got kwargs without a name; only named arguments " + "may be passed via py::arg() to a python function call. " + "(compile in debug mode for details)"); + } + [[noreturn]] static void nameless_argument_error(std::string type) { + throw type_error("Got kwargs without a name of type '" + type + "'; only named " + "arguments may be passed via py::arg() to a python function call. "); + } + [[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(...) \ + namespace pybind11 { namespace detail { \ + template<> class type_caster<__VA_ARGS__> : public type_caster_base<__VA_ARGS__> { }; \ + }} + +/// Lets you pass a type containing a `,` through a macro parameter without needing a separate +/// typedef, e.g.: `PYBIND11_OVERLOAD(PYBIND11_TYPE(ReturnType), PYBIND11_TYPE(Parent), f, arg)` +#define PYBIND11_TYPE(...) __VA_ARGS__ + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/pybind11/include/pybind11/chrono.h b/pybind11/include/pybind11/chrono.h new file mode 100644 index 0000000..95ada76 --- /dev/null +++ b/pybind11/include/pybind11/chrono.h @@ -0,0 +1,162 @@ +/* + 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) +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; + + auto dd = duration_cast(d); + auto subd = d - dd; + auto ss = duration_cast(subd); + auto us = duration_cast(subd - ss); + return PyDelta_FromDSU(dd.count(), ss.count(), us.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_NAMESPACE) diff --git a/pybind11/include/pybind11/common.h b/pybind11/include/pybind11/common.h new file mode 100644 index 0000000..6c8a4f1 --- /dev/null +++ b/pybind11/include/pybind11/common.h @@ -0,0 +1,2 @@ +#include "detail/common.h" +#warning "Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'." diff --git a/pybind11/include/pybind11/complex.h b/pybind11/include/pybind11/complex.h new file mode 100644 index 0000000..3f89638 --- /dev/null +++ b/pybind11/include/pybind11/complex.h @@ -0,0 +1,65 @@ +/* + 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_NAMESPACE) + +template struct format_descriptor, detail::enable_if_t::value>> { + static constexpr const char c = format_descriptor::c; + static constexpr const char value[3] = { 'Z', c, '\0' }; + static std::string format() { return std::string(value); } +}; + +#ifndef PYBIND11_CPP17 + +template constexpr const char format_descriptor< + std::complex, detail::enable_if_t::value>>::value[3]; + +#endif + +NAMESPACE_BEGIN(detail) + +template struct is_fmt_numeric, detail::enable_if_t::value>> { + static constexpr bool value = true; + static constexpr int index = is_fmt_numeric::index + 3; +}; + +template class type_caster> { +public: + bool load(handle src, bool convert) { + if (!src) + return false; + if (!convert && !PyComplex_Check(src.ptr())) + 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_NAMESPACE) diff --git a/pybind11/include/pybind11/detail/class.h b/pybind11/include/pybind11/detail/class.h new file mode 100644 index 0000000..7a5dd01 --- /dev/null +++ b/pybind11/include/pybind11/detail/class.h @@ -0,0 +1,622 @@ +/* + pybind11/detail/class.h: Python C API implementation details for py::class_ + + Copyright (c) 2017 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 "../attr.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +#if PY_VERSION_HEX >= 0x03030000 +# define PYBIND11_BUILTIN_QUALNAME +# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) +#else +// In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type +// signatures; in 3.3+ this macro expands to nothing: +# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) setattr((PyObject *) obj, "__qualname__", nameobj) +#endif + +inline PyTypeObject *type_incref(PyTypeObject *type) { + Py_INCREF(type); + return type; +} + +#if !defined(PYPY_VERSION) + +/// `pybind11_static_property.__get__()`: Always pass the class instead of the instance. +extern "C" inline PyObject *pybind11_static_get(PyObject *self, PyObject * /*ob*/, PyObject *cls) { + return PyProperty_Type.tp_descr_get(self, cls, cls); +} + +/// `pybind11_static_property.__set__()`: Just like the above `__get__()`. +extern "C" inline int pybind11_static_set(PyObject *self, PyObject *obj, PyObject *value) { + PyObject *cls = PyType_Check(obj) ? obj : (PyObject *) Py_TYPE(obj); + return PyProperty_Type.tp_descr_set(self, cls, value); +} + +/** A `static_property` is the same as a `property` but the `__get__()` and `__set__()` + methods are modified to always use the object type instead of a concrete instance. + Return value: New reference. */ +inline PyTypeObject *make_static_property_type() { + constexpr auto *name = "pybind11_static_property"; + auto name_obj = reinterpret_steal(PYBIND11_FROM_STRING(name)); + + /* 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 heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0); + if (!heap_type) + pybind11_fail("make_static_property_type(): error allocating type!"); + + heap_type->ht_name = name_obj.inc_ref().ptr(); +#ifdef PYBIND11_BUILTIN_QUALNAME + heap_type->ht_qualname = name_obj.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = name; + type->tp_base = type_incref(&PyProperty_Type); + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; + type->tp_descr_get = pybind11_static_get; + type->tp_descr_set = pybind11_static_set; + + if (PyType_Ready(type) < 0) + pybind11_fail("make_static_property_type(): failure in PyType_Ready()!"); + + setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); + + return type; +} + +#else // PYPY + +/** PyPy has some issues with the above C API, so we evaluate Python code instead. + This function will only be called once so performance isn't really a concern. + Return value: New reference. */ +inline PyTypeObject *make_static_property_type() { + auto d = dict(); + PyObject *result = PyRun_String(R"(\ + class pybind11_static_property(property): + def __get__(self, obj, cls): + return property.__get__(self, cls, cls) + + def __set__(self, obj, value): + cls = obj if isinstance(obj, type) else type(obj) + property.__set__(self, cls, value) + )", Py_file_input, d.ptr(), d.ptr() + ); + if (result == nullptr) + throw error_already_set(); + Py_DECREF(result); + return (PyTypeObject *) d["pybind11_static_property"].cast().release().ptr(); +} + +#endif // PYPY + +/** Types with static properties need to handle `Type.static_prop = x` in a specific way. + By default, Python replaces the `static_property` itself, but for wrapped C++ types + we need to call `static_property.__set__()` in order to propagate the new value to + the underlying C++ data structure. */ +extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyObject* value) { + // Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw + // descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`). + PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name); + + // The following assignment combinations are possible: + // 1. `Type.static_prop = value` --> descr_set: `Type.static_prop.__set__(value)` + // 2. `Type.static_prop = other_static_prop` --> setattro: replace existing `static_prop` + // 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment + const auto static_prop = (PyObject *) get_internals().static_property_type; + const auto call_descr_set = descr && PyObject_IsInstance(descr, static_prop) + && !PyObject_IsInstance(value, static_prop); + if (call_descr_set) { + // Call `static_property.__set__()` instead of replacing the `static_property`. +#if !defined(PYPY_VERSION) + return Py_TYPE(descr)->tp_descr_set(descr, obj, value); +#else + if (PyObject *result = PyObject_CallMethod(descr, "__set__", "OO", obj, value)) { + Py_DECREF(result); + return 0; + } else { + return -1; + } +#endif + } else { + // Replace existing attribute. + return PyType_Type.tp_setattro(obj, name, value); + } +} + +#if PY_MAJOR_VERSION >= 3 +/** + * Python 3's PyInstanceMethod_Type hides itself via its tp_descr_get, which prevents aliasing + * methods via cls.attr("m2") = cls.attr("m1"): instead the tp_descr_get returns a plain function, + * when called on a class, or a PyMethod, when called on an instance. Override that behaviour here + * to do a special case bypass for PyInstanceMethod_Types. + */ +extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name) { + PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name); + if (descr && PyInstanceMethod_Check(descr)) { + Py_INCREF(descr); + return descr; + } + else { + return PyType_Type.tp_getattro(obj, name); + } +} +#endif + +/** This metaclass is assigned by default to all pybind11 types and is required in order + for static properties to function correctly. Users may override this using `py::metaclass`. + Return value: New reference. */ +inline PyTypeObject* make_default_metaclass() { + constexpr auto *name = "pybind11_type"; + auto name_obj = reinterpret_steal(PYBIND11_FROM_STRING(name)); + + /* 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 heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0); + if (!heap_type) + pybind11_fail("make_default_metaclass(): error allocating metaclass!"); + + heap_type->ht_name = name_obj.inc_ref().ptr(); +#ifdef PYBIND11_BUILTIN_QUALNAME + heap_type->ht_qualname = name_obj.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = name; + type->tp_base = type_incref(&PyType_Type); + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; + + type->tp_setattro = pybind11_meta_setattro; +#if PY_MAJOR_VERSION >= 3 + type->tp_getattro = pybind11_meta_getattro; +#endif + + if (PyType_Ready(type) < 0) + pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!"); + + setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); + + return type; +} + +/// For multiple inheritance types we need to recursively register/deregister base pointers for any +/// base classes with pointers that are difference from the instance value pointer so that we can +/// correctly recognize an offset base class pointer. This calls a function with any offset base ptrs. +inline void traverse_offset_bases(void *valueptr, const detail::type_info *tinfo, instance *self, + bool (*f)(void * /*parentptr*/, instance * /*self*/)) { + for (handle h : reinterpret_borrow(tinfo->type->tp_bases)) { + if (auto parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) { + for (auto &c : parent_tinfo->implicit_casts) { + if (c.first == tinfo->cpptype) { + auto *parentptr = c.second(valueptr); + if (parentptr != valueptr) + f(parentptr, self); + traverse_offset_bases(parentptr, parent_tinfo, self, f); + break; + } + } + } + } +} + +inline bool register_instance_impl(void *ptr, instance *self) { + get_internals().registered_instances.emplace(ptr, self); + return true; // unused, but gives the same signature as the deregister func +} +inline bool deregister_instance_impl(void *ptr, instance *self) { + auto ®istered_instances = get_internals().registered_instances; + auto range = registered_instances.equal_range(ptr); + for (auto it = range.first; it != range.second; ++it) { + if (Py_TYPE(self) == Py_TYPE(it->second)) { + registered_instances.erase(it); + return true; + } + } + return false; +} + +inline void register_instance(instance *self, void *valptr, const type_info *tinfo) { + register_instance_impl(valptr, self); + if (!tinfo->simple_ancestors) + traverse_offset_bases(valptr, tinfo, self, register_instance_impl); +} + +inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo) { + bool ret = deregister_instance_impl(valptr, self); + if (!tinfo->simple_ancestors) + traverse_offset_bases(valptr, tinfo, self, deregister_instance_impl); + return ret; +} + +/// Instance creation function for all pybind11 types. It allocates the internal instance layout for +/// holding C++ objects and holders. Allocation is done lazily (the first time the instance is cast +/// to a reference or pointer), and initialization is done by an `__init__` function. +inline PyObject *make_new_instance(PyTypeObject *type) { +#if defined(PYPY_VERSION) + // PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first inherited + // object is a a plain Python type (i.e. not derived from an extension type). Fix it. + ssize_t instance_size = static_cast(sizeof(instance)); + if (type->tp_basicsize < instance_size) { + type->tp_basicsize = instance_size; + } +#endif + PyObject *self = type->tp_alloc(type, 0); + auto inst = reinterpret_cast(self); + // Allocate the value/holder internals: + inst->allocate_layout(); + + inst->owned = true; + + return self; +} + +/// Instance creation function for all pybind11 types. It only allocates space for the +/// C++ object, but doesn't call the constructor -- an `__init__` function must do that. +extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *) { + return make_new_instance(type); +} + +/// An `__init__` function constructs the C++ object. Users should provide at least one +/// of these using `py::init` or directly with `.def(__init__, ...)`. Otherwise, the +/// following default function will be used which simply throws an exception. +extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) { + PyTypeObject *type = Py_TYPE(self); + std::string msg; +#if defined(PYPY_VERSION) + msg += handle((PyObject *) type).attr("__module__").cast() + "."; +#endif + msg += type->tp_name; + msg += ": No constructor defined!"; + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return -1; +} + +inline void add_patient(PyObject *nurse, PyObject *patient) { + auto &internals = get_internals(); + auto instance = reinterpret_cast(nurse); + instance->has_patients = true; + Py_INCREF(patient); + internals.patients[nurse].push_back(patient); +} + +inline void clear_patients(PyObject *self) { + auto instance = reinterpret_cast(self); + auto &internals = get_internals(); + auto pos = internals.patients.find(self); + assert(pos != internals.patients.end()); + // Clearing the patients can cause more Python code to run, which + // can invalidate the iterator. Extract the vector of patients + // from the unordered_map first. + auto patients = std::move(pos->second); + internals.patients.erase(pos); + instance->has_patients = false; + for (PyObject *&patient : patients) + Py_CLEAR(patient); +} + +/// Clears all internal data from the instance and removes it from registered instances in +/// preparation for deallocation. +inline void clear_instance(PyObject *self) { + auto instance = reinterpret_cast(self); + + // Deallocate any values/holders, if present: + for (auto &v_h : values_and_holders(instance)) { + if (v_h) { + + // We have to deregister before we call dealloc because, for virtual MI types, we still + // need to be able to get the parent pointers. + if (v_h.instance_registered() && !deregister_instance(instance, v_h.value_ptr(), v_h.type)) + pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!"); + + if (instance->owned || v_h.holder_constructed()) + v_h.type->dealloc(v_h); + } + } + // Deallocate the value/holder layout internals: + instance->deallocate_layout(); + + if (instance->weakrefs) + PyObject_ClearWeakRefs(self); + + PyObject **dict_ptr = _PyObject_GetDictPtr(self); + if (dict_ptr) + Py_CLEAR(*dict_ptr); + + if (instance->has_patients) + clear_patients(self); +} + +/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc` +/// to destroy the C++ object itself, while the rest is Python bookkeeping. +extern "C" inline void pybind11_object_dealloc(PyObject *self) { + clear_instance(self); + + auto type = Py_TYPE(self); + type->tp_free(self); + + // `type->tp_dealloc != pybind11_object_dealloc` means that we're being called + // as part of a derived type's dealloc, in which case we're not allowed to decref + // the type here. For cross-module compatibility, we shouldn't compare directly + // with `pybind11_object_dealloc`, but with the common one stashed in internals. + auto pybind11_object_type = (PyTypeObject *) get_internals().instance_base; + if (type->tp_dealloc == pybind11_object_type->tp_dealloc) + Py_DECREF(type); +} + +/** Create the type which can be used as a common base for all classes. This is + needed in order to satisfy Python's requirements for multiple inheritance. + Return value: New reference. */ +inline PyObject *make_object_base_type(PyTypeObject *metaclass) { + constexpr auto *name = "pybind11_object"; + auto name_obj = reinterpret_steal(PYBIND11_FROM_STRING(name)); + + /* 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 heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0); + if (!heap_type) + pybind11_fail("make_object_base_type(): error allocating type!"); + + heap_type->ht_name = name_obj.inc_ref().ptr(); +#ifdef PYBIND11_BUILTIN_QUALNAME + heap_type->ht_qualname = name_obj.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = name; + type->tp_base = type_incref(&PyBaseObject_Type); + type->tp_basicsize = static_cast(sizeof(instance)); + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; + + type->tp_new = pybind11_object_new; + type->tp_init = pybind11_object_init; + type->tp_dealloc = pybind11_object_dealloc; + + /* Support weak references (needed for the keep_alive feature) */ + type->tp_weaklistoffset = offsetof(instance, weakrefs); + + if (PyType_Ready(type) < 0) + pybind11_fail("PyType_Ready failed in make_object_base_type():" + error_string()); + + setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); + + assert(!PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)); + return (PyObject *) heap_type; +} + +/// dynamic_attr: Support for `d = instance.__dict__`. +extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) { + PyObject *&dict = *_PyObject_GetDictPtr(self); + if (!dict) + dict = PyDict_New(); + Py_XINCREF(dict); + return dict; +} + +/// dynamic_attr: Support for `instance.__dict__ = dict()`. +extern "C" inline int pybind11_set_dict(PyObject *self, 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(self); + Py_INCREF(new_dict); + Py_CLEAR(dict); + dict = new_dict; + return 0; +} + +/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`. +extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) { + PyObject *&dict = *_PyObject_GetDictPtr(self); + Py_VISIT(dict); + return 0; +} + +/// dynamic_attr: Allow the GC to clear the dictionary. +extern "C" inline int pybind11_clear(PyObject *self) { + PyObject *&dict = *_PyObject_GetDictPtr(self); + Py_CLEAR(dict); + return 0; +} + +/// Give instances of this type a `__dict__` and opt into garbage collection. +inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) { + auto type = &heap_type->ht_type; +#if defined(PYPY_VERSION) + pybind11_fail(std::string(type->tp_name) + ": dynamic attributes are " + "currently not supported in " + "conjunction with PyPy!"); +#endif + type->tp_flags |= Py_TPFLAGS_HAVE_GC; + type->tp_dictoffset = type->tp_basicsize; // place dict at the end + type->tp_basicsize += (ssize_t)sizeof(PyObject *); // and allocate enough space for it + type->tp_traverse = pybind11_traverse; + type->tp_clear = pybind11_clear; + + static PyGetSetDef getset[] = { + {const_cast("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr}, + {nullptr, nullptr, nullptr, nullptr, nullptr} + }; + type->tp_getset = getset; +} + +/// buffer_protocol: Fill in the view as specified by flags. +extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int flags) { + // Look for a `get_buffer` implementation in this type's info or any bases (following MRO). + type_info *tinfo = nullptr; + for (auto type : reinterpret_borrow(Py_TYPE(obj)->tp_mro)) { + tinfo = get_type_info((PyTypeObject *) type.ptr()); + if (tinfo && tinfo->get_buffer) + break; + } + if (view == nullptr || obj == nullptr || !tinfo || !tinfo->get_buffer) { + if (view) + view->obj = nullptr; + PyErr_SetString(PyExc_BufferError, "pybind11_getbuffer(): Internal error"); + return -1; + } + std::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 = 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 = &info->strides[0]; + view->shape = &info->shape[0]; + } + Py_INCREF(view->obj); + return 0; +} + +/// buffer_protocol: Release the resources of the buffer. +extern "C" inline void pybind11_releasebuffer(PyObject *, Py_buffer *view) { + delete (buffer_info *) view->internal; +} + +/// Give this type a buffer interface. +inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) { + heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer; +#if PY_MAJOR_VERSION < 3 + heap_type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; +#endif + + heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer; + heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer; +} + +/** Create a brand new Python type according to the `type_record` specification. + Return value: New reference. */ +inline PyObject* make_new_python_type(const type_record &rec) { + auto name = reinterpret_steal(PYBIND11_FROM_STRING(rec.name)); + + auto qualname = name; + if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) { +#if PY_MAJOR_VERSION >= 3 + qualname = reinterpret_steal( + PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr())); +#else + qualname = str(rec.scope.attr("__qualname__").cast() + "." + rec.name); +#endif + } + + object module; + if (rec.scope) { + if (hasattr(rec.scope, "__module__")) + module = rec.scope.attr("__module__"); + else if (hasattr(rec.scope, "__name__")) + module = rec.scope.attr("__name__"); + } + + auto full_name = c_str( +#if !defined(PYPY_VERSION) + module ? str(module).cast() + "." + rec.name : +#endif + 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); + } + + auto &internals = get_internals(); + auto bases = tuple(rec.bases); + auto base = (bases.size() == 0) ? internals.instance_base + : bases[0].ptr(); + + /* 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 metaclass = rec.metaclass.ptr() ? (PyTypeObject *) rec.metaclass.ptr() + : internals.default_metaclass; + + auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0); + if (!heap_type) + pybind11_fail(std::string(rec.name) + ": Unable to create type object!"); + + heap_type->ht_name = name.release().ptr(); +#ifdef PYBIND11_BUILTIN_QUALNAME + heap_type->ht_qualname = qualname.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = full_name; + type->tp_doc = tp_doc; + type->tp_base = type_incref((PyTypeObject *)base); + type->tp_basicsize = static_cast(sizeof(instance)); + if (bases.size() > 0) + type->tp_bases = bases.release().ptr(); + + /* Don't inherit base __init__ */ + type->tp_init = pybind11_object_init; + + /* Supported protocols */ + type->tp_as_number = &heap_type->as_number; + type->tp_as_sequence = &heap_type->as_sequence; + type->tp_as_mapping = &heap_type->as_mapping; + + /* Flags */ + type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; +#if PY_MAJOR_VERSION < 3 + type->tp_flags |= Py_TPFLAGS_CHECKTYPES; +#endif + + if (rec.dynamic_attr) + enable_dynamic_attributes(heap_type); + + if (rec.buffer_protocol) + enable_buffer_protocol(heap_type); + + if (PyType_Ready(type) < 0) + pybind11_fail(std::string(rec.name) + ": PyType_Ready failed (" + error_string() + ")!"); + + assert(rec.dynamic_attr ? PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC) + : !PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)); + + /* Register type with the parent scope */ + if (rec.scope) + setattr(rec.scope, rec.name, (PyObject *) type); + else + Py_INCREF(type); // Keep it alive forever (reference leak) + + if (module) // Needed by pydoc + setattr((PyObject *) type, "__module__", module); + + PYBIND11_SET_OLDPY_QUALNAME(type, qualname); + + return (PyObject *) type; +} + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/pybind11/include/pybind11/detail/common.h b/pybind11/include/pybind11/detail/common.h new file mode 100644 index 0000000..5ff7485 --- /dev/null +++ b/pybind11/include/pybind11/detail/common.h @@ -0,0 +1,807 @@ +/* + pybind11/detail/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 + +// Robust support for some features and loading modules compiled against different pybind versions +// requires forcing hidden visibility on pybind code, so we enforce this by setting the attribute on +// the main `pybind11` namespace. +#if !defined(PYBIND11_NAMESPACE) +# ifdef __GNUG__ +# define PYBIND11_NAMESPACE pybind11 __attribute__((visibility("hidden"))) +# else +# define PYBIND11_NAMESPACE pybind11 +# endif +#endif + +#if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER) +# if __cplusplus >= 201402L +# define PYBIND11_CPP14 +# if __cplusplus >= 201703L +# define PYBIND11_CPP17 +# endif +# endif +#elif defined(_MSC_VER) && __cplusplus == 199711L +// MSVC sets _MSVC_LANG rather than __cplusplus (supposedly until the standard is fully implemented) +// Unless you use the /Zc:__cplusplus flag on Visual Studio 2017 15.7 Preview 3 or newer +# if _MSVC_LANG >= 201402L +# define PYBIND11_CPP14 +# if _MSVC_LANG > 201402L && _MSC_VER >= 1910 +# define PYBIND11_CPP17 +# endif +# endif +#endif + +// Compiler version assertions +#if defined(__INTEL_COMPILER) +# if __INTEL_COMPILER < 1700 +# error pybind11 requires Intel C++ compiler v17 or newer +# endif +#elif defined(__clang__) && !defined(__apple_build_version__) +# if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 3) +# error pybind11 requires clang 3.3 or newer +# endif +#elif defined(__clang__) +// Apple changes clang version macros to its Xcode version; the first Xcode release based on +// (upstream) clang 3.3 was Xcode 5: +# if __clang_major__ < 5 +# error pybind11 requires Xcode/clang 5.0 or newer +# endif +#elif defined(__GNUG__) +# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8) +# error pybind11 requires gcc 4.8 or newer +# endif +#elif defined(_MSC_VER) +// Pybind hits various compiler bugs in 2015u2 and earlier, and also makes use of some stl features +// (e.g. std::negation) added in 2015u3: +# if _MSC_FULL_VER < 190024210 +# error pybind11 requires MSVC 2015 update 3 or newer +# 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)]] +#else +# define PYBIND11_DEPRECATED(reason) __attribute__((deprecated(reason))) +#endif + +#define PYBIND11_VERSION_MAJOR 2 +#define PYBIND11_VERSION_MINOR 3 +#define PYBIND11_VERSION_PATCH dev0 + +/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode +#if defined(_MSC_VER) +# if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 4) +# define HAVE_ROUND 1 +# endif +# pragma warning(push) +# pragma warning(disable: 4510 4610 4512 4005) +# if defined(_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 +#include + +#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions +#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr) +#define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check +#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION +#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_BYTES_SIZE PyBytes_Size +#define PYBIND11_LONG_CHECK(o) PyLong_Check(o) +#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o) +#define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) o) +#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) 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_BOOL_ATTR "__bool__" +#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool) +#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_INSTANCE_METHOD_CHECK PyMethod_Check +#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyMethod_GET_FUNCTION +#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_BYTES_SIZE PyString_Size +#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_FROM_SIGNED(o) PyInt_FromSsize_t((ssize_t) o) // Returns long if needed. +#define PYBIND11_LONG_FROM_UNSIGNED(o) PyInt_FromSize_t((size_t) o) // Returns long if needed. +#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_BOOL_ATTR "__nonzero__" +#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_nonzero) +#define PYBIND11_PLUGIN_IMPL(name) \ + static PyObject *pybind11_init_wrapper(); \ + extern "C" PYBIND11_EXPORT void init##name() { \ + (void)pybind11_init_wrapper(); \ + } \ + PyObject *pybind11_init_wrapper() +#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_CONCAT(first, second) first##second + +#define PYBIND11_CHECK_PYTHON_VERSION \ + { \ + const char *compiled_ver = PYBIND11_TOSTRING(PY_MAJOR_VERSION) \ + "." PYBIND11_TOSTRING(PY_MINOR_VERSION); \ + const char *runtime_ver = Py_GetVersion(); \ + size_t len = std::strlen(compiled_ver); \ + if (std::strncmp(runtime_ver, compiled_ver, len) != 0 \ + || (runtime_ver[len] >= '0' && runtime_ver[len] <= '9')) { \ + PyErr_Format(PyExc_ImportError, \ + "Python version mismatch: module was compiled for Python %s, " \ + "but the interpreter version is incompatible: %s.", \ + compiled_ver, runtime_ver); \ + return nullptr; \ + } \ + } + +#define PYBIND11_CATCH_INIT_EXCEPTIONS \ + catch (pybind11::error_already_set &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } catch (const std::exception &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } \ + +/** \rst + ***Deprecated in favor of PYBIND11_MODULE*** + + This macro creates the entry point that will be invoked when the Python interpreter + imports a plugin library. Please create a `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(); + } +\endrst */ +#define PYBIND11_PLUGIN(name) \ + PYBIND11_DEPRECATED("PYBIND11_PLUGIN is deprecated, use PYBIND11_MODULE") \ + static PyObject *pybind11_init(); \ + PYBIND11_PLUGIN_IMPL(name) { \ + PYBIND11_CHECK_PYTHON_VERSION \ + try { \ + return pybind11_init(); \ + } PYBIND11_CATCH_INIT_EXCEPTIONS \ + } \ + PyObject *pybind11_init() + +/** \rst + This macro creates the entry point that will be invoked when the Python interpreter + imports an extension module. The module name is given as the fist argument and it + should not be in quotes. The second macro argument defines a variable of type + `py::module` which can be used to initialize the module. + + .. code-block:: cpp + + PYBIND11_MODULE(example, m) { + m.doc() = "pybind11 example module"; + + // Add bindings here + m.def("foo", []() { + return "Hello, World!"; + }); + } +\endrst */ +#define PYBIND11_MODULE(name, variable) \ + static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \ + PYBIND11_PLUGIN_IMPL(name) { \ + PYBIND11_CHECK_PYTHON_VERSION \ + auto m = pybind11::module(PYBIND11_TOSTRING(name)); \ + try { \ + PYBIND11_CONCAT(pybind11_init_, name)(m); \ + return m.ptr(); \ + } PYBIND11_CATCH_INIT_EXCEPTIONS \ + } \ + void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable) + + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +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 +}; + +NAMESPACE_BEGIN(detail) + +inline static constexpr int log2(size_t n, int k = 0) { return (n <= 1) ? k : log2(n >> 1, k + 1); } + +// Returns the size as a multiple of sizeof(void *), rounded up. +inline static constexpr size_t size_in_ptrs(size_t s) { return 1 + ((s - 1) >> log2(sizeof(void *))); } + +/** + * The space to allocate for simple layout instance holders (see below) in multiple of the size of + * a pointer (e.g. 2 means 16 bytes on 64-bit architectures). The default is the minimum required + * to holder either a std::unique_ptr or std::shared_ptr (which is almost always + * sizeof(std::shared_ptr)). + */ +constexpr size_t instance_simple_holder_in_ptrs() { + static_assert(sizeof(std::shared_ptr) >= sizeof(std::unique_ptr), + "pybind assumes std::shared_ptrs are at least as big as std::unique_ptrs"); + return size_in_ptrs(sizeof(std::shared_ptr)); +} + +// Forward declarations +struct type_info; +struct value_and_holder; + +struct nonsimple_values_and_holders { + void **values_and_holders; + uint8_t *status; +}; + +/// The 'instance' type which needs to be standard layout (need to be able to use 'offsetof') +struct instance { + PyObject_HEAD + /// Storage for pointers and holder; see simple_layout, below, for a description + union { + void *simple_value_holder[1 + instance_simple_holder_in_ptrs()]; + nonsimple_values_and_holders nonsimple; + }; + /// Weak references + PyObject *weakrefs; + /// If true, the pointer is owned which means we're free to manage it with a holder. + bool owned : 1; + /** + * An instance has two possible value/holder layouts. + * + * Simple layout (when this flag is true), means the `simple_value_holder` is set with a pointer + * and the holder object governing that pointer, i.e. [val1*][holder]. This layout is applied + * whenever there is no python-side multiple inheritance of bound C++ types *and* the type's + * holder will fit in the default space (which is large enough to hold either a std::unique_ptr + * or std::shared_ptr). + * + * Non-simple layout applies when using custom holders that require more space than `shared_ptr` + * (which is typically the size of two pointers), or when multiple inheritance is used on the + * python side. Non-simple layout allocates the required amount of memory to have multiple + * bound C++ classes as parents. Under this layout, `nonsimple.values_and_holders` is set to a + * pointer to allocated space of the required space to hold a sequence of value pointers and + * holders followed `status`, a set of bit flags (1 byte each), i.e. + * [val1*][holder1][val2*][holder2]...[bb...] where each [block] is rounded up to a multiple of + * `sizeof(void *)`. `nonsimple.status` is, for convenience, a pointer to the + * beginning of the [bb...] block (but not independently allocated). + * + * Status bits indicate whether the associated holder is constructed (& + * status_holder_constructed) and whether the value pointer is registered (& + * status_instance_registered) in `registered_instances`. + */ + bool simple_layout : 1; + /// For simple layout, tracks whether the holder has been constructed + bool simple_holder_constructed : 1; + /// For simple layout, tracks whether the instance is registered in `registered_instances` + bool simple_instance_registered : 1; + /// If true, get_internals().patients has an entry for this object + bool has_patients : 1; + + /// Initializes all of the above type/values/holders data (but not the instance values themselves) + void allocate_layout(); + + /// Destroys/deallocates all of the above + void deallocate_layout(); + + /// Returns the value_and_holder wrapper for the given type (or the first, if `find_type` + /// omitted). Returns a default-constructed (with `.inst = nullptr`) object on failure if + /// `throw_if_missing` is false. + value_and_holder get_value_and_holder(const type_info *find_type = nullptr, bool throw_if_missing = true); + + /// Bit values for the non-simple status flags + static constexpr uint8_t status_holder_constructed = 1; + static constexpr uint8_t status_instance_registered = 2; +}; + +static_assert(std::is_standard_layout::value, "Internal error: `pybind11::detail::instance` is not standard layout!"); + +/// from __cpp_future__ import (convenient aliases from C++14/17) +#if defined(PYBIND11_CPP14) && (!defined(_MSC_VER) || _MSC_VER >= 1910) +using std::enable_if_t; +using std::conditional_t; +using std::remove_cv_t; +using std::remove_reference_t; +#else +template using enable_if_t = typename std::enable_if::type; +template using conditional_t = typename std::conditional::type; +template using remove_cv_t = typename std::remove_cv::type; +template using remove_reference_t = typename std::remove_reference::type; +#endif + +/// Index sequences +#if defined(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 + +/// Make an index sequence of the indices of true arguments +template struct select_indices_impl { using type = ISeq; }; +template struct select_indices_impl, I, B, Bs...> + : select_indices_impl, index_sequence>, I + 1, Bs...> {}; +template using select_indices = typename select_indices_impl, 0, Bs...>::type; + +/// Backports of std::bool_constant and std::negation to accommodate older compilers +template using bool_constant = std::integral_constant; +template struct negation : bool_constant { }; + +template struct void_t_impl { using type = void; }; +template using void_t = typename void_t_impl::type; + +/// Compile-time all/any/none of that check the boolean value of all template types +#if defined(__cpp_fold_expressions) && !(defined(_MSC_VER) && (_MSC_VER < 1916)) +template using all_of = bool_constant<(Ts::value && ...)>; +template using any_of = bool_constant<(Ts::value || ...)>; +#elif !defined(_MSC_VER) +template struct bools {}; +template using all_of = std::is_same< + bools, + bools>; +template using any_of = negation...>>; +#else +// MSVC has trouble with the above, but supports std::conjunction, which we can use instead (albeit +// at a slight loss of compilation efficiency). +template using all_of = std::conjunction; +template using any_of = std::disjunction; +#endif +template using none_of = negation>; + +template class... Predicates> using satisfies_all_of = all_of...>; +template class... Predicates> using satisfies_any_of = any_of...>; +template class... Predicates> using satisfies_none_of = none_of...>; + +/// 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 { }; + +/// Compile-time integer sum +#ifdef __cpp_fold_expressions +template constexpr size_t constexpr_sum(Ts... ns) { return (0 + ... + size_t{ns}); } +#else +constexpr size_t constexpr_sum() { return 0; } +template +constexpr size_t constexpr_sum(T n, Ts... ns) { return size_t{n} + constexpr_sum(ns...); } +#endif + +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. Returns sizeof...(Ts) if +/// none match. +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, or -1 if none match. +template class Predicate, typename... Ts> +constexpr int constexpr_last() { return constexpr_impl::last(0, -1, Predicate::value...); } + +/// Return the Nth element from the parameter pack +template +struct pack_element { using type = typename pack_element::type; }; +template +struct pack_element<0, T, Ts...> { using type = T; }; + +/// Return the one and only type which matches the predicate, or Default if none match. +/// If more than one type matches the predicate, fail at compile-time. +template class Predicate, typename Default, typename... Ts> +struct exactly_one { + static constexpr auto found = constexpr_sum(Predicate::value...); + static_assert(found <= 1, "Found more than one type matching the predicate"); + + static constexpr auto index = found ? constexpr_first() : 0; + using type = conditional_t::type, Default>; +}; +template class P, typename Default> +struct exactly_one { using type = Default; }; + +template class Predicate, typename Default, typename... Ts> +using exactly_one_t = typename exactly_one::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; + +/// Like is_base_of, but requires a strict base (i.e. `is_strict_base_of::value == false`, +/// unlike `std::is_base_of`) +template using is_strict_base_of = bool_constant< + std::is_base_of::value && !std::is_same::value>; + +/// Like is_base_of, but also requires that the base type is accessible (i.e. that a Derived pointer +/// can be converted to a Base pointer) +template using is_accessible_base_of = bool_constant< + std::is_base_of::value && std::is_convertible::value>; + +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((intrinsic_t*)nullptr)); +#else // MSVC2015 has trouble with decltype in template aliases +struct is_template_base_of : decltype(is_template_base_of_impl::check((intrinsic_t*)nullptr)) { }; +#endif + +/// Check if T is an instantiation of the template `Class`. For example: +/// `is_instantiation` is true if `T == shared_ptr` where U can be anything. +template class Class, typename T> +struct is_instantiation : std::false_type { }; +template class Class, typename... Us> +struct is_instantiation> : std::true_type { }; + +/// Check if T is std::shared_ptr where U can be anything +template using is_shared_ptr = is_instantiation; + +/// Check if T looks like an input iterator +template struct is_input_iterator : std::false_type {}; +template +struct is_input_iterator()), decltype(++std::declval())>> + : std::true_type {}; + +template using is_function_pointer = bool_constant< + std::is_pointer::value && std::is_function::type>::value>; + +template struct strip_function_object { + using type = typename remove_class::type; +}; + +// Extracts the function signature from a function, function pointer or lambda. +template > +using function_signature_t = conditional_t< + std::is_function::value, + F, + typename conditional_t< + std::is_pointer::value || std::is_member_pointer::value, + std::remove_pointer, + strip_function_object + >::type +>; + +/// Returns true if the type looks like a lambda: that is, isn't a function, pointer or member +/// pointer. Note that this can catch all sorts of other things, too; this is intended to be used +/// in a place where passing a lambda makes sense. +template using is_lambda = satisfies_none_of, + std::is_function, std::is_pointer, std::is_member_pointer>; + +/// Ignore that a variable is unused in compiler warnings +inline void ignore_unused(const int *) { } + +/// Apply a function over each element of a parameter pack +#ifdef __cpp_fold_expressions +#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) (((PATTERN), void()), ...) +#else +using expand_side_effects = bool[]; +#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) pybind11::detail::expand_side_effects{ ((PATTERN), void(), false)..., false } +#endif + +NAMESPACE_END(detail) + +/// C++ bindings of builtin Python exceptions +class builtin_exception : public std::runtime_error { +public: + using std::runtime_error::runtime_error; + /// Set the error using the Python C API + virtual void set_error() const = 0; +}; + +#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); } + +template struct format_descriptor { }; + +NAMESPACE_BEGIN(detail) +// Returns the index of the given type in the type char array below, and in the list in numpy.h +// The order here is: bool; 8 ints ((signed,unsigned)x(8,16,32,64)bits); float,double,long double; +// complex float,double,long double. Note that the long double types only participate when long +// double is actually longer than double (it isn't under MSVC). +// NB: not only the string below but also complex.h and numpy.h rely on this order. +template struct is_fmt_numeric { static constexpr bool value = false; }; +template struct is_fmt_numeric::value>> { + static constexpr bool value = true; + static constexpr int index = std::is_same::value ? 0 : 1 + ( + std::is_integral::value ? detail::log2(sizeof(T))*2 + std::is_unsigned::value : 8 + ( + std::is_same::value ? 1 : std::is_same::value ? 2 : 0)); +}; +NAMESPACE_END(detail) + +template struct format_descriptor::value>> { + static constexpr const char c = "?bBhHiIqQfdg"[detail::is_fmt_numeric::index]; + static constexpr const char value[2] = { c, '\0' }; + static std::string format() { return std::string(1, c); } +}; + +#if !defined(PYBIND11_CPP17) + +template constexpr const char format_descriptor< + T, detail::enable_if_t::value>>::value[2]; + +#endif + +/// 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); } +}; + +/// Dummy destructor wrapper that can be used to expose classes with a private destructor +struct nodelete { template void operator()(T*) { } }; + +// overload_cast requires variable templates: C++14 +#if defined(PYBIND11_CPP14) +#define PYBIND11_OVERLOAD_CAST 1 + +NAMESPACE_BEGIN(detail) +template +struct overload_cast_impl { + constexpr overload_cast_impl() {} // MSVC 2015 needs this + + template + constexpr auto operator()(Return (*pf)(Args...)) const noexcept + -> decltype(pf) { return pf; } + + template + constexpr auto operator()(Return (Class::*pmf)(Args...), std::false_type = {}) const noexcept + -> decltype(pmf) { return pmf; } + + template + constexpr auto operator()(Return (Class::*pmf)(Args...) const, std::true_type) const noexcept + -> decltype(pmf) { return pmf; } +}; +NAMESPACE_END(detail) + +/// Syntax sugar for resolving overloaded function pointers: +/// - regular: static_cast(&Class::func) +/// - sweet: overload_cast(&Class::func) +template +static constexpr detail::overload_cast_impl overload_cast = {}; +// MSVC 2015 only accepts this particular initialization syntax for this variable template. + +/// Const member function selector for overload_cast +/// - regular: static_cast(&Class::func) +/// - sweet: overload_cast(&Class::func, const_) +static constexpr auto const_ = std::true_type{}; + +#else // no overload_cast: providing something that static_assert-fails: +template struct overload_cast { + static_assert(detail::deferred_t::value, + "pybind11::overload_cast<...> requires compiling in C++14 mode"); +}; +#endif // overload_cast + +NAMESPACE_BEGIN(detail) + +// Adaptor for converting arbitrary container arguments into a vector; implicitly convertible from +// any standard container (or C-style array) supporting std::begin/std::end, any singleton +// arithmetic type (if T is arithmetic), or explicitly constructible from an iterator pair. +template +class any_container { + std::vector v; +public: + any_container() = default; + + // Can construct from a pair of iterators + template ::value>> + any_container(It first, It last) : v(first, last) { } + + // Implicit conversion constructor from any arbitrary container type with values convertible to T + template ())), T>::value>> + any_container(const Container &c) : any_container(std::begin(c), std::end(c)) { } + + // initializer_list's aren't deducible, so don't get matched by the above template; we need this + // to explicitly allow implicit conversion from one: + template ::value>> + any_container(const std::initializer_list &c) : any_container(c.begin(), c.end()) { } + + // Avoid copying if given an rvalue vector of the correct type. + any_container(std::vector &&v) : v(std::move(v)) { } + + // Moves the vector out of an rvalue any_container + operator std::vector &&() && { return std::move(v); } + + // Dereferencing obtains a reference to the underlying vector + std::vector &operator*() { return v; } + const std::vector &operator*() const { return v; } + + // -> lets you call methods on the underlying vector + std::vector *operator->() { return &v; } + const std::vector *operator->() const { return &v; } +}; + +NAMESPACE_END(detail) + + + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/pybind11/include/pybind11/detail/descr.h b/pybind11/include/pybind11/detail/descr.h new file mode 100644 index 0000000..8d404e5 --- /dev/null +++ b/pybind11/include/pybind11/detail/descr.h @@ -0,0 +1,100 @@ +/* + pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time + + 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) +NAMESPACE_BEGIN(detail) + +#if !defined(_MSC_VER) +# define PYBIND11_DESCR_CONSTEXPR static constexpr +#else +# define PYBIND11_DESCR_CONSTEXPR const +#endif + +/* Concatenate type signatures at compile time */ +template +struct descr { + char text[N + 1]; + + constexpr descr() : text{'\0'} { } + constexpr descr(char const (&s)[N+1]) : descr(s, make_index_sequence()) { } + + template + constexpr descr(char const (&s)[N+1], index_sequence) : text{s[Is]..., '\0'} { } + + template + constexpr descr(char c, Chars... cs) : text{c, static_cast(cs)..., '\0'} { } + + static constexpr std::array types() { + return {{&typeid(Ts)..., nullptr}}; + } +}; + +template +constexpr descr plus_impl(const descr &a, const descr &b, + index_sequence, index_sequence) { + return {a.text[Is1]..., b.text[Is2]...}; +} + +template +constexpr descr operator+(const descr &a, const descr &b) { + return plus_impl(a, b, make_index_sequence(), make_index_sequence()); +} + +template +constexpr descr _(char const(&text)[N]) { return descr(text); } +constexpr descr<0> _(char const(&)[1]) { return {}; } + +template struct int_to_str : int_to_str { }; +template struct int_to_str<0, Digits...> { + static constexpr auto digits = descr(('0' + Digits)...); +}; + +// Ternary description (like std::conditional) +template +constexpr enable_if_t> _(char const(&text1)[N1], char const(&)[N2]) { + return _(text1); +} +template +constexpr enable_if_t> _(char const(&)[N1], char const(&text2)[N2]) { + return _(text2); +} + +template +constexpr enable_if_t _(const T1 &d, const T2 &) { return d; } +template +constexpr enable_if_t _(const T1 &, const T2 &d) { return d; } + +template auto constexpr _() -> decltype(int_to_str::digits) { + return int_to_str::digits; +} + +template constexpr descr<1, Type> _() { return {'%'}; } + +constexpr descr<0> concat() { return {}; } + +template +constexpr descr concat(const descr &descr) { return descr; } + +template +constexpr auto concat(const descr &d, const Args &...args) + -> decltype(std::declval>() + concat(args...)) { + return d + _(", ") + concat(args...); +} + +template +constexpr descr type_descr(const descr &descr) { + return _("{") + descr + _("}"); +} + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/pybind11/include/pybind11/detail/init.h b/pybind11/include/pybind11/detail/init.h new file mode 100644 index 0000000..acfe00b --- /dev/null +++ b/pybind11/include/pybind11/detail/init.h @@ -0,0 +1,335 @@ +/* + pybind11/detail/init.h: init factory function implementation and support code. + + Copyright (c) 2017 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. +*/ + +#pragma once + +#include "class.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +template <> +class type_caster { +public: + bool load(handle h, bool) { + value = reinterpret_cast(h.ptr()); + return true; + } + + template using cast_op_type = value_and_holder &; + operator value_and_holder &() { return *value; } + static constexpr auto name = _(); + +private: + value_and_holder *value = nullptr; +}; + +NAMESPACE_BEGIN(initimpl) + +inline void no_nullptr(void *ptr) { + if (!ptr) throw type_error("pybind11::init(): factory function returned nullptr"); +} + +// Implementing functions for all forms of py::init<...> and py::init(...) +template using Cpp = typename Class::type; +template using Alias = typename Class::type_alias; +template using Holder = typename Class::holder_type; + +template using is_alias_constructible = std::is_constructible, Cpp &&>; + +// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance. +template = 0> +bool is_alias(Cpp *ptr) { + return dynamic_cast *>(ptr) != nullptr; +} +// Failing fallback version of the above for a no-alias class (always returns false) +template +constexpr bool is_alias(void *) { return false; } + +// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall +// back to brace aggregate initiailization so that for aggregate initialization can be used with +// py::init, e.g. `py::init` to initialize a `struct T { int a; int b; }`. For +// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually +// works, but will not do the expected thing when `T` has an `initializer_list` constructor). +template ::value, int> = 0> +inline Class *construct_or_initialize(Args &&...args) { return new Class(std::forward(args)...); } +template ::value, int> = 0> +inline Class *construct_or_initialize(Args &&...args) { return new Class{std::forward(args)...}; } + +// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with +// an alias to provide only a single Cpp factory function as long as the Alias can be +// constructed from an rvalue reference of the base Cpp type. This means that Alias classes +// can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to +// inherit all the base class constructors. +template +void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/, + value_and_holder &v_h, Cpp &&base) { + v_h.value_ptr() = new Alias(std::move(base)); +} +template +[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/, + value_and_holder &, Cpp &&) { + throw type_error("pybind11::init(): unable to convert returned instance to required " + "alias class: no `Alias(Class &&)` constructor available"); +} + +// Error-generating fallback for factories that don't match one of the below construction +// mechanisms. +template +void construct(...) { + static_assert(!std::is_same::value /* always false */, + "pybind11::init(): init function must return a compatible pointer, " + "holder, or value"); +} + +// Pointer return v1: the factory function returns a class pointer for a registered class. +// If we don't need an alias (because this class doesn't have one, or because the final type is +// inherited on the Python side) we can simply take over ownership. Otherwise we need to try to +// construct an Alias from the returned base instance. +template +void construct(value_and_holder &v_h, Cpp *ptr, bool need_alias) { + no_nullptr(ptr); + if (Class::has_alias && need_alias && !is_alias(ptr)) { + // We're going to try to construct an alias by moving the cpp type. Whether or not + // that succeeds, we still need to destroy the original cpp pointer (either the + // moved away leftover, if the alias construction works, or the value itself if we + // throw an error), but we can't just call `delete ptr`: it might have a special + // deleter, or might be shared_from_this. So we construct a holder around it as if + // it was a normal instance, then steal the holder away into a local variable; thus + // the holder and destruction happens when we leave the C++ scope, and the holder + // class gets to handle the destruction however it likes. + v_h.value_ptr() = ptr; + v_h.set_instance_registered(true); // To prevent init_instance from registering it + v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder + Holder temp_holder(std::move(v_h.holder>())); // Steal the holder + v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null + v_h.set_instance_registered(false); + + construct_alias_from_cpp(is_alias_constructible{}, v_h, std::move(*ptr)); + } else { + // Otherwise the type isn't inherited, so we don't need an Alias + v_h.value_ptr() = ptr; + } +} + +// Pointer return v2: a factory that always returns an alias instance ptr. We simply take over +// ownership of the pointer. +template = 0> +void construct(value_and_holder &v_h, Alias *alias_ptr, bool) { + no_nullptr(alias_ptr); + v_h.value_ptr() = static_cast *>(alias_ptr); +} + +// Holder return: copy its pointer, and move or copy the returned holder into the new instance's +// holder. This also handles types like std::shared_ptr and std::unique_ptr where T is a +// derived type (through those holder's implicit conversion from derived class holder constructors). +template +void construct(value_and_holder &v_h, Holder holder, bool need_alias) { + auto *ptr = holder_helper>::get(holder); + // If we need an alias, check that the held pointer is actually an alias instance + if (Class::has_alias && need_alias && !is_alias(ptr)) + throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance " + "is not an alias instance"); + + v_h.value_ptr() = ptr; + v_h.type->init_instance(v_h.inst, &holder); +} + +// return-by-value version 1: returning a cpp class by value. If the class has an alias and an +// alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct +// the alias from the base when needed (i.e. because of Python-side inheritance). When we don't +// need it, we simply move-construct the cpp value into a new instance. +template +void construct(value_and_holder &v_h, Cpp &&result, bool need_alias) { + static_assert(std::is_move_constructible>::value, + "pybind11::init() return-by-value factory function requires a movable class"); + if (Class::has_alias && need_alias) + construct_alias_from_cpp(is_alias_constructible{}, v_h, std::move(result)); + else + v_h.value_ptr() = new Cpp(std::move(result)); +} + +// return-by-value version 2: returning a value of the alias type itself. We move-construct an +// Alias instance (even if no the python-side inheritance is involved). The is intended for +// cases where Alias initialization is always desired. +template +void construct(value_and_holder &v_h, Alias &&result, bool) { + static_assert(std::is_move_constructible>::value, + "pybind11::init() return-by-alias-value factory function requires a movable alias class"); + v_h.value_ptr() = new Alias(std::move(result)); +} + +// Implementing class for py::init<...>() +template +struct constructor { + template = 0> + static void execute(Class &cl, const Extra&... extra) { + cl.def("__init__", [](value_and_holder &v_h, Args... args) { + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + }, is_new_style_constructor(), extra...); + } + + template , Args...>::value, int> = 0> + static void execute(Class &cl, const Extra&... extra) { + cl.def("__init__", [](value_and_holder &v_h, Args... args) { + if (Py_TYPE(v_h.inst) == v_h.type->type) + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + else + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + }, is_new_style_constructor(), extra...); + } + + template , Args...>::value, int> = 0> + static void execute(Class &cl, const Extra&... extra) { + cl.def("__init__", [](value_and_holder &v_h, Args... args) { + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + }, is_new_style_constructor(), extra...); + } +}; + +// Implementing class for py::init_alias<...>() +template struct alias_constructor { + template , Args...>::value, int> = 0> + static void execute(Class &cl, const Extra&... extra) { + cl.def("__init__", [](value_and_holder &v_h, Args... args) { + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + }, is_new_style_constructor(), extra...); + } +}; + +// Implementation class for py::init(Func) and py::init(Func, AliasFunc) +template , typename = function_signature_t> +struct factory; + +// Specialization for py::init(Func) +template +struct factory { + remove_reference_t class_factory; + + factory(Func &&f) : class_factory(std::forward(f)) { } + + // The given class either has no alias or has no separate alias factory; + // this always constructs the class itself. If the class is registered with an alias + // type and an alias instance is needed (i.e. because the final type is a Python class + // inheriting from the C++ type) the returned value needs to either already be an alias + // instance, or the alias needs to be constructible from a `Class &&` argument. + template + void execute(Class &cl, const Extra &...extra) && { + #if defined(PYBIND11_CPP14) + cl.def("__init__", [func = std::move(class_factory)] + #else + auto &func = class_factory; + cl.def("__init__", [func] + #endif + (value_and_holder &v_h, Args... args) { + construct(v_h, func(std::forward(args)...), + Py_TYPE(v_h.inst) != v_h.type->type); + }, is_new_style_constructor(), extra...); + } +}; + +// Specialization for py::init(Func, AliasFunc) +template +struct factory { + static_assert(sizeof...(CArgs) == sizeof...(AArgs), + "pybind11::init(class_factory, alias_factory): class and alias factories " + "must have identical argument signatures"); + static_assert(all_of...>::value, + "pybind11::init(class_factory, alias_factory): class and alias factories " + "must have identical argument signatures"); + + remove_reference_t class_factory; + remove_reference_t alias_factory; + + factory(CFunc &&c, AFunc &&a) + : class_factory(std::forward(c)), alias_factory(std::forward(a)) { } + + // The class factory is called when the `self` type passed to `__init__` is the direct + // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype. + template + void execute(Class &cl, const Extra&... extra) && { + static_assert(Class::has_alias, "The two-argument version of `py::init()` can " + "only be used if the class has an alias"); + #if defined(PYBIND11_CPP14) + cl.def("__init__", [class_func = std::move(class_factory), alias_func = std::move(alias_factory)] + #else + auto &class_func = class_factory; + auto &alias_func = alias_factory; + cl.def("__init__", [class_func, alias_func] + #endif + (value_and_holder &v_h, CArgs... args) { + if (Py_TYPE(v_h.inst) == v_h.type->type) + // If the instance type equals the registered type we don't have inheritance, so + // don't need the alias and can construct using the class function: + construct(v_h, class_func(std::forward(args)...), false); + else + construct(v_h, alias_func(std::forward(args)...), true); + }, is_new_style_constructor(), extra...); + } +}; + +/// Set just the C++ state. Same as `__init__`. +template +void setstate(value_and_holder &v_h, T &&result, bool need_alias) { + construct(v_h, std::forward(result), need_alias); +} + +/// Set both the C++ and Python states +template ::value, int> = 0> +void setstate(value_and_holder &v_h, std::pair &&result, bool need_alias) { + construct(v_h, std::move(result.first), need_alias); + setattr((PyObject *) v_h.inst, "__dict__", result.second); +} + +/// Implementation for py::pickle(GetState, SetState) +template , typename = function_signature_t> +struct pickle_factory; + +template +struct pickle_factory { + static_assert(std::is_same, intrinsic_t>::value, + "The type returned by `__getstate__` must be the same " + "as the argument accepted by `__setstate__`"); + + remove_reference_t get; + remove_reference_t set; + + pickle_factory(Get get, Set set) + : get(std::forward(get)), set(std::forward(set)) { } + + template + void execute(Class &cl, const Extra &...extra) && { + cl.def("__getstate__", std::move(get)); + +#if defined(PYBIND11_CPP14) + cl.def("__setstate__", [func = std::move(set)] +#else + auto &func = set; + cl.def("__setstate__", [func] +#endif + (value_and_holder &v_h, ArgState state) { + setstate(v_h, func(std::forward(state)), + Py_TYPE(v_h.inst) != v_h.type->type); + }, is_new_style_constructor(), extra...); + } +}; + +NAMESPACE_END(initimpl) +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/pybind11/include/pybind11/detail/internals.h b/pybind11/include/pybind11/detail/internals.h new file mode 100644 index 0000000..6d7dc5c --- /dev/null +++ b/pybind11/include/pybind11/detail/internals.h @@ -0,0 +1,291 @@ +/* + pybind11/detail/internals.h: Internal data structure and related functions + + Copyright (c) 2017 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" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) +// Forward declarations +inline PyTypeObject *make_static_property_type(); +inline PyTypeObject *make_default_metaclass(); +inline PyObject *make_object_base_type(PyTypeObject *metaclass); + +// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new +// Thread Specific Storage (TSS) API. +#if PY_VERSION_HEX >= 0x03070000 +# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr +# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key)) +# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (tstate)) +# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr) +#else + // Usually an int but a long on Cygwin64 with Python 3.x +# define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0 +# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key)) +# if PY_MAJOR_VERSION < 3 +# define PYBIND11_TLS_DELETE_VALUE(key) \ + PyThread_delete_key_value(key) +# define PYBIND11_TLS_REPLACE_VALUE(key, value) \ + do { \ + PyThread_delete_key_value((key)); \ + PyThread_set_key_value((key), (value)); \ + } while (false) +# else +# define PYBIND11_TLS_DELETE_VALUE(key) \ + PyThread_set_key_value((key), nullptr) +# define PYBIND11_TLS_REPLACE_VALUE(key, value) \ + PyThread_set_key_value((key), (value)) +# endif +#endif + +// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly +// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module +// even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under +// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name, +// which works. If not under a known-good stl, provide our own name-based hash and equality +// functions that use the type name. +#if defined(__GLIBCXX__) +inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; } +using type_hash = std::hash; +using type_equal_to = std::equal_to; +#else +inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { + return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0; +} + +struct type_hash { + size_t operator()(const std::type_index &t) const { + size_t hash = 5381; + const char *ptr = t.name(); + while (auto c = static_cast(*ptr++)) + hash = (hash * 33) ^ c; + return hash; + } +}; + +struct type_equal_to { + bool operator()(const std::type_index &lhs, const std::type_index &rhs) const { + return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0; + } +}; +#endif + +template +using type_map = std::unordered_map; + +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 structure used to track registered instances and types. +/// Whenever binary incompatible changes are made to this structure, +/// `PYBIND11_INTERNALS_VERSION` must be incremented. +struct internals { + type_map registered_types_cpp; // std::type_index -> pybind11's type information + std::unordered_map> registered_types_py; // PyTypeObject* -> base type_info(s) + std::unordered_multimap registered_instances; // void * -> instance* + std::unordered_set, overload_hash> inactive_overload_cache; + type_map> direct_conversions; + std::unordered_map> patients; + std::forward_list registered_exception_translators; + std::unordered_map shared_data; // Custom data to be shared across extensions + std::vector loader_patient_stack; // Used by `loader_life_support` + std::forward_list static_strings; // Stores the std::strings backing detail::c_str() + PyTypeObject *static_property_type; + PyTypeObject *default_metaclass; + PyObject *instance_base; +#if defined(WITH_THREAD) + PYBIND11_TLS_KEY_INIT(tstate); + PyInterpreterState *istate = nullptr; +#endif +}; + +/// Additional type information which does not fit into the PyTypeObject. +/// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`. +struct type_info { + PyTypeObject *type; + const std::type_info *cpptype; + size_t type_size, type_align, holder_size_in_ptrs; + void *(*operator_new)(size_t); + void (*init_instance)(instance *, const void *); + void (*dealloc)(value_and_holder &v_h); + std::vector implicit_conversions; + std::vector> implicit_casts; + std::vector *direct_conversions; + buffer_info *(*get_buffer)(PyObject *, void *) = nullptr; + void *get_buffer_data = nullptr; + void *(*module_local_load)(PyObject *, const type_info *) = nullptr; + /* A simple type never occurs as a (direct or indirect) parent + * of a class that makes use of multiple inheritance */ + bool simple_type : 1; + /* True if there is no multiple inheritance in this type's inheritance tree */ + bool simple_ancestors : 1; + /* for base vs derived holder_type checks */ + bool default_holder : 1; + /* true if this is a type registered with py::module_local */ + bool module_local : 1; +}; + +/// Tracks the `internals` and `type_info` ABI version independent of the main library version +#define PYBIND11_INTERNALS_VERSION 3 + +#if defined(_DEBUG) +# define PYBIND11_BUILD_TYPE "_debug" +#else +# define PYBIND11_BUILD_TYPE "" +#endif + +#if defined(WITH_THREAD) +# define PYBIND11_INTERNALS_KIND "" +#else +# define PYBIND11_INTERNALS_KIND "_without_thread" +#endif + +#define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \ + PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_BUILD_TYPE "__" + +#define PYBIND11_MODULE_LOCAL_ID "__pybind11_module_local_v" \ + PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_BUILD_TYPE "__" + +/// Each module locally stores a pointer to the `internals` data. The data +/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`. +inline internals **&get_internals_pp() { + static internals **internals_pp = nullptr; + return internals_pp; +} + +/// Return a reference to the current `internals` data +PYBIND11_NOINLINE inline internals &get_internals() { + auto **&internals_pp = get_internals_pp(); + if (internals_pp && *internals_pp) + return **internals_pp; + + constexpr auto *id = PYBIND11_INTERNALS_ID; + auto builtins = handle(PyEval_GetBuiltins()); + if (builtins.contains(id) && isinstance(builtins[id])) { + internals_pp = static_cast(capsule(builtins[id])); + + // We loaded builtins through python's builtins, which means that our `error_already_set` + // and `builtin_exception` may be different local classes than the ones set up in the + // initial exception translator, below, so add another for our local exception classes. + // + // libstdc++ doesn't require this (types there are identified only by name) +#if !defined(__GLIBCXX__) + (*internals_pp)->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; + } + } + ); +#endif + } else { + if (!internals_pp) internals_pp = new internals*(); + auto *&internals_ptr = *internals_pp; + internals_ptr = new internals(); +#if defined(WITH_THREAD) + PyEval_InitThreads(); + PyThreadState *tstate = PyThreadState_Get(); + #if PY_VERSION_HEX >= 0x03070000 + internals_ptr->tstate = PyThread_tss_alloc(); + if (!internals_ptr->tstate || PyThread_tss_create(internals_ptr->tstate)) + pybind11_fail("get_internals: could not successfully initialize the TSS key!"); + PyThread_tss_set(internals_ptr->tstate, tstate); + #else + internals_ptr->tstate = PyThread_create_key(); + if (internals_ptr->tstate == -1) + pybind11_fail("get_internals: could not successfully initialize the TLS key!"); + PyThread_set_key_value(internals_ptr->tstate, tstate); + #endif + internals_ptr->istate = tstate->interp; +#endif + builtins[id] = capsule(internals_pp); + 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; + } + } + ); + internals_ptr->static_property_type = make_static_property_type(); + internals_ptr->default_metaclass = make_default_metaclass(); + internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass); + } + return **internals_pp; +} + +/// Works like `internals.registered_types_cpp`, but for module-local registered types: +inline type_map ®istered_local_types_cpp() { + static type_map locals{}; + return locals; +} + +/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its +/// `c_str()`. Such strings objects have a long storage duration -- the internal strings are only +/// cleared when the program exits or after interpreter shutdown (when embedding), and so are +/// suitable for c-style strings needed by Python internals (such as PyTypeObject's tp_name). +template +const char *c_str(Args &&...args) { + auto &strings = get_internals().static_strings; + strings.emplace_front(std::forward(args)...); + return strings.front().c_str(); +} + +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; +} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/pybind11/include/pybind11/detail/typeid.h b/pybind11/include/pybind11/detail/typeid.h new file mode 100644 index 0000000..6f36aab --- /dev/null +++ b/pybind11/include/pybind11/detail/typeid.h @@ -0,0 +1,53 @@ +/* + pybind11/detail/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) +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_NAMESPACE) diff --git a/pybind11/include/pybind11/eigen.h b/pybind11/include/pybind11/eigen.h new file mode 100644 index 0000000..d963d96 --- /dev/null +++ b/pybind11/include/pybind11/eigen.h @@ -0,0 +1,607 @@ +/* + 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" +# ifdef __clang__ +// Eigen generates a bunch of implicit-copy-constructor-is-deprecated warnings with -Wdeprecated +// under Clang, so disable that warning here: +# pragma GCC diagnostic ignored "-Wdeprecated" +# endif +# if __GNUC__ >= 7 +# pragma GCC diagnostic ignored "-Wint-in-bool-context" +# endif +#endif + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +# pragma warning(disable: 4996) // warning C4996: std::unary_negate is deprecated in C++17 +#endif + +#include +#include + +// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit +// move constructors that break things. We could detect this an explicitly copy, but an extra copy +// of matrices seems highly undesirable. +static_assert(EIGEN_VERSION_AT_LEAST(3,2,7), "Eigen support in pybind11 requires Eigen >= 3.2.7"); + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides: +using EigenDStride = Eigen::Stride; +template using EigenDRef = Eigen::Ref; +template using EigenDMap = Eigen::Map; + +NAMESPACE_BEGIN(detail) + +#if EIGEN_VERSION_AT_LEAST(3,3,0) +using EigenIndex = Eigen::Index; +#else +using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE; +#endif + +// Matches Eigen::Map, Eigen::Ref, blocks, etc: +template using is_eigen_dense_map = all_of, std::is_base_of, T>>; +template using is_eigen_mutable_map = std::is_base_of, T>; +template using is_eigen_dense_plain = all_of>, is_template_base_of>; +template using is_eigen_sparse = 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_other = all_of< + is_template_base_of, + negation, is_eigen_dense_plain, is_eigen_sparse>> +>; + +// Captures numpy/eigen conformability status (returned by EigenProps::conformable()): +template struct EigenConformable { + bool conformable = false; + EigenIndex rows = 0, cols = 0; + EigenDStride stride{0, 0}; // Only valid if negativestrides is false! + bool negativestrides = false; // If true, do not use stride! + + EigenConformable(bool fits = false) : conformable{fits} {} + // Matrix type: + EigenConformable(EigenIndex r, EigenIndex c, + EigenIndex rstride, EigenIndex cstride) : + conformable{true}, rows{r}, cols{c} { + // TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity. http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747 + if (rstride < 0 || cstride < 0) { + negativestrides = true; + } else { + stride = {EigenRowMajor ? rstride : cstride /* outer stride */, + EigenRowMajor ? cstride : rstride /* inner stride */ }; + } + } + // Vector type: + EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride) + : EigenConformable(r, c, r == 1 ? c*stride : stride, c == 1 ? r : r*stride) {} + + template bool stride_compatible() const { + // To have compatible strides, we need (on both dimensions) one of fully dynamic strides, + // matching strides, or a dimension size of 1 (in which case the stride value is irrelevant) + return + !negativestrides && + (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner() || + (EigenRowMajor ? cols : rows) == 1) && + (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer() || + (EigenRowMajor ? rows : cols) == 1); + } + operator bool() const { return conformable; } +}; + +template struct eigen_extract_stride { using type = Type; }; +template +struct eigen_extract_stride> { using type = StrideType; }; +template +struct eigen_extract_stride> { using type = StrideType; }; + +// Helper struct for extracting information from an Eigen type +template struct EigenProps { + using Type = Type_; + using Scalar = typename Type::Scalar; + using StrideType = typename eigen_extract_stride::type; + static constexpr EigenIndex + rows = Type::RowsAtCompileTime, + cols = Type::ColsAtCompileTime, + size = Type::SizeAtCompileTime; + static constexpr bool + row_major = Type::IsRowMajor, + vector = Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1 + fixed_rows = rows != Eigen::Dynamic, + fixed_cols = cols != Eigen::Dynamic, + fixed = size != Eigen::Dynamic, // Fully-fixed size + dynamic = !fixed_rows && !fixed_cols; // Fully-dynamic size + + template using if_zero = std::integral_constant; + static constexpr EigenIndex inner_stride = if_zero::value, + outer_stride = if_zero::value; + static constexpr bool dynamic_stride = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic; + static constexpr bool requires_row_major = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1; + static constexpr bool requires_col_major = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1; + + // Takes an input array and determines whether we can make it fit into the Eigen type. If + // the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector + // (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type). + static EigenConformable conformable(const array &a) { + const auto dims = a.ndim(); + if (dims < 1 || dims > 2) + return false; + + if (dims == 2) { // Matrix type: require exact match (or dynamic) + + EigenIndex + np_rows = a.shape(0), + np_cols = a.shape(1), + np_rstride = a.strides(0) / static_cast(sizeof(Scalar)), + np_cstride = a.strides(1) / static_cast(sizeof(Scalar)); + if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols)) + return false; + + return {np_rows, np_cols, np_rstride, np_cstride}; + } + + // Otherwise we're storing an n-vector. Only one of the strides will be used, but whichever + // is used, we want the (single) numpy stride value. + const EigenIndex n = a.shape(0), + stride = a.strides(0) / static_cast(sizeof(Scalar)); + + if (vector) { // Eigen type is a compile-time vector + if (fixed && size != n) + return false; // Vector size mismatch + return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride}; + } + else if (fixed) { + // The type has a fixed size, but is not a vector: abort + return false; + } + else if (fixed_cols) { + // Since this isn't a vector, cols must be != 1. We allow this only if it exactly + // equals the number of elements (rows is Dynamic, and so 1 row is allowed). + if (cols != n) return false; + return {1, n, stride}; + } + else { + // Otherwise it's either fully dynamic, or column dynamic; both become a column vector + if (fixed_rows && rows != n) return false; + return {n, 1, stride}; + } + } + + static constexpr bool show_writeable = is_eigen_dense_map::value && is_eigen_mutable_map::value; + static constexpr bool show_order = is_eigen_dense_map::value; + static constexpr bool show_c_contiguous = show_order && requires_row_major; + static constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major; + + static constexpr auto descriptor = + _("numpy.ndarray[") + npy_format_descriptor::name + + _("[") + _(_<(size_t) rows>(), _("m")) + + _(", ") + _(_<(size_t) cols>(), _("n")) + + _("]") + + // For a reference type (e.g. Ref) we have other constraints that might need to be + // satisfied: writeable=True (for a mutable reference), and, depending on the map's stride + // options, possibly f_contiguous or c_contiguous. We include them in the descriptor output + // to provide some hint as to why a TypeError is occurring (otherwise it can be confusing to + // see that a function accepts a 'numpy.ndarray[float64[3,2]]' and an error message that you + // *gave* a numpy.ndarray of the right type and dimensions. + _(", flags.writeable", "") + + _(", flags.c_contiguous", "") + + _(", flags.f_contiguous", "") + + _("]"); +}; + +// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data, +// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array. +template handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) { + constexpr ssize_t elem_size = sizeof(typename props::Scalar); + array a; + if (props::vector) + a = array({ src.size() }, { elem_size * src.innerStride() }, src.data(), base); + else + a = array({ src.rows(), src.cols() }, { elem_size * src.rowStride(), elem_size * src.colStride() }, + src.data(), base); + + if (!writeable) + array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_; + + return a.release(); +} + +// Takes an lvalue ref to some Eigen type and a (python) base object, creating a numpy array that +// reference the Eigen object's data with `base` as the python-registered base class (if omitted, +// the base will be set to None, and lifetime management is up to the caller). The numpy array is +// non-writeable if the given type is const. +template +handle eigen_ref_array(Type &src, handle parent = none()) { + // none here is to get past array's should-we-copy detection, which currently always + // copies when there is no base. Setting the base to None should be harmless. + return eigen_array_cast(src, parent, !std::is_const::value); +} + +// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a numpy +// array that references the encapsulated data with a python-side reference to the capsule to tie +// its destruction to that of any dependent python objects. Const-ness is determined by whether or +// not the Type of the pointer given is const. +template ::value>> +handle eigen_encapsulate(Type *src) { + capsule base(src, [](void *o) { delete static_cast(o); }); + return eigen_ref_array(*src, base); +} + +// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense +// types. +template +struct type_caster::value>> { + using Scalar = typename Type::Scalar; + using props = EigenProps; + + bool load(handle src, bool convert) { + // If we're in no-convert mode, only load if given an array of the correct type + if (!convert && !isinstance>(src)) + return false; + + // Coerce into an array, but don't do type conversion yet; the copy below handles it. + auto buf = array::ensure(src); + + if (!buf) + return false; + + auto dims = buf.ndim(); + if (dims < 1 || dims > 2) + return false; + + auto fits = props::conformable(buf); + if (!fits) + return false; + + // Allocate the new type, then build a numpy reference into it + value = Type(fits.rows, fits.cols); + auto ref = reinterpret_steal(eigen_ref_array(value)); + if (dims == 1) ref = ref.squeeze(); + else if (ref.ndim() == 1) buf = buf.squeeze(); + + int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr()); + + if (result < 0) { // Copy failed! + PyErr_Clear(); + return false; + } + + return true; + } + +private: + + // Cast implementation + template + static handle cast_impl(CType *src, return_value_policy policy, handle parent) { + switch (policy) { + case return_value_policy::take_ownership: + case return_value_policy::automatic: + return eigen_encapsulate(src); + case return_value_policy::move: + return eigen_encapsulate(new CType(std::move(*src))); + case return_value_policy::copy: + return eigen_array_cast(*src); + case return_value_policy::reference: + case return_value_policy::automatic_reference: + return eigen_ref_array(*src); + case return_value_policy::reference_internal: + return eigen_ref_array(*src, parent); + default: + throw cast_error("unhandled return_value_policy: should not happen!"); + }; + } + +public: + + // Normal returned non-reference, non-const value: + static handle cast(Type &&src, return_value_policy /* policy */, handle parent) { + return cast_impl(&src, return_value_policy::move, parent); + } + // If you return a non-reference const, we mark the numpy array readonly: + static handle cast(const Type &&src, return_value_policy /* policy */, handle parent) { + return cast_impl(&src, return_value_policy::move, parent); + } + // lvalue reference return; default (automatic) becomes copy + static handle cast(Type &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_impl(&src, policy, parent); + } + // const lvalue reference return; default (automatic) becomes copy + static handle cast(const Type &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); + } + // non-const pointer return + static handle cast(Type *src, return_value_policy policy, handle parent) { + return cast_impl(src, policy, parent); + } + // const pointer return + static handle cast(const Type *src, return_value_policy policy, handle parent) { + return cast_impl(src, policy, parent); + } + + static constexpr auto name = props::descriptor; + + operator Type*() { return &value; } + operator Type&() { return value; } + operator Type&&() && { return std::move(value); } + template using cast_op_type = movable_cast_op_type; + +private: + Type value; +}; + +// Base class for casting reference/map/block/etc. objects back to python. +template struct eigen_map_caster { +private: + using props = EigenProps; + +public: + + // Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has + // to stay around), but we'll allow it under the assumption that you know what you're doing (and + // have an appropriate keep_alive in place). We return a numpy array pointing directly at the + // ref's data (The numpy array ends up read-only if the ref was to a const matrix type.) Note + // that this means you need to ensure you don't destroy the object in some other way (e.g. with + // an appropriate keep_alive, or with a reference to a statically allocated matrix). + static handle cast(const MapType &src, return_value_policy policy, handle parent) { + switch (policy) { + case return_value_policy::copy: + return eigen_array_cast(src); + case return_value_policy::reference_internal: + return eigen_array_cast(src, parent, is_eigen_mutable_map::value); + case return_value_policy::reference: + case return_value_policy::automatic: + case return_value_policy::automatic_reference: + return eigen_array_cast(src, none(), is_eigen_mutable_map::value); + default: + // move, take_ownership don't make any sense for a ref/map: + pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type"); + } + } + + static constexpr auto name = props::descriptor; + + // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return + // types but not bound arguments). We still provide them (with an explicitly delete) so that + // you end up here if you try anyway. + bool load(handle, bool) = delete; + operator MapType() = delete; + template using cast_op_type = MapType; +}; + +// We can return any map-like object (but can only load Refs, specialized next): +template struct type_caster::value>> + : eigen_map_caster {}; + +// Loader for Ref<...> arguments. See the documentation for info on how to make this work without +// copying (it requires some extra effort in many cases). +template +struct type_caster< + Eigen::Ref, + enable_if_t>::value> +> : public eigen_map_caster> { +private: + using Type = Eigen::Ref; + using props = EigenProps; + using Scalar = typename props::Scalar; + using MapType = Eigen::Map; + using Array = array_t; + static constexpr bool need_writeable = is_eigen_mutable_map::value; + // Delay construction (these have no default constructor) + std::unique_ptr map; + std::unique_ptr ref; + // Our array. When possible, this is just a numpy array pointing to the source data, but + // sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an incompatible + // layout, or is an array of a type that needs to be converted). Using a numpy temporary + // (rather than an Eigen temporary) saves an extra copy when we need both type conversion and + // storage order conversion. (Note that we refuse to use this temporary copy when loading an + // argument for a Ref with M non-const, i.e. a read-write reference). + Array copy_or_ref; +public: + bool load(handle src, bool convert) { + // First check whether what we have is already an array of the right type. If not, we can't + // avoid a copy (because the copy is also going to do type conversion). + bool need_copy = !isinstance(src); + + EigenConformable fits; + if (!need_copy) { + // We don't need a converting copy, but we also need to check whether the strides are + // compatible with the Ref's stride requirements + Array aref = reinterpret_borrow(src); + + if (aref && (!need_writeable || aref.writeable())) { + fits = props::conformable(aref); + if (!fits) return false; // Incompatible dimensions + if (!fits.template stride_compatible()) + need_copy = true; + else + copy_or_ref = std::move(aref); + } + else { + need_copy = true; + } + } + + if (need_copy) { + // We need to copy: If we need a mutable reference, or we're not supposed to convert + // (either because we're in the no-convert overload pass, or because we're explicitly + // instructed not to copy (via `py::arg().noconvert()`) we have to fail loading. + if (!convert || need_writeable) return false; + + Array copy = Array::ensure(src); + if (!copy) return false; + fits = props::conformable(copy); + if (!fits || !fits.template stride_compatible()) + return false; + copy_or_ref = std::move(copy); + loader_life_support::add_patient(copy_or_ref); + } + + ref.reset(); + map.reset(new MapType(data(copy_or_ref), fits.rows, fits.cols, make_stride(fits.stride.outer(), fits.stride.inner()))); + ref.reset(new Type(*map)); + + return true; + } + + operator Type*() { return ref.get(); } + operator Type&() { return *ref; } + template using cast_op_type = pybind11::detail::cast_op_type<_T>; + +private: + template ::value, int> = 0> + Scalar *data(Array &a) { return a.mutable_data(); } + + template ::value, int> = 0> + const Scalar *data(Array &a) { return a.data(); } + + // Attempt to figure out a constructor of `Stride` that will work. + // If both strides are fixed, use a default constructor: + template using stride_ctor_default = bool_constant< + S::InnerStrideAtCompileTime != Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic && + std::is_default_constructible::value>; + // Otherwise, if there is a two-index constructor, assume it is (outer,inner) like + // Eigen::Stride, and use it: + template using stride_ctor_dual = bool_constant< + !stride_ctor_default::value && std::is_constructible::value>; + // Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use + // it (passing whichever stride is dynamic). + template using stride_ctor_outer = bool_constant< + !any_of, stride_ctor_dual>::value && + S::OuterStrideAtCompileTime == Eigen::Dynamic && S::InnerStrideAtCompileTime != Eigen::Dynamic && + std::is_constructible::value>; + template using stride_ctor_inner = bool_constant< + !any_of, stride_ctor_dual>::value && + S::InnerStrideAtCompileTime == Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic && + std::is_constructible::value>; + + template ::value, int> = 0> + static S make_stride(EigenIndex, EigenIndex) { return S(); } + template ::value, int> = 0> + static S make_stride(EigenIndex outer, EigenIndex inner) { return S(outer, inner); } + template ::value, int> = 0> + static S make_stride(EigenIndex outer, EigenIndex) { return S(outer); } + template ::value, int> = 0> + static S make_stride(EigenIndex, EigenIndex inner) { return S(inner); } + +}; + +// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not +// EigenDense (i.e. they don't have a data(), at least not with the usual matrix layout). +// 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>> { +protected: + using Matrix = Eigen::Matrix; + using props = EigenProps; +public: + static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) { + handle h = eigen_encapsulate(new Matrix(src)); + return h; + } + static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); } + + static constexpr auto name = props::descriptor; + + // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return + // types but not bound arguments). We still provide them (with an explicitly delete) so that + // you end up here if you try anyway. + bool load(handle, bool) = delete; + operator Type() = delete; + template using cast_op_type = Type; +}; + +template +struct type_caster::value>> { + typedef typename Type::Scalar Scalar; + typedef remove_reference_t().outerIndexPtr())> StorageIndex; + typedef typename Type::Index Index; + static constexpr bool rowMajor = Type::IsRowMajor; + + 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().is(matrix_type)) { + 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(src.nonZeros(), src.valuePtr()); + array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr()); + array innerIndices(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::IsRowMajor) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[") + + npy_format_descriptor::name + _("]")); +}; + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) + +#if defined(__GNUG__) || defined(__clang__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif diff --git a/pybind11/include/pybind11/embed.h b/pybind11/include/pybind11/embed.h new file mode 100644 index 0000000..7265588 --- /dev/null +++ b/pybind11/include/pybind11/embed.h @@ -0,0 +1,200 @@ +/* + pybind11/embed.h: Support for embedding the interpreter + + Copyright (c) 2017 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 "eval.h" + +#if defined(PYPY_VERSION) +# error Embedding the interpreter is not supported with PyPy +#endif + +#if PY_MAJOR_VERSION >= 3 +# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + extern "C" PyObject *pybind11_init_impl_##name() { \ + return pybind11_init_wrapper_##name(); \ + } +#else +# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + extern "C" void pybind11_init_impl_##name() { \ + pybind11_init_wrapper_##name(); \ + } +#endif + +/** \rst + Add a new module to the table of builtins for the interpreter. Must be + defined in global scope. The first macro parameter is the name of the + module (without quotes). The second parameter is the variable which will + be used as the interface to add functions and classes to the module. + + .. code-block:: cpp + + PYBIND11_EMBEDDED_MODULE(example, m) { + // ... initialize functions and classes here + m.def("foo", []() { + return "Hello, World!"; + }); + } + \endrst */ +#define PYBIND11_EMBEDDED_MODULE(name, variable) \ + static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \ + static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \ + auto m = pybind11::module(PYBIND11_TOSTRING(name)); \ + try { \ + PYBIND11_CONCAT(pybind11_init_, name)(m); \ + return m.ptr(); \ + } catch (pybind11::error_already_set &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } catch (const std::exception &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } \ + } \ + PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + pybind11::detail::embedded_module name(PYBIND11_TOSTRING(name), \ + PYBIND11_CONCAT(pybind11_init_impl_, name)); \ + void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable) + + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks. +struct embedded_module { +#if PY_MAJOR_VERSION >= 3 + using init_t = PyObject *(*)(); +#else + using init_t = void (*)(); +#endif + embedded_module(const char *name, init_t init) { + if (Py_IsInitialized()) + pybind11_fail("Can't add new modules after the interpreter has been initialized"); + + auto result = PyImport_AppendInittab(name, init); + if (result == -1) + pybind11_fail("Insufficient memory to add a new module"); + } +}; + +NAMESPACE_END(detail) + +/** \rst + Initialize the Python interpreter. No other pybind11 or CPython API functions can be + called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The + optional parameter can be used to skip the registration of signal handlers (see the + `Python documentation`_ for details). Calling this function again after the interpreter + has already been initialized is a fatal error. + + If initializing the Python interpreter fails, then the program is terminated. (This + is controlled by the CPython runtime and is an exception to pybind11's normal behavior + of throwing exceptions on errors.) + + .. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx + \endrst */ +inline void initialize_interpreter(bool init_signal_handlers = true) { + if (Py_IsInitialized()) + pybind11_fail("The interpreter is already running"); + + Py_InitializeEx(init_signal_handlers ? 1 : 0); + + // Make .py files in the working directory available by default + module::import("sys").attr("path").cast().append("."); +} + +/** \rst + Shut down the Python interpreter. No pybind11 or CPython API functions can be called + after this. In addition, pybind11 objects must not outlive the interpreter: + + .. code-block:: cpp + + { // BAD + py::initialize_interpreter(); + auto hello = py::str("Hello, World!"); + py::finalize_interpreter(); + } // <-- BOOM, hello's destructor is called after interpreter shutdown + + { // GOOD + py::initialize_interpreter(); + { // scoped + auto hello = py::str("Hello, World!"); + } // <-- OK, hello is cleaned up properly + py::finalize_interpreter(); + } + + { // BETTER + py::scoped_interpreter guard{}; + auto hello = py::str("Hello, World!"); + } + + .. warning:: + + The interpreter can be restarted by calling `initialize_interpreter` again. + Modules created using pybind11 can be safely re-initialized. However, Python + itself cannot completely unload binary extension modules and there are several + caveats with regard to interpreter restarting. All the details can be found + in the CPython documentation. In short, not all interpreter memory may be + freed, either due to reference cycles or user-created global data. + + \endrst */ +inline void finalize_interpreter() { + handle builtins(PyEval_GetBuiltins()); + const char *id = PYBIND11_INTERNALS_ID; + + // Get the internals pointer (without creating it if it doesn't exist). It's possible for the + // internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()` + // during destruction), so we get the pointer-pointer here and check it after Py_Finalize(). + detail::internals **internals_ptr_ptr = detail::get_internals_pp(); + // It could also be stashed in builtins, so look there too: + if (builtins.contains(id) && isinstance(builtins[id])) + internals_ptr_ptr = capsule(builtins[id]); + + Py_Finalize(); + + if (internals_ptr_ptr) { + delete *internals_ptr_ptr; + *internals_ptr_ptr = nullptr; + } +} + +/** \rst + Scope guard version of `initialize_interpreter` and `finalize_interpreter`. + This a move-only guard and only a single instance can exist. + + .. code-block:: cpp + + #include + + int main() { + py::scoped_interpreter guard{}; + py::print(Hello, World!); + } // <-- interpreter shutdown + \endrst */ +class scoped_interpreter { +public: + scoped_interpreter(bool init_signal_handlers = true) { + initialize_interpreter(init_signal_handlers); + } + + scoped_interpreter(const scoped_interpreter &) = delete; + scoped_interpreter(scoped_interpreter &&other) noexcept { other.is_valid = false; } + scoped_interpreter &operator=(const scoped_interpreter &) = delete; + scoped_interpreter &operator=(scoped_interpreter &&) = delete; + + ~scoped_interpreter() { + if (is_valid) + finalize_interpreter(); + } + +private: + bool is_valid = true; +}; + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/pybind11/include/pybind11/eval.h b/pybind11/include/pybind11/eval.h new file mode 100644 index 0000000..ea85ba1 --- /dev/null +++ b/pybind11/include/pybind11/eval.h @@ -0,0 +1,117 @@ +/* + 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 + +#include "pybind11.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +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 = globals(), object local = object()) { + 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(const char (&s)[N], object global = globals(), object local = object()) { + /* Support raw string literals by removing common leading whitespace */ + auto expr = (s[0] == '\n') ? str(module::import("textwrap").attr("dedent")(s)) + : str(s); + return eval(expr, global, local); +} + +inline void exec(str expr, object global = globals(), object local = object()) { + eval(expr, global, local); +} + +template +void exec(const char (&s)[N], object global = globals(), object local = object()) { + eval(s, global, local); +} + +template +object eval_file(str fname, object global = globals(), object local = object()) { + 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!"); + } + +#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION) + PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(), + local.ptr()); + (void) closeFile; +#else + PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), + local.ptr(), closeFile); +#endif + + if (!result) + throw error_already_set(); + return reinterpret_steal(result); +} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/pybind11/include/pybind11/functional.h b/pybind11/include/pybind11/functional.h new file mode 100644 index 0000000..9cdf21f --- /dev/null +++ b/pybind11/include/pybind11/functional.h @@ -0,0 +1,83 @@ +/* + 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) +NAMESPACE_BEGIN(detail) + +template +struct type_caster> { + using type = std::function; + using retval_type = conditional_t::value, void_type, Return>; + using function_type = Return (*) (Args...); + +public: + bool load(handle src, bool convert) { + if (src.is_none()) { + // Defer accepting None to other overloads (if we aren't in convert mode): + if (!convert) return false; + return true; + } + + if (!isinstance(src)) + return false; + + auto func = reinterpret_borrow(src); + + /* + 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 (auto cfunc = func.cpp_function()) { + auto c = reinterpret_borrow(PyCFunction_GET_SELF(cfunc.ptr())); + auto rec = (function_record *) c; + + if (rec && rec->is_stateless && + same_type(typeid(function_type), *reinterpret_cast(rec->data[1]))) { + struct capture { function_type f; }; + value = ((capture *) &rec->data)->f; + return true; + } + } + + value = [func](Args... args) -> Return { + gil_scoped_acquire acq; + object retval(func(std::forward(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[[") + concat(make_caster::name...) + _("], ") + + make_caster::name + _("]")); +}; + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/pybind11/include/pybind11/iostream.h b/pybind11/include/pybind11/iostream.h new file mode 100644 index 0000000..182e8ee --- /dev/null +++ b/pybind11/include/pybind11/iostream.h @@ -0,0 +1,200 @@ +/* + pybind11/iostream.h -- Tools to assist with redirecting cout and cerr to Python + + Copyright (c) 2017 Henry F. Schreiner + + 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 + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +// Buffer that writes to Python instead of C++ +class pythonbuf : public std::streambuf { +private: + using traits_type = std::streambuf::traits_type; + + char d_buffer[1024]; + object pywrite; + object pyflush; + + int overflow(int c) { + if (!traits_type::eq_int_type(c, traits_type::eof())) { + *pptr() = traits_type::to_char_type(c); + pbump(1); + } + return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof(); + } + + int sync() { + if (pbase() != pptr()) { + // This subtraction cannot be negative, so dropping the sign + str line(pbase(), static_cast(pptr() - pbase())); + + pywrite(line); + pyflush(); + + setp(pbase(), epptr()); + } + return 0; + } + +public: + pythonbuf(object pyostream) + : pywrite(pyostream.attr("write")), + pyflush(pyostream.attr("flush")) { + setp(d_buffer, d_buffer + sizeof(d_buffer) - 1); + } + + /// Sync before destroy + ~pythonbuf() { + sync(); + } +}; + +NAMESPACE_END(detail) + + +/** \rst + This a move-only guard that redirects output. + + .. code-block:: cpp + + #include + + ... + + { + py::scoped_ostream_redirect output; + std::cout << "Hello, World!"; // Python stdout + } // <-- return std::cout to normal + + You can explicitly pass the c++ stream and the python object, + for example to guard stderr instead. + + .. code-block:: cpp + + { + py::scoped_ostream_redirect output{std::cerr, py::module::import("sys").attr("stderr")}; + std::cerr << "Hello, World!"; + } + \endrst */ +class scoped_ostream_redirect { +protected: + std::streambuf *old; + std::ostream &costream; + detail::pythonbuf buffer; + +public: + scoped_ostream_redirect( + std::ostream &costream = std::cout, + object pyostream = module::import("sys").attr("stdout")) + : costream(costream), buffer(pyostream) { + old = costream.rdbuf(&buffer); + } + + ~scoped_ostream_redirect() { + costream.rdbuf(old); + } + + scoped_ostream_redirect(const scoped_ostream_redirect &) = delete; + scoped_ostream_redirect(scoped_ostream_redirect &&other) = default; + scoped_ostream_redirect &operator=(const scoped_ostream_redirect &) = delete; + scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete; +}; + + +/** \rst + Like `scoped_ostream_redirect`, but redirects cerr by default. This class + is provided primary to make ``py::call_guard`` easier to make. + + .. code-block:: cpp + + m.def("noisy_func", &noisy_func, + py::call_guard()); + +\endrst */ +class scoped_estream_redirect : public scoped_ostream_redirect { +public: + scoped_estream_redirect( + std::ostream &costream = std::cerr, + object pyostream = module::import("sys").attr("stderr")) + : scoped_ostream_redirect(costream,pyostream) {} +}; + + +NAMESPACE_BEGIN(detail) + +// Class to redirect output as a context manager. C++ backend. +class OstreamRedirect { + bool do_stdout_; + bool do_stderr_; + std::unique_ptr redirect_stdout; + std::unique_ptr redirect_stderr; + +public: + OstreamRedirect(bool do_stdout = true, bool do_stderr = true) + : do_stdout_(do_stdout), do_stderr_(do_stderr) {} + + void enter() { + if (do_stdout_) + redirect_stdout.reset(new scoped_ostream_redirect()); + if (do_stderr_) + redirect_stderr.reset(new scoped_estream_redirect()); + } + + void exit() { + redirect_stdout.reset(); + redirect_stderr.reset(); + } +}; + +NAMESPACE_END(detail) + +/** \rst + This is a helper function to add a C++ redirect context manager to Python + instead of using a C++ guard. To use it, add the following to your binding code: + + .. code-block:: cpp + + #include + + ... + + py::add_ostream_redirect(m, "ostream_redirect"); + + You now have a Python context manager that redirects your output: + + .. code-block:: python + + with m.ostream_redirect(): + m.print_to_cout_function() + + This manager can optionally be told which streams to operate on: + + .. code-block:: python + + with m.ostream_redirect(stdout=true, stderr=true): + m.noisy_function_with_error_printing() + + \endrst */ +inline class_ add_ostream_redirect(module m, std::string name = "ostream_redirect") { + return class_(m, name.c_str(), module_local()) + .def(init(), arg("stdout")=true, arg("stderr")=true) + .def("__enter__", &detail::OstreamRedirect::enter) + .def("__exit__", [](detail::OstreamRedirect &self_, args) { self_.exit(); }); +} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/pybind11/include/pybind11/numpy.h b/pybind11/include/pybind11/numpy.h new file mode 100644 index 0000000..bdc3a5d --- /dev/null +++ b/pybind11/include/pybind11/numpy.h @@ -0,0 +1,1607 @@ +/* + 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 / ssize_t / Py_intptr_t business down to just ssize_t for all size + and dimension types (e.g. shape, strides, indexing), instead of inflicting this + upon the library user. */ +static_assert(sizeof(ssize_t) == sizeof(Py_intptr_t), "ssize_t != Py_intptr_t"); + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +class array; // Forward declaration + +NAMESPACE_BEGIN(detail) +template struct npy_format_descriptor; + +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_ARRAY_C_CONTIGUOUS_ = 0x0001, + NPY_ARRAY_F_CONTIGUOUS_ = 0x0002, + NPY_ARRAY_OWNDATA_ = 0x0004, + NPY_ARRAY_FORCECAST_ = 0x0010, + NPY_ARRAY_ENSUREARRAY_ = 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_ + }; + + typedef struct { + Py_intptr_t *ptr; + int len; + } PyArray_Dims; + + 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_); + } + + unsigned int (*PyArray_GetNDArrayCFeatureVersion_)(); + PyObject *(*PyArray_DescrFromType_)(int); + PyObject *(*PyArray_NewFromDescr_) + (PyTypeObject *, PyObject *, int, Py_intptr_t *, + Py_intptr_t *, void *, int, PyObject *); + PyObject *(*PyArray_DescrNewFromType_)(int); + int (*PyArray_CopyInto_)(PyObject *, PyObject *); + 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 *); + int (*PyArray_SetBaseObject_)(PyObject *, PyObject *); + PyObject* (*PyArray_Resize_)(PyObject*, PyArray_Dims*, int, int); +private: + enum functions { + API_PyArray_GetNDArrayCFeatureVersion = 211, + 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_Resize = 80, + API_PyArray_CopyInto = 82, + 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, + API_PyArray_SetBaseObject = 282 + }; + + 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_GetNDArrayCFeatureVersion); + if (api.PyArray_GetNDArrayCFeatureVersion_() < 0x7) + pybind11_fail("pybind11 numpy support requires numpy >= 1.7.0"); + 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_Resize); + DECL_NPY_API(PyArray_CopyInto); + 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); + DECL_NPY_API(PyArray_SetBaseObject); +#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)); +} + +template struct is_std_array : std::false_type { }; +template struct is_std_array> : std::true_type { }; +template struct is_complex : std::false_type { }; +template struct is_complex> : std::true_type { }; + +template struct array_info_scalar { + typedef T type; + static constexpr bool is_array = false; + static constexpr bool is_empty = false; + static constexpr auto extents = _(""); + static void append_extents(list& /* shape */) { } +}; +// Computes underlying type and a comma-separated list of extents for array +// types (any mix of std::array and built-in arrays). An array of char is +// treated as scalar because it gets special handling. +template struct array_info : array_info_scalar { }; +template struct array_info> { + using type = typename array_info::type; + static constexpr bool is_array = true; + static constexpr bool is_empty = (N == 0) || array_info::is_empty; + static constexpr size_t extent = N; + + // appends the extents to shape + static void append_extents(list& shape) { + shape.append(N); + array_info::append_extents(shape); + } + + static constexpr auto extents = _::is_array>( + concat(_(), array_info::extents), _() + ); +}; +// For numpy we have special handling for arrays of characters, so we don't include +// the size in the array extents. +template struct array_info : array_info_scalar { }; +template struct array_info> : array_info_scalar> { }; +template struct array_info : array_info> { }; +template using remove_all_extents_t = typename array_info::type; + +template using is_pod_struct = all_of< + std::is_standard_layout, // since we're accessing directly in memory we need a standard layout type +#if !defined(__GNUG__) || defined(_LIBCPP_VERSION) || defined(_GLIBCXX_USE_CXX11_ABI) + // _GLIBCXX_USE_CXX11_ABI indicates that we're using libstdc++ from GCC 5 or newer, independent + // of the actual compiler (Clang can also use libstdc++, but it always defines __GNUC__ == 4). + std::is_trivially_copyable, +#else + // GCC 4 doesn't implement is_trivially_copyable, so approximate it + std::is_trivially_destructible, + satisfies_any_of, +#endif + satisfies_none_of +>; + +template ssize_t byte_offset_unsafe(const Strides &) { return 0; } +template +ssize_t byte_offset_unsafe(const Strides &strides, ssize_t i, Ix... index) { + return i * strides[Dim] + byte_offset_unsafe(strides, index...); +} + +/** + * Proxy class providing unsafe, unchecked const access to array data. This is constructed through + * the `unchecked()` method of `array` or the `unchecked()` method of `array_t`. `Dims` + * will be -1 for dimensions determined at runtime. + */ +template +class unchecked_reference { +protected: + static constexpr bool Dynamic = Dims < 0; + const unsigned char *data_; + // Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to + // make large performance gains on big, nested loops, but requires compile-time dimensions + conditional_t> + shape_, strides_; + const ssize_t dims_; + + friend class pybind11::array; + // Constructor for compile-time dimensions: + template + unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t) + : data_{reinterpret_cast(data)}, dims_{Dims} { + for (size_t i = 0; i < (size_t) dims_; i++) { + shape_[i] = shape[i]; + strides_[i] = strides[i]; + } + } + // Constructor for runtime dimensions: + template + unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t dims) + : data_{reinterpret_cast(data)}, shape_{shape}, strides_{strides}, dims_{dims} {} + +public: + /** + * Unchecked const reference access to data at the given indices. For a compile-time known + * number of dimensions, this requires the correct number of arguments; for run-time + * dimensionality, this is not checked (and so is up to the caller to use safely). + */ + template const T &operator()(Ix... index) const { + static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic, + "Invalid number of indices for unchecked array reference"); + return *reinterpret_cast(data_ + byte_offset_unsafe(strides_, ssize_t(index)...)); + } + /** + * Unchecked const reference access to data; this operator only participates if the reference + * is to a 1-dimensional array. When present, this is exactly equivalent to `obj(index)`. + */ + template > + const T &operator[](ssize_t index) const { return operator()(index); } + + /// Pointer access to the data at the given indices. + template const T *data(Ix... ix) const { return &operator()(ssize_t(ix)...); } + + /// Returns the item size, i.e. sizeof(T) + constexpr static ssize_t itemsize() { return sizeof(T); } + + /// Returns the shape (i.e. size) of dimension `dim` + ssize_t shape(ssize_t dim) const { return shape_[(size_t) dim]; } + + /// Returns the number of dimensions of the array + ssize_t ndim() const { return dims_; } + + /// Returns the total number of elements in the referenced array, i.e. the product of the shapes + template + enable_if_t size() const { + return std::accumulate(shape_.begin(), shape_.end(), (ssize_t) 1, std::multiplies()); + } + template + enable_if_t size() const { + return std::accumulate(shape_, shape_ + ndim(), (ssize_t) 1, std::multiplies()); + } + + /// Returns the total number of bytes used by the referenced data. Note that the actual span in + /// memory may be larger if the referenced array has non-contiguous strides (e.g. for a slice). + ssize_t nbytes() const { + return size() * itemsize(); + } +}; + +template +class unchecked_mutable_reference : public unchecked_reference { + friend class pybind11::array; + using ConstBase = unchecked_reference; + using ConstBase::ConstBase; + using ConstBase::Dynamic; +public: + /// Mutable, unchecked access to data at the given indices. + template T& operator()(Ix... index) { + static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic, + "Invalid number of indices for unchecked array reference"); + return const_cast(ConstBase::operator()(index...)); + } + /** + * Mutable, unchecked access data at the given index; this operator only participates if the + * reference is to a 1-dimensional array (or has runtime dimensions). When present, this is + * exactly equivalent to `obj(index)`. + */ + template > + T &operator[](ssize_t index) { return operator()(index); } + + /// Mutable pointer access to the data at the given indices. + template T *mutable_data(Ix... ix) { return &operator()(ssize_t(ix)...); } +}; + +template +struct type_caster> { + static_assert(Dim == 0 && Dim > 0 /* always fail */, "unchecked array proxy object is not castable"); +}; +template +struct type_caster> : type_caster> {}; + +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, ssize_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.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. + ssize_t itemsize() const { + return 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(ssize_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_ARRAY_C_CONTIGUOUS_, + f_style = detail::npy_api::NPY_ARRAY_F_CONTIGUOUS_, + forcecast = detail::npy_api::NPY_ARRAY_FORCECAST_ + }; + + array() : array({{0}}, static_cast(nullptr)) {} + + using ShapeContainer = detail::any_container; + using StridesContainer = detail::any_container; + + // Constructs an array taking shape/strides from arbitrary container types + array(const pybind11::dtype &dt, ShapeContainer shape, StridesContainer strides, + const void *ptr = nullptr, handle base = handle()) { + + if (strides->empty()) + *strides = c_strides(*shape, dt.itemsize()); + + auto ndim = shape->size(); + if (ndim != 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 ownership 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 &api = detail::npy_api::get(); + auto tmp = reinterpret_steal(api.PyArray_NewFromDescr_( + api.PyArray_Type_, descr.release().ptr(), (int) ndim, shape->data(), strides->data(), + const_cast(ptr), flags, nullptr)); + if (!tmp) + throw error_already_set(); + if (ptr) { + if (base) { + api.PyArray_SetBaseObject_(tmp.ptr(), 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, ShapeContainer shape, const void *ptr = nullptr, handle base = handle()) + : array(dt, std::move(shape), {}, ptr, base) { } + + template ::value && !std::is_same::value>> + array(const pybind11::dtype &dt, T count, const void *ptr = nullptr, handle base = handle()) + : array(dt, {{count}}, ptr, base) { } + + template + array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle()) + : array(pybind11::dtype::of(), std::move(shape), std::move(strides), ptr, base) { } + + template + array(ShapeContainer shape, const T *ptr, handle base = handle()) + : array(std::move(shape), {}, ptr, base) { } + + template + explicit array(ssize_t count, const T *ptr, handle base = handle()) : array({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 + ssize_t size() const { + return std::accumulate(shape(), shape() + ndim(), (ssize_t) 1, std::multiplies()); + } + + /// Byte size of a single element + ssize_t itemsize() const { + return detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize; + } + + /// Total number of bytes + ssize_t nbytes() const { + return size() * itemsize(); + } + + /// Number of dimensions + ssize_t ndim() const { + return 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 ssize_t* shape() const { + return detail::array_proxy(m_ptr)->dimensions; + } + + /// Dimension along a given axis + ssize_t shape(ssize_t dim) const { + if (dim >= ndim()) + fail_dim_check(dim, "invalid axis"); + return shape()[dim]; + } + + /// Strides of the array + const ssize_t* strides() const { + return detail::array_proxy(m_ptr)->strides; + } + + /// Stride along a given axis + ssize_t strides(ssize_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 ssize_t offset_at(Ix... index) const { + if ((ssize_t) sizeof...(index) > ndim()) + fail_dim_check(sizeof...(index), "too many indices for an array"); + return byte_offset(ssize_t(index)...); + } + + ssize_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 ssize_t index_at(Ix... index) const { + return offset_at(index...) / itemsize(); + } + + /** + * Returns a proxy object that provides access to the array's data without bounds or + * dimensionality checking. Will throw if the array is missing the `writeable` flag. Use with + * care: the array must not be destroyed or reshaped for the duration of the returned object, + * and the caller must take care not to access invalid dimensions or dimension indices. + */ + template detail::unchecked_mutable_reference mutable_unchecked() & { + if (Dims >= 0 && ndim() != Dims) + throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) + + "; expected " + std::to_string(Dims)); + return detail::unchecked_mutable_reference(mutable_data(), shape(), strides(), ndim()); + } + + /** + * Returns a proxy object that provides const access to the array's data without bounds or + * dimensionality checking. Unlike `mutable_unchecked()`, this does not require that the + * underlying array have the `writable` flag. Use with care: the array must not be destroyed or + * reshaped for the duration of the returned object, and the caller must take care not to access + * invalid dimensions or dimension indices. + */ + template detail::unchecked_reference unchecked() const & { + if (Dims >= 0 && ndim() != Dims) + throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) + + "; expected " + std::to_string(Dims)); + return detail::unchecked_reference(data(), shape(), strides(), ndim()); + } + + /// 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)); + } + + /// Resize array to given shape + /// If refcheck is true and more that one reference exist to this array + /// then resize will succeed only if it makes a reshape, i.e. original size doesn't change + void resize(ShapeContainer new_shape, bool refcheck = true) { + detail::npy_api::PyArray_Dims d = { + new_shape->data(), int(new_shape->size()) + }; + // try to resize, set ordering param to -1 cause it's not used anyway + object new_array = reinterpret_steal( + detail::npy_api::get().PyArray_Resize_(m_ptr, &d, int(refcheck), -1) + ); + if (!new_array) throw error_already_set(); + if (isinstance(new_array)) { *this = std::move(new_array); } + } + + /// 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(ssize_t dim, const std::string& msg) const { + throw index_error(msg + ": " + std::to_string(dim) + + " (ndim = " + std::to_string(ndim()) + ")"); + } + + template ssize_t byte_offset(Ix... index) const { + check_dimensions(index...); + return detail::byte_offset_unsafe(strides(), ssize_t(index)...); + } + + void check_writeable() const { + if (!writeable()) + throw std::domain_error("array is not writeable"); + } + + // Default, C-style strides + static std::vector c_strides(const std::vector &shape, ssize_t itemsize) { + auto ndim = shape.size(); + std::vector strides(ndim, itemsize); + if (ndim > 0) + for (size_t i = ndim - 1; i > 0; --i) + strides[i - 1] = strides[i] * shape[i]; + return strides; + } + + // F-style strides; default when constructing an array_t with `ExtraFlags & f_style` + static std::vector f_strides(const std::vector &shape, ssize_t itemsize) { + auto ndim = shape.size(); + std::vector strides(ndim, itemsize); + for (size_t i = 1; i < ndim; ++i) + strides[i] = strides[i - 1] * shape[i - 1]; + return strides; + } + + template void check_dimensions(Ix... index) const { + check_dimensions_impl(ssize_t(0), shape(), ssize_t(index)...); + } + + void check_dimensions_impl(ssize_t, const ssize_t*) const { } + + template void check_dimensions_impl(ssize_t axis, const ssize_t* shape, ssize_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) { + PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array from a nullptr"); + return nullptr; + } + return detail::npy_api::get().PyArray_FromAny_( + ptr, nullptr, 0, 0, detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr); + } +}; + +template class array_t : public array { +private: + struct private_ctor {}; + // Delegating constructor needed when both moving and accessing in the same constructor + array_t(private_ctor, ShapeContainer &&shape, StridesContainer &&strides, const T *ptr, handle base) + : array(std::move(shape), std::move(strides), ptr, base) {} +public: + static_assert(!detail::array_info::is_array, "Array types cannot be used with array_t"); + + using value_type = T; + + array_t() : array(0, static_cast(nullptr)) {} + array_t(handle h, borrowed_t) : array(h, borrowed_t{}) { } + array_t(handle h, stolen_t) : array(h, stolen_t{}) { } + + PYBIND11_DEPRECATED("Use array_t::ensure() instead") + array_t(handle h, bool is_borrowed) : array(raw_array_t(h.ptr()), stolen_t{}) { + if (!m_ptr) PyErr_Clear(); + if (!is_borrowed) Py_XDECREF(h.ptr()); + } + + array_t(const object &o) : array(raw_array_t(o.ptr()), stolen_t{}) { + if (!m_ptr) throw error_already_set(); + } + + explicit array_t(const buffer_info& info) : array(info) { } + + array_t(ShapeContainer shape, StridesContainer strides, const T *ptr = nullptr, handle base = handle()) + : array(std::move(shape), std::move(strides), ptr, base) { } + + explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle()) + : array_t(private_ctor{}, std::move(shape), + ExtraFlags & f_style ? f_strides(*shape, itemsize()) : c_strides(*shape, itemsize()), + ptr, base) { } + + explicit array_t(size_t count, const T *ptr = nullptr, handle base = handle()) + : array({count}, {}, ptr, base) { } + + constexpr ssize_t itemsize() const { + return sizeof(T); + } + + template ssize_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(ssize_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(ssize_t(index)...) / itemsize()); + } + + /** + * Returns a proxy object that provides access to the array's data without bounds or + * dimensionality checking. Will throw if the array is missing the `writeable` flag. Use with + * care: the array must not be destroyed or reshaped for the duration of the returned object, + * and the caller must take care not to access invalid dimensions or dimension indices. + */ + template detail::unchecked_mutable_reference mutable_unchecked() & { + return array::mutable_unchecked(); + } + + /** + * Returns a proxy object that provides const access to the array's data without bounds or + * dimensionality checking. Unlike `unchecked()`, this does not require that the underlying + * array have the `writable` flag. Use with care: the array must not be destroyed or reshaped + * for the duration of the returned object, and the caller must take care not to access invalid + * dimensions or dimension indices. + */ + template detail::unchecked_reference unchecked() const & { + return array::unchecked(); + } + + /// Ensure that the argument is a NumPy array of the correct dtype (and if not, try to convert + /// it). 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) { + PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array_t from a nullptr"); + return nullptr; + } + return detail::npy_api::get().PyArray_FromAny_( + ptr, dtype::of().release().ptr(), 0, 0, + detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | 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(); + } +}; + +template +struct format_descriptor::is_array>> { + static std::string format() { + using namespace detail; + static constexpr auto extents = _("(") + array_info::extents + _(")"); + return extents.text + format_descriptor>::format(); + } +}; + +NAMESPACE_BEGIN(detail) +template +struct pyobject_caster> { + using type = array_t; + + bool load(handle src, bool convert) { + if (!convert && !type::check_(src)) + return false; + 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 compare_buffer_info::value>> { + static bool compare(const buffer_info& b) { + return npy_api::get().PyArray_EquivTypes_(dtype::of().ptr(), dtype(b).ptr()); + } +}; + +template +struct npy_format_descriptor_name; + +template +struct npy_format_descriptor_name::value>> { + static constexpr auto name = _::value>( + _("bool"), _::value>("int", "uint") + _() + ); +}; + +template +struct npy_format_descriptor_name::value>> { + static constexpr auto name = _::value || std::is_same::value>( + _("float") + _(), _("longdouble") + ); +}; + +template +struct npy_format_descriptor_name::value>> { + static constexpr auto name = _::value + || std::is_same::value>( + _("complex") + _(), _("longcomplex") + ); +}; + +template +struct npy_format_descriptor::value>> + : npy_format_descriptor_name { +private: + // NB: the order here must match the one in common.h + constexpr static const int values[15] = { + npy_api::NPY_BOOL_, + 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_, + npy_api::NPY_FLOAT_, npy_api::NPY_DOUBLE_, npy_api::NPY_LONGDOUBLE_, + npy_api::NPY_CFLOAT_, npy_api::NPY_CDOUBLE_, npy_api::NPY_CLONGDOUBLE_ + }; + +public: + static constexpr int value = values[detail::is_fmt_numeric::index]; + + static pybind11::dtype dtype() { + if (auto ptr = npy_api::get().PyArray_DescrFromType_(value)) + return reinterpret_borrow(ptr); + pybind11_fail("Unsupported buffer format!"); + } +}; + +#define PYBIND11_DECL_CHAR_FMT \ + static constexpr auto name = _("S") + _(); \ + static pybind11::dtype dtype() { return pybind11::dtype(std::string("S") + std::to_string(N)); } +template struct npy_format_descriptor { PYBIND11_DECL_CHAR_FMT }; +template struct npy_format_descriptor> { PYBIND11_DECL_CHAR_FMT }; +#undef PYBIND11_DECL_CHAR_FMT + +template struct npy_format_descriptor::is_array>> { +private: + using base_descr = npy_format_descriptor::type>; +public: + static_assert(!array_info::is_empty, "Zero-sized arrays are not supported"); + + static constexpr auto name = _("(") + array_info::extents + _(")") + base_descr::name; + static pybind11::dtype dtype() { + list shape; + array_info::append_extents(shape); + return pybind11::dtype::from_args(pybind11::make_tuple(base_descr::dtype(), shape)); + } +}; + +template struct npy_format_descriptor::value>> { +private: + using base_descr = npy_format_descriptor::type>; +public: + static constexpr auto name = base_descr::name; + static pybind11::dtype dtype() { return base_descr::dtype(); } +}; + +struct field_descriptor { + const char *name; + ssize_t offset; + ssize_t size; + std::string format; + dtype descr; +}; + +inline PYBIND11_NOINLINE void register_structured_dtype( + any_container fields, + const std::type_info& tinfo, ssize_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(std::move(fields)); + std::sort(ordered_fields.begin(), ordered_fields.end(), + [](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; }); + ssize_t offset = 0; + std::ostringstream oss; + // mark the structure as unaligned with '^', because numpy and C++ don't + // always agree about alignment (particularly for complex), and we're + // explicitly listing all our padding. This depends on none of the fields + // overriding the endianness. Putting the ^ in front of individual fields + // isn't guaranteed to work due to https://github.com/numpy/numpy/issues/9049 + oss << "^T{"; + for (auto& field : ordered_fields) { + if (field.offset > offset) + oss << (field.offset - offset) << 'x'; + 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 { + static_assert(is_pod_struct::value, "Attempt to use a non-POD or unimplemented POD type as a numpy dtype"); + + static constexpr auto name = make_caster::name; + + 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(any_container fields) { + register_structured_dtype(std::move(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; + } +}; + +#ifdef __CLION_IDE__ // replace heavy macro with dummy code for the IDE (doesn't affect code) +# define PYBIND11_NUMPY_DTYPE(Type, ...) ((void)0) +# define PYBIND11_NUMPY_DTYPE_EX(Type, ...) ((void)0) +#else + +#define PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, Name) \ + ::pybind11::detail::field_descriptor { \ + Name, offsetof(T, Field), sizeof(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 \ + (::std::vector<::pybind11::detail::field_descriptor> \ + {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 \ + (::std::vector<::pybind11::detail::field_descriptor> \ + {PYBIND11_MAP2_LIST (PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)}) + +#endif // __CLION_IDE__ + +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 container_type& 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 container_type &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] = 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 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 container_type &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 = *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; +}; + +enum class broadcast_trivial { non_trivial, c_trivial, f_trivial }; + +// Populates the shape and number of dimensions for the set of buffers. Returns a broadcast_trivial +// enum value indicating whether the broadcast is "trivial"--that is, has each buffer being either a +// singleton or a full-size, C-contiguous (`c_trivial`) or Fortran-contiguous (`f_trivial`) storage +// buffer; returns `non_trivial` otherwise. +template +broadcast_trivial broadcast(const std::array &buffers, ssize_t &ndim, std::vector &shape) { + ndim = std::accumulate(buffers.begin(), buffers.end(), ssize_t(0), [](ssize_t res, const buffer_info &buf) { + return std::max(res, buf.ndim); + }); + + shape.clear(); + shape.resize((size_t) ndim, 1); + + // Figure out the output size, and make sure all input arrays conform (i.e. are either size 1 or + // the full size). + for (size_t i = 0; i < N; ++i) { + auto res_iter = shape.rbegin(); + auto end = buffers[i].shape.rend(); + for (auto shape_iter = buffers[i].shape.rbegin(); shape_iter != end; ++shape_iter, ++res_iter) { + const auto &dim_size_in = *shape_iter; + auto &dim_size_out = *res_iter; + + // Each input dimension can either be 1 or `n`, but `n` values must match across buffers + if (dim_size_out == 1) + dim_size_out = dim_size_in; + else if (dim_size_in != 1 && dim_size_in != dim_size_out) + pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!"); + } + } + + bool trivial_broadcast_c = true; + bool trivial_broadcast_f = true; + for (size_t i = 0; i < N && (trivial_broadcast_c || trivial_broadcast_f); ++i) { + if (buffers[i].size == 1) + continue; + + // Require the same number of dimensions: + if (buffers[i].ndim != ndim) + return broadcast_trivial::non_trivial; + + // Require all dimensions be full-size: + if (!std::equal(buffers[i].shape.cbegin(), buffers[i].shape.cend(), shape.cbegin())) + return broadcast_trivial::non_trivial; + + // Check for C contiguity (but only if previous inputs were also C contiguous) + if (trivial_broadcast_c) { + ssize_t expect_stride = buffers[i].itemsize; + auto end = buffers[i].shape.crend(); + for (auto shape_iter = buffers[i].shape.crbegin(), stride_iter = buffers[i].strides.crbegin(); + trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) { + if (expect_stride == *stride_iter) + expect_stride *= *shape_iter; + else + trivial_broadcast_c = false; + } + } + + // Check for Fortran contiguity (if previous inputs were also F contiguous) + if (trivial_broadcast_f) { + ssize_t expect_stride = buffers[i].itemsize; + auto end = buffers[i].shape.cend(); + for (auto shape_iter = buffers[i].shape.cbegin(), stride_iter = buffers[i].strides.cbegin(); + trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) { + if (expect_stride == *stride_iter) + expect_stride *= *shape_iter; + else + trivial_broadcast_f = false; + } + } + } + + return + trivial_broadcast_c ? broadcast_trivial::c_trivial : + trivial_broadcast_f ? broadcast_trivial::f_trivial : + broadcast_trivial::non_trivial; +} + +template +struct vectorize_arg { + static_assert(!std::is_rvalue_reference::value, "Functions with rvalue reference arguments cannot be vectorized"); + // The wrapped function gets called with this type: + using call_type = remove_reference_t; + // Is this a vectorized argument? + static constexpr bool vectorize = + satisfies_any_of::value && + satisfies_none_of::value && + (!std::is_reference::value || + (std::is_lvalue_reference::value && std::is_const::value)); + // Accept this type: an array for vectorized types, otherwise the type as-is: + using type = conditional_t, array::forcecast>, T>; +}; + +template +struct vectorize_helper { +private: + static constexpr size_t N = sizeof...(Args); + static constexpr size_t NVectorized = constexpr_sum(vectorize_arg::vectorize...); + static_assert(NVectorized >= 1, + "pybind11::vectorize(...) requires a function with at least one vectorizable argument"); + +public: + template + explicit vectorize_helper(T &&f) : f(std::forward(f)) { } + + object operator()(typename vectorize_arg::type... args) { + return run(args..., + make_index_sequence(), + select_indices::vectorize...>(), + make_index_sequence()); + } + +private: + remove_reference_t f; + + template using param_n_t = typename pack_element::call_type...>::type; + + // Runs a vectorized function given arguments tuple and three index sequences: + // - Index is the full set of 0 ... (N-1) argument indices; + // - VIndex is the subset of argument indices with vectorized parameters, letting us access + // vectorized arguments (anything not in this sequence is passed through) + // - BIndex is a incremental sequence (beginning at 0) of the same size as VIndex, so that + // we can store vectorized buffer_infos in an array (argument VIndex has its buffer at + // index BIndex in the array). + template object run( + typename vectorize_arg::type &...args, + index_sequence i_seq, index_sequence vi_seq, index_sequence bi_seq) { + + // Pointers to values the function was called with; the vectorized ones set here will start + // out as array_t pointers, but they will be changed them to T pointers before we make + // call the wrapped function. Non-vectorized pointers are left as-is. + std::array params{{ &args... }}; + + // The array of `buffer_info`s of vectorized arguments: + std::array buffers{{ reinterpret_cast(params[VIndex])->request()... }}; + + /* Determine dimensions parameters of output array */ + ssize_t nd = 0; + std::vector shape(0); + auto trivial = broadcast(buffers, nd, shape); + size_t ndim = (size_t) nd; + + size_t size = std::accumulate(shape.begin(), shape.end(), (size_t) 1, std::multiplies()); + + // If all arguments are 0-dimension arrays (i.e. single values) return a plain value (i.e. + // not wrapped in an array). + if (size == 1 && ndim == 0) { + PYBIND11_EXPAND_SIDE_EFFECTS(params[VIndex] = buffers[BIndex].ptr); + return cast(f(*reinterpret_cast *>(params[Index])...)); + } + + array_t result; + if (trivial == broadcast_trivial::f_trivial) result = array_t(shape); + else result = array_t(shape); + + if (size == 0) return result; + + /* Call the function */ + if (trivial == broadcast_trivial::non_trivial) + apply_broadcast(buffers, params, result, i_seq, vi_seq, bi_seq); + else + apply_trivial(buffers, params, result.mutable_data(), size, i_seq, vi_seq, bi_seq); + + return result; + } + + template + void apply_trivial(std::array &buffers, + std::array ¶ms, + Return *out, + size_t size, + index_sequence, index_sequence, index_sequence) { + + // Initialize an array of mutable byte references and sizes with references set to the + // appropriate pointer in `params`; as we iterate, we'll increment each pointer by its size + // (except for singletons, which get an increment of 0). + std::array, NVectorized> vecparams{{ + std::pair( + reinterpret_cast(params[VIndex] = buffers[BIndex].ptr), + buffers[BIndex].size == 1 ? 0 : sizeof(param_n_t) + )... + }}; + + for (size_t i = 0; i < size; ++i) { + out[i] = f(*reinterpret_cast *>(params[Index])...); + for (auto &x : vecparams) x.first += x.second; + } + } + + template + void apply_broadcast(std::array &buffers, + std::array ¶ms, + array_t &output_array, + index_sequence, index_sequence, index_sequence) { + + buffer_info output = output_array.request(); + multi_array_iterator input_iter(buffers, output.shape); + + for (array_iterator iter = array_begin(output), end = array_end(output); + iter != end; + ++iter, ++input_iter) { + PYBIND11_EXPAND_SIDE_EFFECTS(( + params[VIndex] = input_iter.template data() + )); + *iter = f(*reinterpret_cast *>(std::get(params))...); + } + } +}; + +template +vectorize_helper +vectorize_extractor(const Func &f, Return (*) (Args ...)) { + return detail::vectorize_helper(f); +} + +template struct handle_type_name> { + static constexpr auto name = _("numpy.ndarray[") + npy_format_descriptor::name + _("]"); +}; + +NAMESPACE_END(detail) + +// Vanilla pointer vectorizer: +template +detail::vectorize_helper +vectorize(Return (*f) (Args ...)) { + return detail::vectorize_helper(f); +} + +// lambda vectorizer: +template ::value, int> = 0> +auto vectorize(Func &&f) -> decltype( + detail::vectorize_extractor(std::forward(f), (detail::function_signature_t *) nullptr)) { + return detail::vectorize_extractor(std::forward(f), (detail::function_signature_t *) nullptr); +} + +// Vectorize a class method (non-const): +template ())), Return, Class *, Args...>> +Helper vectorize(Return (Class::*f)(Args...)) { + return Helper(std::mem_fn(f)); +} + +// Vectorize a class method (const): +template ())), Return, const Class *, Args...>> +Helper vectorize(Return (Class::*f)(Args...) const) { + return Helper(std::mem_fn(f)); +} + +NAMESPACE_END(PYBIND11_NAMESPACE) + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif diff --git a/pybind11/include/pybind11/operators.h b/pybind11/include/pybind11/operators.h new file mode 100644 index 0000000..b3dd62c --- /dev/null +++ b/pybind11/include/pybind11/operators.h @@ -0,0 +1,168 @@ +/* + 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())) +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +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, op_itruediv, op_hash +}; + +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 { + using Base = typename Class::type; + using L_type = conditional_t::value, Base, L>; + using R_type = conditional_t::value, Base, R>; + using op = op_impl; + cl.def(op::name(), &op::execute, is_operator(), extra...); + #if PY_MAJOR_VERSION < 3 + if (id == op_truediv || id == op_itruediv) + cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__", + &op::execute, is_operator(), extra...); + #endif + } + template void execute_cast(Class &cl, const Extra&... extra) const { + using Base = typename Class::type; + using L_type = conditional_t::value, Base, L>; + using R_type = conditional_t::value, Base, R>; + using op = op_impl; + cl.def(op::name(), &op::execute_cast, is_operator(), extra...); + #if PY_MAJOR_VERSION < 3 + if (id == op_truediv || id == op_itruediv) + cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__", + &op::execute, is_operator(), extra...); + #endif + } +}; + +#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) +PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r) +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(itruediv, 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(hash, hash, std::hash()(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_NAMESPACE) + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif diff --git a/pybind11/include/pybind11/options.h b/pybind11/include/pybind11/options.h new file mode 100644 index 0000000..cc1e1f6 --- /dev/null +++ b/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 "detail/common.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +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_NAMESPACE) diff --git a/pybind11/include/pybind11/pybind11.h b/pybind11/include/pybind11/pybind11.h new file mode 100644 index 0000000..7fa0f0e --- /dev/null +++ b/pybind11/include/pybind11/pybind11.h @@ -0,0 +1,2094 @@ +/* + 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(__INTEL_COMPILER) +# pragma warning push +# pragma warning disable 68 // integer conversion resulted in a change of sign +# pragma warning disable 186 // pointless comparison of unsigned integer with zero +# pragma warning disable 878 // incompatible exception specifications +# pragma warning disable 1334 // the "template" keyword used for syntactic disambiguation may only be used within a template +# pragma warning disable 1682 // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem) +# pragma warning disable 1786 // function "strdup" was declared deprecated +# pragma warning disable 1875 // offsetof applied to non-POD (Plain Old Data) types is nonstandard +# pragma warning disable 2196 // warning #2196: routine is both "inline" and "noinline" +#elif 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(__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" +# if __GNUC__ >= 7 +# pragma GCC diagnostic ignored "-Wnoexcept-type" +# endif +#endif + +#include "attr.h" +#include "options.h" +#include "detail/class.h" +#include "detail/init.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object +class cpp_function : public function { +public: + cpp_function() { } + cpp_function(std::nullptr_t) { } + + /// 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 ::value>> + cpp_function(Func &&f, const Extra&... extra) { + initialize(std::forward(f), + (detail::function_signature_t *) 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) { + using namespace detail; + struct capture { remove_reference_t 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 = [](function_record *r) { ((capture *) &r->data)->~capture(); }; + } else { + rec->data[0] = new capture { std::forward(f) }; + rec->free_data = [](function_record *r) { delete ((capture *) r->data[0]); }; + } + + /* Type casters for the function arguments and return value */ + using cast_in = argument_loader; + using cast_out = make_caster< + conditional_t::value, void_type, Return> + >; + + static_assert(expected_num_args(sizeof...(Args), cast_in::has_args, cast_in::has_kwargs), + "The number of argument annotations does not match the number of function arguments"); + + /* Dispatch code which converts function arguments and performs the actual function call */ + rec->impl = [](function_call &call) -> handle { + cast_in args_converter; + + /* Try to cast the function arguments into the C++ domain */ + if (!args_converter.load_args(call)) + return PYBIND11_TRY_NEXT_OVERLOAD; + + /* Invoke call policy pre-call hook */ + process_attributes::precall(call); + + /* Get a pointer to the capture object */ + auto data = (sizeof(capture) <= sizeof(call.func.data) + ? &call.func.data : call.func.data[0]); + capture *cap = const_cast(reinterpret_cast(data)); + + /* Override policy for rvalues -- usually to enforce rvp::move on an rvalue */ + return_value_policy policy = return_value_policy_override::policy(call.func.policy); + + /* Function scope guard -- defaults to the compile-to-nothing `void_type` */ + using Guard = extract_guard_t; + + /* Perform the function call */ + handle result = cast_out::cast( + std::move(args_converter).template call(cap->f), policy, call.parent); + + /* Invoke call policy post-call hook */ + process_attributes::postcall(call, result); + + return result; + }; + + /* Process any user-provided function attributes */ + process_attributes::init(extra..., rec); + + /* Generate a readable signature describing the function's arguments and return value types */ + static constexpr auto signature = _("(") + cast_in::arg_names + _(") -> ") + cast_out::name; + PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types(); + + /* Register the function with Python from generic (non-templated) code */ + initialize_generic(rec, signature.text, types.data(), 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] = const_cast(reinterpret_cast(&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()); + } + + rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__"); + +#if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING) + if (rec->is_constructor && !rec->is_new_style_constructor) { + const auto class_name = std::string(((PyTypeObject *) rec->scope.ptr())->tp_name); + const auto func_name = std::string(rec->name); + PyErr_WarnEx( + PyExc_FutureWarning, + ("pybind11-bound class '" + class_name + "' is using an old-style " + "placement-new '" + func_name + "' which has been deprecated. See " + "the upgrade guide in pybind11's docs. This message is only visible " + "when compiled in debug mode.").c_str(), 0 + ); + } +#endif + + /* Generate a proper function signature */ + std::string signature; + size_t type_index = 0, arg_index = 0; + for (auto *pc = text; *pc != '\0'; ++pc) { + const auto c = *pc; + + if (c == '{') { + // Write arg name for everything except *args and **kwargs. + if (*(pc + 1) == '*') + continue; + + if (arg_index < rec->args.size() && rec->args[arg_index].name) { + 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 += ": "; + } else if (c == '}') { + // Write default value if available. + 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)) { + handle th((PyObject *) tinfo->type); + signature += + th.attr("__module__").cast() + "." + + th.attr("__qualname__").cast(); // Python 3.3+, but we backport it to earlier versions + } else if (rec->is_new_style_constructor && arg_index == 0) { + // A new-style `__init__` takes `self` as `value_and_holder`. + // Rewrite it to the proper class type. + signature += + rec->scope.attr("__module__").cast() + "." + + rec->scope.attr("__qualname__").cast(); + } else { + std::string tname(t->name()); + detail::clean_type_id(tname); + signature += tname; + } + } else { + signature += c; + } + } + if (arg_index != args || types[type_index] != nullptr) + pybind11_fail("Internal error while parsing type signature (2)"); + +#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->nargs = (std::uint16_t) args; + + if (rec->sibling && PYBIND11_INSTANCE_METHOD_CHECK(rec->sibling.ptr())) + rec->sibling = PYBIND11_INSTANCE_METHOD_GET_FUNCTION(rec->sibling.ptr()); + + detail::function_record *chain = nullptr, *chain_start = rec; + if (rec->sibling) { + if (PyCFunction_Check(rec->sibling.ptr())) { + auto rec_capsule = reinterpret_borrow(PyCFunction_GET_SELF(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.is(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(); + std::memset(rec->def, 0, sizeof(PyMethodDef)); + rec->def->ml_name = rec->name; + rec->def->ml_meth = reinterpret_cast(reinterpret_cast(*dispatcher)); + rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS; + + capsule rec_capsule(rec, [](void *ptr) { + destruct((detail::function_record *) ptr); + }); + + 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; + if (chain->is_method != rec->is_method) + pybind11_fail("overloading a method with both static and instance methods is not supported; " + #if defined(NDEBUG) + "compile in debug mode for more details" + #else + "error while attempting to bind " + std::string(rec->is_method ? "instance" : "static") + " method " + + std::string(pybind11::str(rec->scope.attr("__name__"))) + "." + std::string(rec->name) + signature + #endif + ); + 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 + bool first_user_def = true; + for (auto it = chain_start; it != nullptr; it = it->next) { + if (options::show_function_signatures()) { + if (index > 0) signatures += "\n"; + 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 we're appending another docstring, and aren't printing function signatures, we + // need to append a newline first: + if (!options::show_function_signatures()) { + if (first_user_def) first_user_def = false; + else signatures += "\n"; + } + if (options::show_function_signatures()) signatures += "\n"; + signatures += it->doc; + if (options::show_function_signatures()) signatures += "\n"; + } + } + + /* Install docstring */ + PyCFunctionObject *func = (PyCFunctionObject *) m_ptr; + if (func->m_ml->ml_doc) + std::free(const_cast(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(const_cast(arg.name)); + std::free(const_cast(arg.descr)); + arg.value.dec_ref(); + } + if (rec->def) { + std::free(const_cast(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_in, PyObject *kwargs_in) { + using namespace detail; + + /* Iterator over the list of potentially admissible overloads */ + const function_record *overloads = (function_record *) PyCapsule_GetPointer(self, nullptr), + *it = overloads; + + /* Need to know how many arguments + keyword arguments there are to pick the right overload */ + const size_t n_args_in = (size_t) PyTuple_GET_SIZE(args_in); + + handle parent = n_args_in > 0 ? PyTuple_GET_ITEM(args_in, 0) : nullptr, + result = PYBIND11_TRY_NEXT_OVERLOAD; + + auto self_value_and_holder = value_and_holder(); + if (overloads->is_constructor) { + const auto tinfo = get_type_info((PyTypeObject *) overloads->scope.ptr()); + const auto pi = reinterpret_cast(parent.ptr()); + self_value_and_holder = pi->get_value_and_holder(tinfo, false); + + if (!self_value_and_holder.type || !self_value_and_holder.inst) { + PyErr_SetString(PyExc_TypeError, "__init__(self, ...) called with invalid `self` argument"); + return nullptr; + } + + // If this value is already registered it must mean __init__ is invoked multiple times; + // we really can't support that in C++, so just ignore the second __init__. + if (self_value_and_holder.instance_registered()) + return none().release().ptr(); + } + + try { + // We do this in two passes: in the first pass, we load arguments with `convert=false`; + // in the second, we allow conversion (except for arguments with an explicit + // py::arg().noconvert()). This lets us prefer calls without conversion, with + // conversion as a fallback. + std::vector second_pass; + + // However, if there are no overloads, we can just skip the no-convert pass entirely + const bool overloaded = it != nullptr && it->next != nullptr; + + for (; it != nullptr; it = it->next) { + + /* For each overload: + 1. Copy all positional arguments we were given, also checking to make sure that + named positional arguments weren't *also* specified via kwarg. + 2. If we weren't given enough, try to make up the omitted ones by checking + whether they were provided by a kwarg matching the `py::arg("name")` name. If + so, use it (and remove it from kwargs; if not, see if the function binding + provided a default that we can use. + 3. Ensure that either all keyword arguments were "consumed", or that the function + takes a kwargs argument to accept unconsumed kwargs. + 4. Any positional arguments still left get put into a tuple (for args), and any + leftover kwargs get put into a dict. + 5. Pack everything into a vector; if we have py::args or py::kwargs, they are an + extra tuple or dict at the end of the positional arguments. + 6. Call the function call dispatcher (function_record::impl) + + If one of these fail, move on to the next overload and keep trying until we get a + result other than PYBIND11_TRY_NEXT_OVERLOAD. + */ + + const function_record &func = *it; + size_t pos_args = func.nargs; // Number of positional arguments that we need + if (func.has_args) --pos_args; // (but don't count py::args + if (func.has_kwargs) --pos_args; // or py::kwargs) + + if (!func.has_args && n_args_in > pos_args) + continue; // Too many arguments for this overload + + if (n_args_in < pos_args && func.args.size() < pos_args) + continue; // Not enough arguments given, and not enough defaults to fill in the blanks + + function_call call(func, parent); + + size_t args_to_copy = std::min(pos_args, n_args_in); + size_t args_copied = 0; + + // 0. Inject new-style `self` argument + if (func.is_new_style_constructor) { + // The `value` may have been preallocated by an old-style `__init__` + // if it was a preceding candidate for overload resolution. + if (self_value_and_holder) + self_value_and_holder.type->dealloc(self_value_and_holder); + + call.init_self = PyTuple_GET_ITEM(args_in, 0); + call.args.push_back(reinterpret_cast(&self_value_and_holder)); + call.args_convert.push_back(false); + ++args_copied; + } + + // 1. Copy any position arguments given. + bool bad_arg = false; + for (; args_copied < args_to_copy; ++args_copied) { + const argument_record *arg_rec = args_copied < func.args.size() ? &func.args[args_copied] : nullptr; + if (kwargs_in && arg_rec && arg_rec->name && PyDict_GetItemString(kwargs_in, arg_rec->name)) { + bad_arg = true; + break; + } + + handle arg(PyTuple_GET_ITEM(args_in, args_copied)); + if (arg_rec && !arg_rec->none && arg.is_none()) { + bad_arg = true; + break; + } + call.args.push_back(arg); + call.args_convert.push_back(arg_rec ? arg_rec->convert : true); + } + if (bad_arg) + continue; // Maybe it was meant for another overload (issue #688) + + // We'll need to copy this if we steal some kwargs for defaults + dict kwargs = reinterpret_borrow(kwargs_in); + + // 2. Check kwargs and, failing that, defaults that may help complete the list + if (args_copied < pos_args) { + bool copied_kwargs = false; + + for (; args_copied < pos_args; ++args_copied) { + const auto &arg = func.args[args_copied]; + + handle value; + if (kwargs_in && arg.name) + value = PyDict_GetItemString(kwargs.ptr(), arg.name); + + if (value) { + // Consume a kwargs value + if (!copied_kwargs) { + kwargs = reinterpret_steal(PyDict_Copy(kwargs.ptr())); + copied_kwargs = true; + } + PyDict_DelItemString(kwargs.ptr(), arg.name); + } else if (arg.value) { + value = arg.value; + } + + if (value) { + call.args.push_back(value); + call.args_convert.push_back(arg.convert); + } + else + break; + } + + if (args_copied < pos_args) + continue; // Not enough arguments, defaults, or kwargs to fill the positional arguments + } + + // 3. Check everything was consumed (unless we have a kwargs arg) + if (kwargs && kwargs.size() > 0 && !func.has_kwargs) + continue; // Unconsumed kwargs, but no py::kwargs argument to accept them + + // 4a. If we have a py::args argument, create a new tuple with leftovers + if (func.has_args) { + tuple extra_args; + if (args_to_copy == 0) { + // We didn't copy out any position arguments from the args_in tuple, so we + // can reuse it directly without copying: + extra_args = reinterpret_borrow(args_in); + } else if (args_copied >= n_args_in) { + extra_args = tuple(0); + } else { + size_t args_size = n_args_in - args_copied; + extra_args = tuple(args_size); + for (size_t i = 0; i < args_size; ++i) { + extra_args[i] = PyTuple_GET_ITEM(args_in, args_copied + i); + } + } + call.args.push_back(extra_args); + call.args_convert.push_back(false); + call.args_ref = std::move(extra_args); + } + + // 4b. If we have a py::kwargs, pass on any remaining kwargs + if (func.has_kwargs) { + if (!kwargs.ptr()) + kwargs = dict(); // If we didn't get one, send an empty one + call.args.push_back(kwargs); + call.args_convert.push_back(false); + call.kwargs_ref = std::move(kwargs); + } + + // 5. Put everything in a vector. Not technically step 5, we've been building it + // in `call.args` all along. + #if !defined(NDEBUG) + if (call.args.size() != func.nargs || call.args_convert.size() != func.nargs) + pybind11_fail("Internal error: function call dispatcher inserted wrong number of arguments!"); + #endif + + std::vector second_pass_convert; + if (overloaded) { + // We're in the first no-convert pass, so swap out the conversion flags for a + // set of all-false flags. If the call fails, we'll swap the flags back in for + // the conversion-allowed call below. + second_pass_convert.resize(func.nargs, false); + call.args_convert.swap(second_pass_convert); + } + + // 6. Call the function. + try { + loader_life_support guard{}; + result = func.impl(call); + } catch (reference_cast_error &) { + result = PYBIND11_TRY_NEXT_OVERLOAD; + } + + if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) + break; + + if (overloaded) { + // The (overloaded) call failed; if the call has at least one argument that + // permits conversion (i.e. it hasn't been explicitly specified `.noconvert()`) + // then add this call to the list of second pass overloads to try. + for (size_t i = func.is_method ? 1 : 0; i < pos_args; i++) { + if (second_pass_convert[i]) { + // Found one: swap the converting flags back in and store the call for + // the second pass. + call.args_convert.swap(second_pass_convert); + second_pass.push_back(std::move(call)); + break; + } + } + } + } + + if (overloaded && !second_pass.empty() && result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) { + // The no-conversion pass finished without success, try again with conversion allowed + for (auto &call : second_pass) { + try { + loader_life_support guard{}; + result = call.func.impl(call); + } catch (reference_cast_error &) { + result = PYBIND11_TRY_NEXT_OVERLOAD; + } + + if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) { + // The error reporting logic below expects 'it' to be valid, as it would be + // if we'd encountered this failure in the first-pass loop. + if (!result) + it = &call.func; + 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 = 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; + } + + auto append_note_if_missing_header_is_suspected = [](std::string &msg) { + if (msg.find("std::") != std::string::npos) { + msg += "\n\n" + "Did you forget to `#include `? Or ,\n" + ", , etc. Some automatic\n" + "conversions are optional and require extra headers to be included\n" + "when compiling your pybind11 module."; + } + }; + + 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 (const 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_in); + bool some_args = false; + for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) { + if (!some_args) some_args = true; + else msg += ", "; + msg += pybind11::repr(args_[ti]); + } + if (kwargs_in) { + auto kwargs = reinterpret_borrow(kwargs_in); + if (kwargs.size() > 0) { + if (some_args) msg += "; "; + msg += "kwargs: "; + bool first = true; + for (auto kwarg : kwargs) { + if (first) first = false; + else msg += ", "; + msg += pybind11::str("{}={!r}").format(kwarg.first, kwarg.second); + } + } + } + + append_note_if_missing_header_is_suspected(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; + append_note_if_missing_header_is_suspected(msg); + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return nullptr; + } else { + if (overloads->is_constructor && !self_value_and_holder.holder_constructed()) { + auto *pi = reinterpret_cast(parent.ptr()); + self_value_and_holder.type->init_instance(pi, nullptr); + } + return result.ptr(); + } + } +}; + +/// Wrapper for Python extension modules +class module : public object { +public: + PYBIND11_OBJECT_DEFAULT(module, object, PyModule_Check) + + /// Create a new top-level Python module with the given name and docstring + 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(); + std::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(); + } + + /** \rst + 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`. + \endrst */ + 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; + } + + /** \rst + Create and return a new Python submodule with the given name and docstring. + This also works recursively, i.e. + + .. code-block:: cpp + + py::module m("example", "pybind11 example plugin"); + py::module m2 = m.def_submodule("sub", "A submodule of 'example'"); + py::module m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'"); + \endrst */ + 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; + } + + /// Import and return a module or throws `error_already_set`. + static module import(const char *name) { + PyObject *obj = PyImport_ImportModule(name); + if (!obj) + throw error_already_set(); + return reinterpret_steal(obj); + } + + /// Reload the module or throws `error_already_set`. + void reload() { + PyObject *obj = PyImport_ReloadModule(ptr()); + if (!obj) + throw error_already_set(); + *this = 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, handle obj, bool overwrite = false) { + if (!overwrite && hasattr(*this, name)) + pybind11_fail("Error during initialization: multiple incompatible definitions with name \"" + + std::string(name) + "\""); + + PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */); + } +}; + +/// \ingroup python_builtins +/// Return a dictionary representing the global variables in the current execution frame, +/// or ``__main__.__dict__`` if there is no frame (usually when the interpreter is embedded). +inline dict globals() { + PyObject *p = PyEval_GetGlobals(); + return reinterpret_borrow(p ? p : module::import("__main__").attr("__dict__").ptr()); +} + +NAMESPACE_BEGIN(detail) +/// 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(const type_record &rec) { + if (rec.scope && 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 (rec.module_local ? get_local_type_info(*rec.type) : get_global_type_info(*rec.type)) + pybind11_fail("generic_type: type \"" + std::string(rec.name) + + "\" is already registered!"); + + m_ptr = make_new_python_type(rec); + + /* Register supplemental type information in C++ dict */ + auto *tinfo = new detail::type_info(); + tinfo->type = (PyTypeObject *) m_ptr; + tinfo->cpptype = rec.type; + tinfo->type_size = rec.type_size; + tinfo->type_align = rec.type_align; + tinfo->operator_new = rec.operator_new; + tinfo->holder_size_in_ptrs = size_in_ptrs(rec.holder_size); + tinfo->init_instance = rec.init_instance; + tinfo->dealloc = rec.dealloc; + tinfo->simple_type = true; + tinfo->simple_ancestors = true; + tinfo->default_holder = rec.default_holder; + tinfo->module_local = rec.module_local; + + auto &internals = get_internals(); + auto tindex = std::type_index(*rec.type); + tinfo->direct_conversions = &internals.direct_conversions[tindex]; + if (rec.module_local) + registered_local_types_cpp()[tindex] = tinfo; + else + internals.registered_types_cpp[tindex] = tinfo; + internals.registered_types_py[(PyTypeObject *) m_ptr] = { tinfo }; + + if (rec.bases.size() > 1 || rec.multiple_inheritance) { + mark_parents_nonsimple(tinfo->type); + tinfo->simple_ancestors = false; + } + else if (rec.bases.size() == 1) { + auto parent_tinfo = get_type_info((PyTypeObject *) rec.bases[0].ptr()); + tinfo->simple_ancestors = parent_tinfo->simple_ancestors; + } + + if (rec.module_local) { + // Stash the local typeinfo and loader so that external modules can access it. + tinfo->module_local_load = &type_caster_generic::local_load; + setattr(m_ptr, PYBIND11_MODULE_LOCAL_ID, capsule(tinfo)); + } + } + + /// 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()); + } + } + + void install_buffer_funcs( + buffer_info *(*get_buffer)(PyObject *, void *), + void *get_buffer_data) { + PyHeapTypeObject *type = (PyHeapTypeObject*) m_ptr; + auto tinfo = detail::get_type_info(&type->ht_type); + + if (!type->ht_type.tp_as_buffer) + pybind11_fail( + "To be able to register buffer protocol support for the type '" + + std::string(tinfo->type->tp_name) + + "' the associated class<>(..) invocation must " + "include the pybind11::buffer_protocol() annotation!"); + + tinfo->get_buffer = get_buffer; + tinfo->get_buffer_data = get_buffer_data; + } + + // rec_func must be set for either fget or fset. + void def_property_static_impl(const char *name, + handle fget, handle fset, + detail::function_record *rec_func) { + const auto is_static = rec_func && !(rec_func->is_method && rec_func->scope); + const auto has_doc = rec_func && rec_func->doc && pybind11::options::show_user_defined_docstrings(); + auto property = handle((PyObject *) (is_static ? get_internals().static_property_type + : &PyProperty_Type)); + attr(name) = property(fget.ptr() ? fget : none(), + fset.ptr() ? fset : none(), + /*deleter*/none(), + pybind11::str(has_doc ? rec_func->doc : "")); + } +}; + +/// Set the pointer to operator new if it exists. The cast is needed because it can be overloaded. +template (T::operator new))>> +void set_operator_new(type_record *r) { r->operator_new = &T::operator new; } + +template void set_operator_new(...) { } + +template struct has_operator_delete : std::false_type { }; +template struct has_operator_delete(T::operator delete))>> + : std::true_type { }; +template struct has_operator_delete_size : std::false_type { }; +template struct has_operator_delete_size(T::operator delete))>> + : std::true_type { }; +/// Call class-specific delete if it exists or global otherwise. Can also be an overload set. +template ::value, int> = 0> +void call_operator_delete(T *p, size_t, size_t) { T::operator delete(p); } +template ::value && has_operator_delete_size::value, int> = 0> +void call_operator_delete(T *p, size_t s, size_t) { T::operator delete(p, s); } + +inline void call_operator_delete(void *p, size_t s, size_t a) { + (void)s; (void)a; +#if defined(PYBIND11_CPP17) + if (a > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + ::operator delete(p, s, std::align_val_t(a)); + else + ::operator delete(p, s); +#else + ::operator delete(p); +#endif +} + +NAMESPACE_END(detail) + +/// Given a pointer to a member function, cast it to its `Derived` version. +/// Forward everything else unchanged. +template +auto method_adaptor(F &&f) -> decltype(std::forward(f)) { return std::forward(f); } + +template +auto method_adaptor(Return (Class::*pmf)(Args...)) -> Return (Derived::*)(Args...) { + static_assert(detail::is_accessible_base_of::value, + "Cannot bind an inaccessible base class method; use a lambda definition instead"); + return pmf; +} + +template +auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(Args...) const { + static_assert(detail::is_accessible_base_of::value, + "Cannot bind an inaccessible base class method; use a lambda definition instead"); + return pmf; +} + +template +class class_ : public detail::generic_type { + template using is_holder = detail::is_holder_type; + template using is_subtype = detail::is_strict_base_of; + template using is_base = detail::is_strict_base_of; + // struct instead of using here to help MSVC: + template struct is_valid_class_option : + detail::any_of, is_subtype, is_base> {}; + +public: + using type = type_; + using type_alias = detail::exactly_one_t; + constexpr static bool has_alias = !std::is_void::value; + using holder_type = detail::exactly_one_t, options...>; + + static_assert(detail::all_of...>::value, + "Unknown/invalid class_ template parameters provided"); + + static_assert(!has_alias || std::is_polymorphic::value, + "Cannot use an alias class with a non-polymorphic type"); + + PYBIND11_OBJECT(class_, generic_type, PyType_Check) + + template + class_(handle scope, const char *name, const Extra &... extra) { + using namespace detail; + + // MI can only be specified via class_ template options, not constructor parameters + static_assert( + none_of...>::value || // no base class arguments, or: + ( constexpr_sum(is_pyobject::value...) == 1 && // Exactly one base + constexpr_sum(is_base::value...) == 0 && // no template option bases + none_of...>::value), // no multiple_inheritance attr + "Error: multiple inheritance bases must be specified via class_ template options"); + + type_record record; + record.scope = scope; + record.name = name; + record.type = &typeid(type); + record.type_size = sizeof(conditional_t); + record.type_align = alignof(conditional_t&); + record.holder_size = sizeof(holder_type); + record.init_instance = init_instance; + record.dealloc = dealloc; + record.default_holder = detail::is_instantiation::value; + + set_operator_new(&record); + + /* Register base classes specified via template arguments to class_, if any */ + PYBIND11_EXPAND_SIDE_EFFECTS(add_base(record)); + + /* Process optional arguments, if any */ + process_attributes::init(extra..., &record); + + generic_type::initialize(record); + + if (has_alias) { + auto &instances = record.module_local ? registered_local_types_cpp() : 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(method_adaptor(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) { + static_assert(!std::is_member_function_pointer::value, + "def_static(...) called with a non-static member function pointer"); + 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::initimpl::constructor &init, const Extra&... extra) { + init.execute(*this, extra...); + return *this; + } + + template + class_ &def(const detail::initimpl::alias_constructor &init, const Extra&... extra) { + init.execute(*this, extra...); + return *this; + } + + template + class_ &def(detail::initimpl::factory &&init, const Extra&... extra) { + std::move(init).execute(*this, extra...); + return *this; + } + + template + class_ &def(detail::initimpl::pickle_factory &&pf, const Extra &...extra) { + std::move(pf).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::make_caster caster; + if (!caster.load(obj, false)) + return nullptr; + return new buffer_info(((capture *) ptr)->func(caster)); + }, ptr); + return *this; + } + + template + class_ &def_buffer(Return (Class::*func)(Args...)) { + return def_buffer([func] (type &obj) { return (obj.*func)(); }); + } + + template + class_ &def_buffer(Return (Class::*func)(Args...) const) { + return def_buffer([func] (const type &obj) { return (obj.*func)(); }); + } + + template + class_ &def_readwrite(const char *name, D C::*pm, const Extra&... extra) { + static_assert(std::is_base_of::value, "def_readwrite() requires a class member (or base class member)"); + cpp_function fget([pm](const type &c) -> const D &{ return c.*pm; }, is_method(*this)), + fset([pm](type &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) { + static_assert(std::is_base_of::value, "def_readonly() requires a class member (or base class member)"); + cpp_function fget([pm](const type &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(method_adaptor(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, nullptr, 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, nullptr, extra...); + } + + /// Uses return_value_policy::reference_internal by default + template + class_ &def_property(const char *name, const Getter &fget, const Setter &fset, const Extra& ...extra) { + return def_property(name, fget, cpp_function(method_adaptor(fset)), extra...); + } + template + class_ &def_property(const char *name, const Getter &fget, const cpp_function &fset, const Extra& ...extra) { + return def_property(name, cpp_function(method_adaptor(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); + auto *rec_active = rec_fget; + if (rec_fget) { + 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) { + char *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); + } + if (! rec_active) rec_active = rec_fset; + } + def_property_static_impl(name, fget, fset, rec_active); + return *this; + } + +private: + /// Initialize holder object, variant 1: object derives from enable_shared_from_this + template + static void init_holder(detail::instance *inst, detail::value_and_holder &v_h, + const holder_type * /* unused */, const std::enable_shared_from_this * /* dummy */) { + try { + auto sh = std::dynamic_pointer_cast( + v_h.value_ptr()->shared_from_this()); + if (sh) { + new (std::addressof(v_h.holder())) holder_type(std::move(sh)); + v_h.set_holder_constructed(); + } + } catch (const std::bad_weak_ptr &) {} + + if (!v_h.holder_constructed() && inst->owned) { + new (std::addressof(v_h.holder())) holder_type(v_h.value_ptr()); + v_h.set_holder_constructed(); + } + } + + static void init_holder_from_existing(const detail::value_and_holder &v_h, + const holder_type *holder_ptr, std::true_type /*is_copy_constructible*/) { + new (std::addressof(v_h.holder())) holder_type(*reinterpret_cast(holder_ptr)); + } + + static void init_holder_from_existing(const detail::value_and_holder &v_h, + const holder_type *holder_ptr, std::false_type /*is_copy_constructible*/) { + new (std::addressof(v_h.holder())) holder_type(std::move(*const_cast(holder_ptr))); + } + + /// Initialize holder object, variant 2: try to construct from existing holder object, if possible + static void init_holder(detail::instance *inst, detail::value_and_holder &v_h, + const holder_type *holder_ptr, const void * /* dummy -- not enable_shared_from_this) */) { + if (holder_ptr) { + init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible()); + v_h.set_holder_constructed(); + } else if (inst->owned || detail::always_construct_holder::value) { + new (std::addressof(v_h.holder())) holder_type(v_h.value_ptr()); + v_h.set_holder_constructed(); + } + } + + /// Performs instance initialization including constructing a holder and registering the known + /// instance. Should be called as soon as the `type` value_ptr is set for an instance. Takes an + /// optional pointer to an existing holder to use; if not specified and the instance is + /// `.owned`, a new holder will be constructed to manage the value pointer. + static void init_instance(detail::instance *inst, const void *holder_ptr) { + auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(type))); + if (!v_h.instance_registered()) { + register_instance(inst, v_h.value_ptr(), v_h.type); + v_h.set_instance_registered(); + } + init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr()); + } + + /// Deallocates an instance; via holder, if constructed; otherwise via operator delete. + static void dealloc(detail::value_and_holder &v_h) { + if (v_h.holder_constructed()) { + v_h.holder().~holder_type(); + v_h.set_holder_constructed(false); + } + else { + detail::call_operator_delete(v_h.value_ptr(), + v_h.type->type_size, + v_h.type->type_align + ); + } + v_h.value_ptr() = nullptr; + } + + static detail::function_record *get_function_record(handle h) { + h = detail::get_function(h); + return h ? (detail::function_record *) reinterpret_borrow(PyCFunction_GET_SELF(h.ptr())) + : nullptr; + } +}; + +/// Binds an existing constructor taking arguments Args... +template detail::initimpl::constructor init() { return {}; } +/// Like `init()`, but the instance is always constructed through the alias class (even +/// when not inheriting on the Python side). +template detail::initimpl::alias_constructor init_alias() { return {}; } + +/// Binds a factory function as a constructor +template > +Ret init(Func &&f) { return {std::forward(f)}; } + +/// Dual-argument factory function: the first function is called when no alias is needed, the second +/// when an alias is needed (i.e. due to python-side inheritance). Arguments must be identical. +template > +Ret init(CFunc &&c, AFunc &&a) { + return {std::forward(c), std::forward(a)}; +} + +/// Binds pickling functions `__getstate__` and `__setstate__` and ensures that the type +/// returned by `__getstate__` is the same as the argument accepted by `__setstate__`. +template +detail::initimpl::pickle_factory pickle(GetState &&g, SetState &&s) { + return {std::forward(g), std::forward(s)}; +} + +NAMESPACE_BEGIN(detail) +struct enum_base { + enum_base(handle base, handle parent) : m_base(base), m_parent(parent) { } + + PYBIND11_NOINLINE void init(bool is_arithmetic, bool is_convertible) { + m_base.attr("__entries") = dict(); + auto property = handle((PyObject *) &PyProperty_Type); + auto static_property = handle((PyObject *) get_internals().static_property_type); + + m_base.attr("__repr__") = cpp_function( + [](handle arg) -> str { + handle type = arg.get_type(); + object type_name = type.attr("__name__"); + dict entries = type.attr("__entries"); + for (const auto &kv : entries) { + object other = kv.second[int_(0)]; + if (other.equal(arg)) + return pybind11::str("{}.{}").format(type_name, kv.first); + } + return pybind11::str("{}.???").format(type_name); + }, is_method(m_base) + ); + + m_base.attr("name") = property(cpp_function( + [](handle arg) -> str { + dict entries = arg.get_type().attr("__entries"); + for (const auto &kv : entries) { + if (handle(kv.second[int_(0)]).equal(arg)) + return pybind11::str(kv.first); + } + return "???"; + }, is_method(m_base) + )); + + m_base.attr("__doc__") = static_property(cpp_function( + [](handle arg) -> std::string { + std::string docstring; + dict entries = arg.attr("__entries"); + if (((PyTypeObject *) arg.ptr())->tp_doc) + docstring += std::string(((PyTypeObject *) arg.ptr())->tp_doc) + "\n\n"; + docstring += "Members:"; + for (const auto &kv : entries) { + auto key = std::string(pybind11::str(kv.first)); + auto comment = kv.second[int_(1)]; + docstring += "\n\n " + key; + if (!comment.is_none()) + docstring += " : " + (std::string) pybind11::str(comment); + } + return docstring; + } + ), none(), none(), ""); + + m_base.attr("__members__") = static_property(cpp_function( + [](handle arg) -> dict { + dict entries = arg.attr("__entries"), m; + for (const auto &kv : entries) + m[kv.first] = kv.second[int_(0)]; + return m; + }), none(), none(), "" + ); + + #define PYBIND11_ENUM_OP_STRICT(op, expr, strict_behavior) \ + m_base.attr(op) = cpp_function( \ + [](object a, object b) { \ + if (!a.get_type().is(b.get_type())) \ + strict_behavior; \ + return expr; \ + }, \ + is_method(m_base)) + + #define PYBIND11_ENUM_OP_CONV(op, expr) \ + m_base.attr(op) = cpp_function( \ + [](object a_, object b_) { \ + int_ a(a_), b(b_); \ + return expr; \ + }, \ + is_method(m_base)) + + if (is_convertible) { + PYBIND11_ENUM_OP_CONV("__eq__", !b.is_none() && a.equal(b)); + PYBIND11_ENUM_OP_CONV("__ne__", b.is_none() || !a.equal(b)); + + if (is_arithmetic) { + PYBIND11_ENUM_OP_CONV("__lt__", a < b); + PYBIND11_ENUM_OP_CONV("__gt__", a > b); + PYBIND11_ENUM_OP_CONV("__le__", a <= b); + PYBIND11_ENUM_OP_CONV("__ge__", a >= b); + PYBIND11_ENUM_OP_CONV("__and__", a & b); + PYBIND11_ENUM_OP_CONV("__rand__", a & b); + PYBIND11_ENUM_OP_CONV("__or__", a | b); + PYBIND11_ENUM_OP_CONV("__ror__", a | b); + PYBIND11_ENUM_OP_CONV("__xor__", a ^ b); + PYBIND11_ENUM_OP_CONV("__rxor__", a ^ b); + } + } else { + PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false); + PYBIND11_ENUM_OP_STRICT("__ne__", !int_(a).equal(int_(b)), return true); + + if (is_arithmetic) { + #define PYBIND11_THROW throw type_error("Expected an enumeration of matching type!"); + PYBIND11_ENUM_OP_STRICT("__lt__", int_(a) < int_(b), PYBIND11_THROW); + PYBIND11_ENUM_OP_STRICT("__gt__", int_(a) > int_(b), PYBIND11_THROW); + PYBIND11_ENUM_OP_STRICT("__le__", int_(a) <= int_(b), PYBIND11_THROW); + PYBIND11_ENUM_OP_STRICT("__ge__", int_(a) >= int_(b), PYBIND11_THROW); + #undef PYBIND11_THROW + } + } + + #undef PYBIND11_ENUM_OP_CONV + #undef PYBIND11_ENUM_OP_STRICT + + object getstate = cpp_function( + [](object arg) { return int_(arg); }, is_method(m_base)); + + m_base.attr("__getstate__") = getstate; + m_base.attr("__hash__") = getstate; + } + + PYBIND11_NOINLINE void value(char const* name_, object value, const char *doc = nullptr) { + dict entries = m_base.attr("__entries"); + str name(name_); + if (entries.contains(name)) { + std::string type_name = (std::string) str(m_base.attr("__name__")); + throw value_error(type_name + ": element \"" + std::string(name_) + "\" already exists!"); + } + + entries[name] = std::make_pair(value, doc); + m_base.attr(name) = value; + } + + PYBIND11_NOINLINE void export_values() { + dict entries = m_base.attr("__entries"); + for (const auto &kv : entries) + m_parent.attr(kv.first) = kv.second[int_(0)]; + } + + handle m_base; + handle m_parent; +}; + +NAMESPACE_END(detail) + +/// Binds C++ enumerations and enumeration classes to Python +template class enum_ : public class_ { +public: + using Base = class_; + using Base::def; + using Base::attr; + using Base::def_property_readonly; + using Base::def_property_readonly_static; + using Scalar = typename std::underlying_type::type; + + template + enum_(const handle &scope, const char *name, const Extra&... extra) + : class_(scope, name, extra...), m_base(*this, scope) { + constexpr bool is_arithmetic = detail::any_of...>::value; + constexpr bool is_convertible = std::is_convertible::value; + m_base.init(is_arithmetic, is_convertible); + + def(init([](Scalar i) { return static_cast(i); })); + def("__int__", [](Type value) { return (Scalar) value; }); + #if PY_MAJOR_VERSION < 3 + def("__long__", [](Type value) { return (Scalar) value; }); + #endif + cpp_function setstate( + [](Type &value, Scalar arg) { value = static_cast(arg); }, + is_method(*this)); + attr("__setstate__") = setstate; + } + + /// Export enumeration entries into the parent scope + enum_& export_values() { + m_base.export_values(); + return *this; + } + + /// Add an enumeration entry + enum_& value(char const* name, Type value, const char *doc = nullptr) { + m_base.value(name, pybind11::cast(value, return_value_policy::copy), doc); + return *this; + } + +private: + detail::enum_base m_base; +}; + +NAMESPACE_BEGIN(detail) + + +inline void keep_alive_impl(handle nurse, handle patient) { + 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 */ + + auto tinfo = all_type_info(Py_TYPE(nurse.ptr())); + if (!tinfo.empty()) { + /* It's a pybind-registered type, so we can store the patient in the + * internal list. */ + add_patient(nurse.ptr(), patient.ptr()); + } + else { + /* Fall back to clever approach based on weak references taken from + * Boost.Python. This is not used for pybind-registered types because + * the objects can be destroyed out-of-order in a GC pass. */ + 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(size_t Nurse, size_t Patient, function_call &call, handle ret) { + auto get_arg = [&](size_t n) { + if (n == 0) + return ret; + else if (n == 1 && call.init_self) + return call.init_self; + else if (n <= call.args.size()) + return call.args[n - 1]; + return handle(); + }; + + keep_alive_impl(get_arg(Nurse), get_arg(Patient)); +} + +inline std::pair all_type_info_get_cache(PyTypeObject *type) { + auto res = get_internals().registered_types_py +#ifdef __cpp_lib_unordered_map_try_emplace + .try_emplace(type); +#else + .emplace(type, std::vector()); +#endif + if (res.second) { + // New cache entry created; set up a weak reference to automatically remove it if the type + // gets destroyed: + weakref((PyObject *) type, cpp_function([type](handle wr) { + get_internals().registered_types_py.erase(type); + wr.dec_ref(); + })).release(); + } + + return res; +} + +template +struct iterator_state { + Iterator it; + Sentinel end; + bool first_or_done; +}; + +NAMESPACE_END(detail) + +/// Makes a python iterator from a first and past-the-end C++ InputIterator. +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", pybind11::module_local()) + .def("__iter__", [](state &s) -> state& { return s; }) + .def("__next__", [](state &s) -> ValueType { + if (!s.first_or_done) + ++s.it; + else + s.first_or_done = false; + if (s.it == s.end) { + s.first_or_done = true; + throw stop_iteration(); + } + return *s.it; + }, std::forward(extra)..., Policy); + } + + return cast(state{first, last, true}); +} + +/// Makes an python iterator over the keys (`.first`) of a iterator over pairs from a +/// first and past-the-end InputIterator. +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", pybind11::module_local()) + .def("__iter__", [](state &s) -> state& { return s; }) + .def("__next__", [](state &s) -> KeyType { + if (!s.first_or_done) + ++s.it; + else + s.first_or_done = false; + if (s.it == s.end) { + s.first_or_done = true; + throw stop_iteration(); + } + return (*s.it).first; + }, std::forward(extra)..., Policy); + } + + return cast(state{first, last, true}); +} + +/// Makes an iterator over values of an stl container or other container supporting +/// `std::begin()`/`std::end()` +template iterator make_iterator(Type &value, Extra&&... extra) { + return make_iterator(std::begin(value), std::end(value), extra...); +} + +/// Makes an iterator over the keys (`.first`) of a stl map-like container supporting +/// `std::begin()`/`std::end()` +template iterator make_key_iterator(Type &value, Extra&&... extra) { + return make_key_iterator(std::begin(value), std::end(value), extra...); +} + +template void implicitly_convertible() { + struct set_flag { + bool &flag; + set_flag(bool &flag) : flag(flag) { flag = true; } + ~set_flag() { flag = false; } + }; + auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * { + static bool currently_used = false; + if (currently_used) // implicit conversions are non-reentrant + return nullptr; + set_flag flag_helper(currently_used); + if (!detail::make_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() = default; + 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(const_cast(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); + } +}; + +NAMESPACE_BEGIN(detail) +// Returns a reference to a function-local static exception object used in the simple +// register_exception approach below. (It would be simpler to have the static local variable +// directly in register_exception, but that makes clang <3.5 segfault - issue #1349). +template +exception &get_exception_object() { static exception ex; return ex; } +NAMESPACE_END(detail) + +/** + * 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) { + auto &ex = detail::get_exception_object(); + if (!ex) ex = exception(scope, name, base); + + register_exception_translator([](std::exception_ptr p) { + if (!p) return; + try { + std::rethrow_exception(p); + } catch (const CppException &e) { + detail::get_exception_object()(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) && !defined(PYPY_VERSION) + +/* 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 *) PYBIND11_TLS_GET_VALUE(internals.tstate); + + if (!tstate) { + /* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if + calling from a Python thread). Since we use a different key, this ensures + we don't create a new thread state and deadlock in PyEval_AcquireThread + below. Note we don't save this state with internals.tstate, since we don't + create it we would fail to clear it (its reference count should be > 0). */ + tstate = PyGILState_GetThisThreadState(); + } + + 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; + PYBIND11_TLS_REPLACE_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(); + PYBIND11_TLS_DELETE_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) { + // `get_internals()` must be called here unconditionally in order to initialize + // `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an + // initialization race could occur as multiple threads try `gil_scoped_acquire`. + const auto &internals = detail::get_internals(); + tstate = PyEval_SaveThread(); + if (disassoc) { + auto key = internals.tstate; + PYBIND11_TLS_DELETE_VALUE(key); + } + } + ~gil_scoped_release() { + if (!tstate) + return; + PyEval_RestoreThread(tstate); + if (disassoc) { + auto key = detail::get_internals().tstate; + PYBIND11_TLS_REPLACE_VALUE(key, tstate); + } + } +private: + PyThreadState *tstate; + bool disassoc; +}; +#elif defined(PYPY_VERSION) +class gil_scoped_acquire { + PyGILState_STATE state; +public: + gil_scoped_acquire() { state = PyGILState_Ensure(); } + ~gil_scoped_acquire() { PyGILState_Release(state); } +}; + +class gil_scoped_release { + PyThreadState *state; +public: + gil_scoped_release() { state = PyEval_SaveThread(); } + ~gil_scoped_release() { PyEval_RestoreThread(state); } +}; +#else +class gil_scoped_acquire { }; +class gil_scoped_release { }; +#endif + +error_already_set::~error_already_set() { + if (type) { + error_scope scope; + gil_scoped_acquire gil; + type.release().dec_ref(); + value.release().dec_ref(); + trace.release().dec_ref(); + } +} + +inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) { + handle self = detail::get_object_handle(this_ptr, this_type); + if (!self) + return function(); + handle type = self.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(self, name, function()); + if (overload.is_cpp_function()) { + cache.insert(key); + return function(); + } + + /* Don't call dispatch code if invoked from overridden function. + Unfortunately this doesn't work on PyPy. */ +#if !defined(PYPY_VERSION) + 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 == self.ptr()) + return function(); + } +#else + /* PyPy currently doesn't provide a detailed cpyext emulation of + frame objects, so we have to emulate this using Python. This + is going to be slow..*/ + dict d; d["self"] = self; d["name"] = pybind11::str(name); + PyObject *result = PyRun_String( + "import inspect\n" + "frame = inspect.currentframe()\n" + "if frame is not None:\n" + " frame = frame.f_back\n" + " if frame is not None and str(frame.f_code.co_name) == name and " + "frame.f_code.co_argcount > 0:\n" + " self_caller = frame.f_locals[frame.f_code.co_varnames[0]]\n" + " if self_caller == self:\n" + " self = None\n", + Py_file_input, d.ptr(), d.ptr()); + if (result == nullptr) + throw error_already_set(); + if (d["self"].is_none()) + return function(); + Py_DECREF(result); +#endif + + 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(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__) \ + return cname::fn(__VA_ARGS__) + +#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \ + PYBIND11_OVERLOAD_INT(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__) \ + pybind11::pybind11_fail("Tried to call pure virtual function \"" PYBIND11_STRINGIFY(cname) "::" name "\""); + +#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \ + PYBIND11_OVERLOAD_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__) + +#define PYBIND11_OVERLOAD_PURE(ret_type, cname, fn, ...) \ + PYBIND11_OVERLOAD_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__) + +NAMESPACE_END(PYBIND11_NAMESPACE) + +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +# pragma warning(pop) +#elif defined(__GNUG__) && !defined(__clang__) +# pragma GCC diagnostic pop +#endif diff --git a/pybind11/include/pybind11/pytypes.h b/pybind11/include/pybind11/pytypes.h new file mode 100644 index 0000000..fa5ed7c --- /dev/null +++ b/pybind11/include/pybind11/pytypes.h @@ -0,0 +1,1431 @@ +/* + pybind11/pytypes.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 "detail/common.h" +#include "buffer_info.h" +#include +#include + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +/* 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>; + +/** \rst + A mixin class which adds common functions to `handle`, `object` and various accessors. + The only requirement for `Derived` is to implement ``PyObject *Derived::ptr() const``. +\endrst */ +template +class object_api : public pyobject_tag { + const Derived &derived() const { return static_cast(*this); } + +public: + /** \rst + Return an iterator equivalent to calling ``iter()`` in Python. The object + must be a collection which supports the iteration protocol. + \endrst */ + iterator begin() const; + /// Return a sentinel which ends iteration. + iterator end() const; + + /** \rst + Return an internal functor to invoke the object's sequence protocol. Casting + the returned ``detail::item_accessor`` instance to a `handle` or `object` + subclass causes a corresponding call to ``__getitem__``. Assigning a `handle` + or `object` subclass causes a call to ``__setitem__``. + \endrst */ + item_accessor operator[](handle key) const; + /// See above (the only difference is that they key is provided as a string literal) + item_accessor operator[](const char *key) const; + + /** \rst + Return an internal functor to access the object's attributes. Casting the + returned ``detail::obj_attr_accessor`` instance to a `handle` or `object` + subclass causes a corresponding call to ``getattr``. Assigning a `handle` + or `object` subclass causes a call to ``setattr``. + \endrst */ + obj_attr_accessor attr(handle key) const; + /// See above (the only difference is that they key is provided as a string literal) + str_attr_accessor attr(const char *key) const; + + /** \rst + Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple`` + or ``list`` for a function call. Applying another * to the result yields + ** unpacking, e.g. to unpack a dict as function keyword arguments. + See :ref:`calling_python_functions`. + \endrst */ + args_proxy operator*() const; + + /// Check if the given item is contained within this object, i.e. ``item in obj``. + template bool contains(T &&item) const; + + /** \rst + Assuming the Python object is a function or implements the ``__call__`` + protocol, ``operator()`` invokes the underlying function, passing an + arbitrary set of parameters. The result is returned as a `object` and + may need to be converted back into a Python object using `handle::cast()`. + + When some of the arguments cannot be converted to Python objects, the + function will throw a `cast_error` exception. When the Python function + call fails, a `error_already_set` exception is thrown. + \endrst */ + template + object operator()(Args &&...args) const; + template + PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)") + object call(Args&&... args) const; + + /// Equivalent to ``obj is other`` in Python. + bool is(object_api const& other) const { return derived().ptr() == other.derived().ptr(); } + /// Equivalent to ``obj is None`` in Python. + bool is_none() const { return derived().ptr() == Py_None; } + /// Equivalent to obj == other in Python + bool equal(object_api const &other) const { return rich_compare(other, Py_EQ); } + bool not_equal(object_api const &other) const { return rich_compare(other, Py_NE); } + bool operator<(object_api const &other) const { return rich_compare(other, Py_LT); } + bool operator<=(object_api const &other) const { return rich_compare(other, Py_LE); } + bool operator>(object_api const &other) const { return rich_compare(other, Py_GT); } + bool operator>=(object_api const &other) const { return rich_compare(other, Py_GE); } + + object operator-() const; + object operator~() const; + object operator+(object_api const &other) const; + object operator+=(object_api const &other) const; + object operator-(object_api const &other) const; + object operator-=(object_api const &other) const; + object operator*(object_api const &other) const; + object operator*=(object_api const &other) const; + object operator/(object_api const &other) const; + object operator/=(object_api const &other) const; + object operator|(object_api const &other) const; + object operator|=(object_api const &other) const; + object operator&(object_api const &other) const; + object operator&=(object_api const &other) const; + object operator^(object_api const &other) const; + object operator^=(object_api const &other) const; + object operator<<(object_api const &other) const; + object operator<<=(object_api const &other) const; + object operator>>(object_api const &other) const; + object operator>>=(object_api const &other) const; + + PYBIND11_DEPRECATED("Use py::str(obj) instead") + pybind11::str str() const; + + /// Get or set the object's docstring, i.e. ``obj.__doc__``. + str_attr_accessor doc() const; + + /// Return the object's current reference count + int ref_count() const { return static_cast(Py_REFCNT(derived().ptr())); } + /// Return a handle to the Python type object underlying the instance + handle get_type() const; + +private: + bool rich_compare(object_api const &other, int value) const; +}; + +NAMESPACE_END(detail) + +/** \rst + Holds a reference to a Python object (no reference counting) + + The `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 `object` class inherits from `handle` and adds automatic reference + counting features. +\endrst */ +class handle : public detail::object_api { +public: + /// The default constructor creates a handle with a ``nullptr``-valued pointer + handle() = default; + /// Creates a ``handle`` from the given raw Python object pointer + handle(PyObject *ptr) : m_ptr(ptr) { } // Allow implicit conversion from PyObject* + + /// Return the underlying ``PyObject *`` pointer + PyObject *ptr() const { return m_ptr; } + PyObject *&ptr() { return m_ptr; } + + /** \rst + Manually increase the reference count of the Python object. Usually, it is + preferable to use the `object` class which derives from `handle` and calls + this function automatically. Returns a reference to itself. + \endrst */ + const handle& inc_ref() const & { Py_XINCREF(m_ptr); return *this; } + + /** \rst + Manually decrease the reference count of the Python object. Usually, it is + preferable to use the `object` class which derives from `handle` and calls + this function automatically. Returns a reference to itself. + \endrst */ + const handle& dec_ref() const & { Py_XDECREF(m_ptr); return *this; } + + /** \rst + Attempt to cast the Python object into the given C++ type. A `cast_error` + will be throw upon failure. + \endrst */ + template T cast() const; + /// Return ``true`` when the `handle` wraps a valid Python object + explicit operator bool() const { return m_ptr != nullptr; } + /** \rst + Deprecated: Check that the underlying pointers are the same. + Equivalent to ``obj1 is obj2`` in Python. + \endrst */ + PYBIND11_DEPRECATED("Use obj1.is(obj2) instead") + bool operator==(const handle &h) const { return m_ptr == h.m_ptr; } + PYBIND11_DEPRECATED("Use !obj1.is(obj2) instead") + 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; +}; + +/** \rst + Holds a reference to a Python object (with reference counting) + + Like `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 `handle`, it + optionally increases the object's reference count upon construction, and it + *always* decreases the reference count when the `object` instance goes out of + scope and is destructed. When using `object` instances consistently, it is much + easier to get reference counting right at the first attempt. +\endrst */ +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(); } + /// Copy constructor; always increases the reference count + object(const object &o) : handle(o) { inc_ref(); } + /// Move constructor; steals the object from ``other`` and preserves its reference count + object(object &&other) noexcept { m_ptr = other.m_ptr; other.m_ptr = nullptr; } + /// Destructor; automatically calls `handle::dec_ref()` + ~object() { dec_ref(); } + + /** \rst + 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. + \endrst */ + 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 { }; + struct stolen_t { }; + + 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) { } +}; + +/** \rst + Declare that a `handle` or ``PyObject *`` is a certain type and borrow the reference. + The target type ``T`` must be `object` or one of its derived classes. The function + doesn't do any conversions or checks. It's up to the user to make sure that the + target type is correct. + + .. code-block:: cpp + + PyObject *p = PyList_GetItem(obj, index); + py::object o = reinterpret_borrow(p); + // or + py::tuple t = reinterpret_borrow(p); // <-- `p` must be already be a `tuple` +\endrst */ +template T reinterpret_borrow(handle h) { return {h, object::borrowed_t{}}; } + +/** \rst + Like `reinterpret_borrow`, but steals the reference. + + .. code-block:: cpp + + PyObject *p = PyObject_Str(obj); + py::str s = reinterpret_steal(p); // <-- `p` must be already be a `str` +\endrst */ +template T reinterpret_steal(handle h) { return {h, object::stolen_t{}}; } + +NAMESPACE_BEGIN(detail) +inline std::string error_string(); +NAMESPACE_END(detail) + +/// Fetch and hold an error which was already set in Python. An instance of this is typically +/// thrown to propagate python-side errors back through C++ which can either be caught manually or +/// else falls back to the function dispatcher (which then raises the captured error back to +/// python). +class error_already_set : public std::runtime_error { +public: + /// Constructs a new exception from the current Python error indicator, if any. The current + /// Python error indicator will be cleared. + error_already_set() : std::runtime_error(detail::error_string()) { + PyErr_Fetch(&type.ptr(), &value.ptr(), &trace.ptr()); + } + + error_already_set(const error_already_set &) = default; + error_already_set(error_already_set &&) = default; + + inline ~error_already_set(); + + /// Give the currently-held error back to Python, if any. If there is currently a Python error + /// already set it is cleared first. After this call, the current object no longer stores the + /// error variables (but the `.what()` string is still available). + void restore() { PyErr_Restore(type.release().ptr(), value.release().ptr(), trace.release().ptr()); } + + // Does nothing; provided for backwards compatibility. + PYBIND11_DEPRECATED("Use of error_already_set.clear() is deprecated") + void clear() {} + + /// Check if the currently trapped error type matches the given Python exception class (or a + /// subclass thereof). May also be passed a tuple to search for any exception class matches in + /// the given tuple. + bool matches(handle ex) const { return PyErr_GivenExceptionMatches(ex.ptr(), type.ptr()); } + +private: + object type, value, trace; +}; + +/** \defgroup python_builtins _ + Unless stated otherwise, the following C++ functions behave the same + as their Python counterparts. + */ + +/** \ingroup python_builtins + \rst + Return true if ``obj`` is an instance of ``T``. Type ``T`` must be a subclass of + `object` or a class which was exposed to Python as ``py::class_``. +\endrst */ +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; } + +/// \ingroup python_builtins +/// Return true if ``obj`` is an instance of the ``type``. +inline bool isinstance(handle obj, handle type) { + const auto result = PyObject_IsInstance(obj.ptr(), type.ptr()); + if (result == -1) + throw error_already_set(); + return result != 0; +} + +/// \addtogroup python_builtins +/// @{ +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(); } +} + +inline ssize_t hash(handle obj) { + auto h = PyObject_Hash(obj.ptr()); + if (h == -1) { throw error_already_set(); } + return h; +} + +/// @} python_builtins + +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()); + else +#endif + if (PyMethod_Check(value.ptr())) + value = PyMethod_GET_FUNCTION(value.ptr()); + } + return value; +} + +// Helper aliases/functions to support implicit casting of values given to python accessors/methods. +// When given a pyobject, this simply returns the pyobject as-is; for other C++ type, the value goes +// through pybind11::cast(obj) to convert it to an `object`. +template ::value, int> = 0> +auto object_or_cast(T &&o) -> decltype(std::forward(o)) { return std::forward(o); } +// The following casting version is implemented in cast.h: +template ::value, int> = 0> +object object_or_cast(T &&o); +// Match a PyObject*, which we want to convert directly to handle via its converting constructor +inline handle object_or_cast(PyObject *ptr) { return ptr; } + + +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)) { } + accessor(const accessor &) = default; + accessor(accessor &&) = default; + + // accessor overload required to override default assignment operator (templates are not allowed + // to replace default compiler-generated assignments). + void operator=(const accessor &a) && { std::move(*this).operator=(handle(a)); } + void operator=(const accessor &a) & { operator=(handle(a)); } + + template void operator=(T &&value) && { + Policy::set(obj, key, object_or_cast(std::forward(value))); + } + template void operator=(T &&value) & { + get_cache() = reinterpret_borrow(object_or_cast(std::forward(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_steal(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) + +/// STL iterator template used for tuple, list, sequence and dict +template +class generic_iterator : public Policy { + using It = generic_iterator; + +public: + using difference_type = ssize_t; + using iterator_category = typename Policy::iterator_category; + using value_type = typename Policy::value_type; + using reference = typename Policy::reference; + using pointer = typename Policy::pointer; + + generic_iterator() = default; + generic_iterator(handle seq, ssize_t index) : Policy(seq, index) { } + + reference operator*() const { return Policy::dereference(); } + reference operator[](difference_type n) const { return *(*this + n); } + pointer operator->() const { return **this; } + + It &operator++() { Policy::increment(); return *this; } + It operator++(int) { auto copy = *this; Policy::increment(); return copy; } + It &operator--() { Policy::decrement(); return *this; } + It operator--(int) { auto copy = *this; Policy::decrement(); return copy; } + It &operator+=(difference_type n) { Policy::advance(n); return *this; } + It &operator-=(difference_type n) { Policy::advance(-n); return *this; } + + friend It operator+(const It &a, difference_type n) { auto copy = a; return copy += n; } + friend It operator+(difference_type n, const It &b) { return b + n; } + friend It operator-(const It &a, difference_type n) { auto copy = a; return copy -= n; } + friend difference_type operator-(const It &a, const It &b) { return a.distance_to(b); } + + friend bool operator==(const It &a, const It &b) { return a.equal(b); } + friend bool operator!=(const It &a, const It &b) { return !(a == b); } + friend bool operator< (const It &a, const It &b) { return b - a > 0; } + friend bool operator> (const It &a, const It &b) { return b < a; } + friend bool operator>=(const It &a, const It &b) { return !(a < b); } + friend bool operator<=(const It &a, const It &b) { return !(a > b); } +}; + +NAMESPACE_BEGIN(iterator_policies) +/// Quick proxy class needed to implement ``operator->`` for iterators which can't return pointers +template +struct arrow_proxy { + T value; + + arrow_proxy(T &&value) : value(std::move(value)) { } + T *operator->() const { return &value; } +}; + +/// Lightweight iterator policy using just a simple pointer: see ``PySequence_Fast_ITEMS`` +class sequence_fast_readonly { +protected: + using iterator_category = std::random_access_iterator_tag; + using value_type = handle; + using reference = const handle; + using pointer = arrow_proxy; + + sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) { } + + reference dereference() const { return *ptr; } + void increment() { ++ptr; } + void decrement() { --ptr; } + void advance(ssize_t n) { ptr += n; } + bool equal(const sequence_fast_readonly &b) const { return ptr == b.ptr; } + ssize_t distance_to(const sequence_fast_readonly &b) const { return ptr - b.ptr; } + +private: + PyObject **ptr; +}; + +/// Full read and write access using the sequence protocol: see ``detail::sequence_accessor`` +class sequence_slow_readwrite { +protected: + using iterator_category = std::random_access_iterator_tag; + using value_type = object; + using reference = sequence_accessor; + using pointer = arrow_proxy; + + sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) { } + + reference dereference() const { return {obj, static_cast(index)}; } + void increment() { ++index; } + void decrement() { --index; } + void advance(ssize_t n) { index += n; } + bool equal(const sequence_slow_readwrite &b) const { return index == b.index; } + ssize_t distance_to(const sequence_slow_readwrite &b) const { return index - b.index; } + +private: + handle obj; + ssize_t index; +}; + +/// Python's dictionary protocol permits this to be a forward iterator +class dict_readonly { +protected: + using iterator_category = std::forward_iterator_tag; + using value_type = std::pair; + using reference = const value_type; + using pointer = arrow_proxy; + + dict_readonly() = default; + dict_readonly(handle obj, ssize_t pos) : obj(obj), pos(pos) { increment(); } + + reference dereference() const { return {key, value}; } + void increment() { if (!PyDict_Next(obj.ptr(), &pos, &key, &value)) { pos = -1; } } + bool equal(const dict_readonly &b) const { return pos == b.pos; } + +private: + handle obj; + PyObject *key, *value; + ssize_t pos = -1; +}; +NAMESPACE_END(iterator_policies) + +#if !defined(PYPY_VERSION) +using tuple_iterator = generic_iterator; +using list_iterator = generic_iterator; +#else +using tuple_iterator = generic_iterator; +using list_iterator = generic_iterator; +#endif + +using sequence_iterator = generic_iterator; +using dict_iterator = generic_iterator; + +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; } +#if PY_MAJOR_VERSION >= 3 +inline bool PyEllipsis_Check(PyObject *o) { return o == Py_Ellipsis; } +#endif + +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 = satisfies_none_of; +template using is_keyword_or_ds = satisfies_any_of; + +// 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_t{}) : Parent(h, stolen_t{})) { } \ + Name(handle h, borrowed_t) : Parent(h, borrowed_t{}) { } \ + Name(handle h, stolen_t) : Parent(h, stolen_t{}) { } \ + 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(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) \ + { if (!m_ptr) throw error_already_set(); } \ + Name(object &&o) \ + : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) \ + { if (!m_ptr) throw error_already_set(); } \ + template \ + Name(const ::pybind11::detail::accessor &a) : Name(object(a)) { } + +#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() { } + +/// \addtogroup pytypes +/// @{ + +/** \rst + Wraps a Python iterator so that it can also be used as a C++ input iterator + + Caveat: copying an iterator does not (and cannot) clone the internal + state of the Python iterable. This also applies to the post-increment + operator. This iterator should only be used to retrieve the current + value using ``operator*()``. +\endrst */ +class iterator : public object { +public: + using iterator_category = std::input_iterator_tag; + using difference_type = ssize_t; + using value_type = handle; + using reference = const handle; + using pointer = const handle *; + + PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check) + + iterator& operator++() { + advance(); + return *this; + } + + iterator operator++(int) { + auto rv = *this; + advance(); + return rv; + } + + reference operator*() const { + if (m_ptr && !value.ptr()) { + auto& self = const_cast(*this); + self.advance(); + } + return value; + } + + pointer operator->() const { operator*(); return &value; } + + /** \rst + The value which marks the end of the iteration. ``it == iterator::sentinel()`` + is equivalent to catching ``StopIteration`` in Python. + + .. code-block:: cpp + + void foo(py::iterator it) { + while (it != py::iterator::sentinel()) { + // use `*it` + ++it; + } + } + \endrst */ + static iterator sentinel() { return {}; } + + friend bool operator==(const iterator &a, const iterator &b) { return a->ptr() == b->ptr(); } + friend bool operator!=(const iterator &a, const iterator &b) { return a->ptr() != b->ptr(); } + +private: + void advance() { + value = reinterpret_steal(PyIter_Next(m_ptr)); + if (PyErr_Occurred()) { throw error_already_set(); } + } + +private: + object value = {}; +}; + +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_t{}) { + 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_t{}) { + 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); + + /** \rst + Return a string representation of the object. This is analogous to + the ``str()`` function in Python. + \endrst */ + explicit str(handle h) : object(raw_str(h.ptr()), stolen_t{}) { } + + 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; + } +}; +/// @} pytypes + +inline namespace literals { +/** \rst + String literal version of `str` + \endrst */ +inline str operator"" _s(const char *s, size_t size) { return {s, size}; } +} + +/// \addtogroup pytypes +/// @{ +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_t{}) { + 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_t{}) { + 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_t{}) { } +}; + +#if PY_MAJOR_VERSION >= 3 +class ellipsis : public object { +public: + PYBIND11_OBJECT(ellipsis, object, detail::PyEllipsis_Check) + ellipsis() : object(Py_Ellipsis, borrowed_t{}) { } +}; +#endif + +class bool_ : public object { +public: + PYBIND11_OBJECT_CVT(bool_, object, PyBool_Check, raw_bool) + bool_() : object(Py_False, borrowed_t{}) { } + // Allow implicit conversion from and to `bool`: + bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) { } + 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(); + } +}; + +NAMESPACE_BEGIN(detail) +// Converts a value to the given unsigned type. If an error occurs, you get back (Unsigned) -1; +// otherwise you get back the unsigned long or unsigned long long value cast to (Unsigned). +// (The distinction is critically important when casting a returned -1 error value to some other +// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes). +template +Unsigned as_unsigned(PyObject *o) { + if (sizeof(Unsigned) <= sizeof(unsigned long) +#if PY_VERSION_HEX < 0x03000000 + || PyInt_Check(o) +#endif + ) { + unsigned long v = PyLong_AsUnsignedLong(o); + return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; + } + else { + unsigned long long v = PyLong_AsUnsignedLongLong(o); + return v == (unsigned long long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; + } +} +NAMESPACE_END(detail) + +class int_ : public object { +public: + PYBIND11_OBJECT_CVT(int_, object, PYBIND11_LONG_CHECK, PyNumber_Long) + int_() : object(PyLong_FromLong(0), stolen_t{}) { } + // 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 { + return std::is_unsigned::value + ? detail::as_unsigned(m_ptr) + : sizeof(T) <= sizeof(long) + ? (T) PyLong_AsLong(m_ptr) + : (T) PYBIND11_LONG_AS_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_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate float object!"); + } + float_(double value = .0) : object(PyFloat_FromDouble((double) value), stolen_t{}) { + 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_t{}) { + 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_t{}) : object(ptr, stolen_t{})) { } + + explicit capsule(const void *value, const char *name = nullptr, void (*destructor)(PyObject *) = nullptr) + : object(PyCapsule_New(const_cast(value), name, destructor), stolen_t{}) { + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + } + + PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input") + capsule(const void *value, void (*destruct)(PyObject *)) + : object(PyCapsule_New(const_cast(value), nullptr, destruct), stolen_t{}) { + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + } + + capsule(const void *value, void (*destructor)(void *)) { + m_ptr = PyCapsule_New(const_cast(value), nullptr, [](PyObject *o) { + auto destructor = reinterpret_cast(PyCapsule_GetContext(o)); + void *ptr = PyCapsule_GetPointer(o, nullptr); + destructor(ptr); + }); + + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + + if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) + pybind11_fail("Could not set capsule context!"); + } + + capsule(void (*destructor)()) { + m_ptr = PyCapsule_New(reinterpret_cast(destructor), nullptr, [](PyObject *o) { + auto destructor = reinterpret_cast(PyCapsule_GetPointer(o, nullptr)); + destructor(); + }); + + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + } + + template operator T *() const { + auto name = this->name(); + T * result = static_cast(PyCapsule_GetPointer(m_ptr, name)); + if (!result) pybind11_fail("Unable to extract capsule contents!"); + return result; + } + + const char *name() const { return PyCapsule_GetName(m_ptr); } +}; + +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_t{}) { + 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}; } + detail::item_accessor operator[](handle h) const { return object::operator[](h); } + detail::tuple_iterator begin() const { return {*this, 0}; } + detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; } +}; + +class dict : public object { +public: + PYBIND11_OBJECT_CVT(dict, object, PyDict_Check, raw_dict) + dict() : object(PyDict_New(), stolen_t{}) { + 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 {*this, 0}; } + detail::dict_iterator end() const { return {}; } + 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_DEFAULT(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}; } + detail::item_accessor operator[](handle h) const { return object::operator[](h); } + detail::sequence_iterator begin() const { return {*this, 0}; } + detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; } +}; + +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_t{}) { + 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}; } + detail::item_accessor operator[](handle h) const { return object::operator[](h); } + detail::list_iterator begin() const { return {*this, 0}; } + detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; } + template void append(T &&val) const { + PyList_Append(m_ptr, detail::object_or_cast(std::forward(val)).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_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate set object!"); + } + size_t size() const { return (size_t) PySet_Size(m_ptr); } + template bool add(T &&val) const { + return PySet_Add(m_ptr, detail::object_or_cast(std::forward(val)).ptr()) == 0; + } + void clear() const { PySet_Clear(m_ptr); } +}; + +class function : public object { +public: + PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check) + handle cpp_function() const { + handle fun = detail::get_function(m_ptr); + if (fun && PyCFunction_Check(fun.ptr())) + return fun; + return handle(); + } + bool is_cpp_function() const { return (bool) cpp_function(); } +}; + +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) { + delete view; + 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 = info.itemsize; + buf.format = const_cast(info.format.c_str()); + buf.ndim = (int) info.ndim; + buf.len = info.size; + py_strides.clear(); + py_shape.clear(); + for (size_t i = 0; i < (size_t) info.ndim; ++i) { + py_strides.push_back(info.strides[i]); + py_shape.push_back(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) +}; +/// @} pytypes + +/// \addtogroup python_builtins +/// @{ +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); +} + +inline iterator iter(handle obj) { + PyObject *result = PyObject_GetIter(obj.ptr()); + if (!result) { throw error_already_set(); } + return reinterpret_steal(result); +} +/// @} python_builtins + +NAMESPACE_BEGIN(detail) +template iterator object_api::begin() const { return iter(derived()); } +template iterator object_api::end() const { return iterator::sentinel(); } +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 &&item) const { + return attr("__contains__")(std::forward(item)).template cast(); +} + +template +pybind11::str object_api::str() const { return pybind11::str(derived()); } + +template +str_attr_accessor object_api::doc() const { return attr("__doc__"); } + +template +handle object_api::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); } + +template +bool object_api::rich_compare(object_api const &other, int value) const { + int rv = PyObject_RichCompareBool(derived().ptr(), other.derived().ptr(), value); + if (rv == -1) + throw error_already_set(); + return rv == 1; +} + +#define PYBIND11_MATH_OPERATOR_UNARY(op, fn) \ + template object object_api::op() const { \ + object result = reinterpret_steal(fn(derived().ptr())); \ + if (!result.ptr()) \ + throw error_already_set(); \ + return result; \ + } + +#define PYBIND11_MATH_OPERATOR_BINARY(op, fn) \ + template \ + object object_api::op(object_api const &other) const { \ + object result = reinterpret_steal( \ + fn(derived().ptr(), other.derived().ptr())); \ + if (!result.ptr()) \ + throw error_already_set(); \ + return result; \ + } + +PYBIND11_MATH_OPERATOR_UNARY (operator~, PyNumber_Invert) +PYBIND11_MATH_OPERATOR_UNARY (operator-, PyNumber_Negative) +PYBIND11_MATH_OPERATOR_BINARY(operator+, PyNumber_Add) +PYBIND11_MATH_OPERATOR_BINARY(operator+=, PyNumber_InPlaceAdd) +PYBIND11_MATH_OPERATOR_BINARY(operator-, PyNumber_Subtract) +PYBIND11_MATH_OPERATOR_BINARY(operator-=, PyNumber_InPlaceSubtract) +PYBIND11_MATH_OPERATOR_BINARY(operator*, PyNumber_Multiply) +PYBIND11_MATH_OPERATOR_BINARY(operator*=, PyNumber_InPlaceMultiply) +PYBIND11_MATH_OPERATOR_BINARY(operator/, PyNumber_TrueDivide) +PYBIND11_MATH_OPERATOR_BINARY(operator/=, PyNumber_InPlaceTrueDivide) +PYBIND11_MATH_OPERATOR_BINARY(operator|, PyNumber_Or) +PYBIND11_MATH_OPERATOR_BINARY(operator|=, PyNumber_InPlaceOr) +PYBIND11_MATH_OPERATOR_BINARY(operator&, PyNumber_And) +PYBIND11_MATH_OPERATOR_BINARY(operator&=, PyNumber_InPlaceAnd) +PYBIND11_MATH_OPERATOR_BINARY(operator^, PyNumber_Xor) +PYBIND11_MATH_OPERATOR_BINARY(operator^=, PyNumber_InPlaceXor) +PYBIND11_MATH_OPERATOR_BINARY(operator<<, PyNumber_Lshift) +PYBIND11_MATH_OPERATOR_BINARY(operator<<=, PyNumber_InPlaceLshift) +PYBIND11_MATH_OPERATOR_BINARY(operator>>, PyNumber_Rshift) +PYBIND11_MATH_OPERATOR_BINARY(operator>>=, PyNumber_InPlaceRshift) + +#undef PYBIND11_MATH_OPERATOR_UNARY +#undef PYBIND11_MATH_OPERATOR_BINARY + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/pybind11/include/pybind11/stl.h b/pybind11/include/pybind11/stl.h new file mode 100644 index 0000000..32f8d29 --- /dev/null +++ b/pybind11/include/pybind11/stl.h @@ -0,0 +1,386 @@ +/* + 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 +#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() && \ + !__has_include()) +# include +# define PYBIND11_HAS_EXP_OPTIONAL 1 +# endif +// std::variant +# if defined(PYBIND11_CPP17) && __has_include() +# include +# define PYBIND11_HAS_VARIANT 1 +# endif +#elif defined(_MSC_VER) && defined(PYBIND11_CPP17) +# include +# include +# define PYBIND11_HAS_OPTIONAL 1 +# define PYBIND11_HAS_VARIANT 1 +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for +/// forwarding a container element). Typically used indirect via forwarded_type(), below. +template +using forwarded_type = conditional_t< + std::is_lvalue_reference::value, remove_reference_t &, remove_reference_t &&>; + +/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically +/// used for forwarding a container's elements. +template +forwarded_type forward_like(U &&u) { + return std::forward>(std::forward(u)); +} + +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(); + for (auto entry : s) { + key_conv conv; + if (!conv.load(entry, convert)) + return false; + value.insert(cast_op(std::move(conv))); + } + return true; + } + + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + if (!std::is_lvalue_reference::value) + policy = return_value_policy_override::policy(policy); + pybind11::set s; + for (auto &&value : src) { + auto value_ = reinterpret_steal(key_conv::cast(forward_like(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 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); + value.clear(); + for (auto it : d) { + key_conv kconv; + value_conv vconv; + if (!kconv.load(it.first.ptr(), convert) || + !vconv.load(it.second.ptr(), convert)) + return false; + value.emplace(cast_op(std::move(kconv)), cast_op(std::move(vconv))); + } + return true; + } + + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + dict d; + return_value_policy policy_key = policy; + return_value_policy policy_value = policy; + if (!std::is_lvalue_reference::value) { + policy_key = return_value_policy_override::policy(policy_key); + policy_value = return_value_policy_override::policy(policy_value); + } + for (auto &&kv : src) { + auto key = reinterpret_steal(key_conv::cast(forward_like(kv.first), policy_key, parent)); + auto value = reinterpret_steal(value_conv::cast(forward_like(kv.second), policy_value, 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 value_conv = make_caster; + + bool load(handle src, bool convert) { + if (!isinstance(src) || isinstance(src)) + return false; + auto s = reinterpret_borrow(src); + value.clear(); + reserve_maybe(s, &value); + for (auto it : s) { + value_conv conv; + if (!conv.load(it, convert)) + return false; + value.push_back(cast_op(std::move(conv))); + } + return true; + } + +private: + template ().reserve(0)), void>::value, int> = 0> + void reserve_maybe(sequence s, Type *) { value.reserve(s.size()); } + void reserve_maybe(sequence, void *) { } + +public: + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + if (!std::is_lvalue_reference::value) + policy = return_value_policy_override::policy(policy); + list l(src.size()); + size_t index = 0; + for (auto &&value : src) { + auto value_ = reinterpret_steal(value_conv::cast(forward_like(value), policy, parent)); + if (!value_) + return handle(); + PyList_SET_ITEM(l.ptr(), (ssize_t) 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> + : list_caster, Type> { }; + +template struct array_caster { + using value_conv = make_caster; + +private: + template + bool require_size(enable_if_t size) { + if (value.size() != size) + value.resize(size); + return true; + } + template + bool require_size(enable_if_t size) { + return size == Size; + } + +public: + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + auto l = reinterpret_borrow(src); + if (!require_size(l.size())) + return false; + size_t ctr = 0; + for (auto it : l) { + value_conv conv; + if (!conv.load(it, convert)) + return false; + value[ctr++] = cast_op(std::move(conv)); + } + return true; + } + + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + list l(src.size()); + size_t index = 0; + for (auto &&value : src) { + auto value_ = reinterpret_steal(value_conv::cast(forward_like(value), policy, parent)); + if (!value_) + return handle(); + PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference + } + return l.release(); + } + + PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name + _(_(""), _("[") + _() + _("]")) + _("]")); +}; + +template struct type_caster> + : array_caster, Type, false, Size> { }; + +template struct type_caster> + : array_caster, Type, true> { }; + +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; + + template + static handle cast(T_ &&src, return_value_policy policy, handle parent) { + if (!src) + return none().inc_ref(); + policy = return_value_policy_override::policy(policy); + return value_conv::cast(*std::forward(src), policy, parent); + } + + bool load(handle src, bool convert) { + if (!src) { + return false; + } else if (src.is_none()) { + return true; // default-constructed value is already empty + } + value_conv inner_caster; + if (!inner_caster.load(src, convert)) + return false; + + value.emplace(cast_op(std::move(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 + +/// Visit a variant and cast any found type to Python +struct variant_caster_visitor { + return_value_policy policy; + handle parent; + + using result_type = handle; // required by boost::variant in C++11 + + template + result_type operator()(T &&src) const { + return make_caster::cast(std::forward(src), policy, parent); + } +}; + +/// Helper class which abstracts away variant's `visit` function. `std::variant` and similar +/// `namespace::variant` types which provide a `namespace::visit()` function are handled here +/// automatically using argument-dependent lookup. Users can provide specializations for other +/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`. +template class Variant> +struct visit_helper { + template + static auto call(Args &&...args) -> decltype(visit(std::forward(args)...)) { + return visit(std::forward(args)...); + } +}; + +/// Generic variant caster +template struct variant_caster; + +template class V, typename... Ts> +struct variant_caster> { + static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative."); + + template + bool load_alternative(handle src, bool convert, type_list) { + auto caster = make_caster(); + if (caster.load(src, convert)) { + value = cast_op(caster); + return true; + } + return load_alternative(src, convert, type_list{}); + } + + bool load_alternative(handle, bool, type_list<>) { return false; } + + bool load(handle src, bool convert) { + // Do a first pass without conversions to improve constructor resolution. + // E.g. `py::int_(1).cast>()` needs to fill the `int` + // slot of the variant. Without two-pass loading `double` would be filled + // because it appears first and a conversion is possible. + if (convert && load_alternative(src, false, type_list{})) + return true; + return load_alternative(src, convert, type_list{}); + } + + template + static handle cast(Variant &&src, return_value_policy policy, handle parent) { + return visit_helper::call(variant_caster_visitor{policy, parent}, + std::forward(src)); + } + + using Type = V; + PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster::name...) + _("]")); +}; + +#if PYBIND11_HAS_VARIANT +template +struct type_caster> : variant_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_NAMESPACE) + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif diff --git a/pybind11/include/pybind11/stl_bind.h b/pybind11/include/pybind11/stl_bind.h new file mode 100644 index 0000000..38dd68f --- /dev/null +++ b/pybind11/include/pybind11/stl_bind.h @@ -0,0 +1,599 @@ +/* + 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 "detail/common.h" +#include "operators.h" + +#include +#include + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +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::value, Class_> &cl) { + cl.def(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 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([](iterable it) { + auto v = std::unique_ptr(new Vector()); + v->reserve(len(it)); + for (handle h : it) + v->push_back(h.cast()); + return v.release(); + })); + + cl.def("extend", + [](Vector &v, const Vector &src) { + 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) { + if (i > v.size()) + throw index_error(); + 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 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 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 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 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 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 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 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 = negation< + std::is_same()[typename Vector::size_type()]), typename Vector::value_type &>>; + +// 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 index_error(); + return v[i]; + }, + return_value_policy::reference_internal // ref + keepalive + ); + + cl.def("__iter__", + [](Vector &v) { + return 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 index_error(); + return v[i]; + } + ); + + cl.def("__iter__", + [](Vector &v) { + return 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." + ); +} + +// Provide the buffer interface for vectors if we have data() and we have a format for it +// GCC seems to have "void std::vector::data()" - doing SFINAE on the existence of data() is insufficient, we need to check it returns an appropriate pointer +template +struct vector_has_data_and_format : std::false_type {}; +template +struct vector_has_data_and_format::format(), std::declval().data()), typename Vector::value_type*>::value>> : std::true_type {}; + +// Add the buffer interface to a vector +template +enable_if_t...>::value> +vector_buffer(Class_& cl) { + using T = typename Vector::value_type; + + static_assert(vector_has_data_and_format::value, "There is not an appropriate format descriptor for this vector"); + + // numpy.h declares this for arbitrary types, but it may raise an exception and crash hard at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here + format_descriptor::format(); + + cl.def_buffer([](Vector& v) -> buffer_info { + return buffer_info(v.data(), static_cast(sizeof(T)), format_descriptor::format(), 1, {v.size()}, {sizeof(T)}); + }); + + cl.def(init([](buffer buf) { + auto info = buf.request(); + if (info.ndim != 1 || info.strides[0] % static_cast(sizeof(T))) + throw type_error("Only valid 1D buffers can be copied to a vector"); + if (!detail::compare_buffer_info::compare(info) || (ssize_t) sizeof(T) != info.itemsize) + throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor::format() + ")"); + + auto vec = std::unique_ptr(new Vector()); + vec->reserve((size_t) info.shape[0]); + T *p = static_cast(info.ptr); + ssize_t step = info.strides[0] / static_cast(sizeof(T)); + T *end = p + info.shape[0] * step; + for (; p != end; p += step) + vec->push_back(*p); + return vec.release(); + })); + + return; +} + +template +enable_if_t...>::value> vector_buffer(Class_&) {} + +NAMESPACE_END(detail) + +// +// std::vector +// +template , typename... Args> +class_ bind_vector(handle scope, std::string const &name, Args&&... args) { + using Class_ = class_; + + // If the value_type is unregistered (e.g. a converting type) or is itself registered + // module-local then make the vector binding module-local as well: + using vtype = typename Vector::value_type; + auto vtype_info = detail::get_type_info(typeid(vtype)); + bool local = !vtype_info || vtype_info->module_local; + + Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward(args)...); + + // Declare the buffer interface if a buffer_protocol() is passed in + detail::vector_buffer(cl); + + cl.def(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(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 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 index_error(); + }, "access the first element"); + + cl.def("back", [](Vector &v) { + if (v.size()) return v.back(); + else throw 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 && + 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> +class_ bind_map(handle scope, const std::string &name, Args&&... args) { + using KeyType = typename Map::key_type; + using MappedType = typename Map::mapped_type; + using Class_ = class_; + + // If either type is a non-module-local bound type then make the map binding non-local as well; + // otherwise (e.g. both types are either module-local or converting) the map will be + // module-local. + auto tinfo = detail::get_type_info(typeid(MappedType)); + bool local = !tinfo || tinfo->module_local; + if (local) { + tinfo = detail::get_type_info(typeid(KeyType)); + local = !tinfo || tinfo->module_local; + } + + Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward(args)...); + + cl.def(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 make_key_iterator(m.begin(), m.end()); }, + keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + ); + + cl.def("items", + [](Map &m) { return make_iterator(m.begin(), m.end()); }, + 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 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 key_error(); + m.erase(it); + } + ); + + cl.def("__len__", &Map::size); + + return cl; +} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/pybind11/pybind11/__init__.py b/pybind11/pybind11/__init__.py new file mode 100644 index 0000000..5782ffe --- /dev/null +++ b/pybind11/pybind11/__init__.py @@ -0,0 +1,28 @@ +from ._version import version_info, __version__ # noqa: F401 imported but unused + + +def get_include(user=False): + from distutils.dist import Distribution + import os + import sys + + # Are we running in a virtual environment? + virtualenv = hasattr(sys, 'real_prefix') or \ + sys.prefix != getattr(sys, "base_prefix", sys.prefix) + + if virtualenv: + return os.path.join(sys.prefix, 'include', 'site', + 'python' + sys.version[:3]) + else: + dist = Distribution({'name': 'pybind11'}) + dist.parse_config_files() + + dist_cobj = dist.get_command_obj('install', create=True) + + # Search for packages in user's home directory? + if user: + dist_cobj.user = user + dist_cobj.prefix = "" + dist_cobj.finalize_options() + + return os.path.dirname(dist_cobj.install_headers) diff --git a/pybind11/pybind11/__main__.py b/pybind11/pybind11/__main__.py new file mode 100644 index 0000000..9ef8378 --- /dev/null +++ b/pybind11/pybind11/__main__.py @@ -0,0 +1,37 @@ +from __future__ import print_function + +import argparse +import sys +import sysconfig + +from . import get_include + + +def print_includes(): + dirs = [sysconfig.get_path('include'), + sysconfig.get_path('platinclude'), + get_include(), + get_include(True)] + + # Make unique but preserve order + unique_dirs = [] + for d in dirs: + if d not in unique_dirs: + unique_dirs.append(d) + + print(' '.join('-I' + d for d in unique_dirs)) + + +def main(): + parser = argparse.ArgumentParser(prog='python -m pybind11') + parser.add_argument('--includes', action='store_true', + help='Include flags for both pybind11 and Python headers.') + args = parser.parse_args() + if not sys.argv[1:]: + parser.print_help() + if args.includes: + print_includes() + + +if __name__ == '__main__': + main() diff --git a/pybind11/pybind11/_version.py b/pybind11/pybind11/_version.py new file mode 100644 index 0000000..c046ed7 --- /dev/null +++ b/pybind11/pybind11/_version.py @@ -0,0 +1,2 @@ +version_info = (2, 3, 'dev0') +__version__ = '.'.join(map(str, version_info)) diff --git a/pybind11/setup.cfg b/pybind11/setup.cfg new file mode 100644 index 0000000..9bbbd03 --- /dev/null +++ b/pybind11/setup.cfg @@ -0,0 +1,10 @@ +[bdist_wheel] +universal=1 + +[flake8] +max-line-length = 99 +show_source = True +exclude = .git, __pycache__, build, dist, docs, tools, venv +ignore = + # required for pretty matrix formatting: multiple spaces after `,` and `[` + E201, E241, W504 diff --git a/pybind11/setup.py b/pybind11/setup.py new file mode 100644 index 0000000..f677f2a --- /dev/null +++ b/pybind11/setup.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +# Setup script for PyPI; use CMakeFile.txt to build extension modules + +from setuptools import setup +from distutils.command.install_headers import install_headers +from pybind11 import __version__ +import os + +# Prevent installation of pybind11 headers by setting +# PYBIND11_USE_CMAKE. +if os.environ.get('PYBIND11_USE_CMAKE'): + headers = [] +else: + headers = [ + 'include/pybind11/detail/class.h', + 'include/pybind11/detail/common.h', + 'include/pybind11/detail/descr.h', + 'include/pybind11/detail/init.h', + 'include/pybind11/detail/internals.h', + 'include/pybind11/detail/typeid.h', + 'include/pybind11/attr.h', + 'include/pybind11/buffer_info.h', + 'include/pybind11/cast.h', + 'include/pybind11/chrono.h', + 'include/pybind11/common.h', + 'include/pybind11/complex.h', + 'include/pybind11/eigen.h', + 'include/pybind11/embed.h', + 'include/pybind11/eval.h', + 'include/pybind11/functional.h', + 'include/pybind11/iostream.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', + ] + + +class InstallHeaders(install_headers): + """Use custom header installer because the default one flattens subdirectories""" + def run(self): + if not self.distribution.headers: + return + + for header in self.distribution.headers: + subdir = os.path.dirname(os.path.relpath(header, 'include/pybind11')) + install_dir = os.path.join(self.install_dir, subdir) + self.mkpath(install_dir) + + (out, _) = self.copy_file(header, install_dir) + self.outfiles.append(out) + + +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/pybind/pybind11', + download_url='https://github.com/pybind/pybind11/tarball/v' + __version__, + packages=['pybind11'], + license='BSD', + headers=headers, + cmdclass=dict(install_headers=InstallHeaders), + 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', + 'Programming Language :: Python :: 3.6', + 'License :: OSI Approved :: BSD License' + ], + keywords='C++11, Python bindings', + long_description="""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 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 ~4K lines of code and depend on +Python (2.7 or 3.x, or PyPy2.7 >= 5.7) 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/pybind11/tests/CMakeLists.txt b/pybind11/tests/CMakeLists.txt new file mode 100644 index 0000000..a31d5b8 --- /dev/null +++ b/pybind11/tests/CMakeLists.txt @@ -0,0 +1,238 @@ +# CMakeLists.txt -- Build system for the pybind11 test suite +# +# 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) + +option(PYBIND11_WERROR "Report all warnings as errors" OFF) + +if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + # We're being loaded directly, i.e. not via add_subdirectory, so make this + # work as its own project and load the pybind11Config to get the tools we need + project(pybind11_tests CXX) + + find_package(pybind11 REQUIRED CONFIG) +endif() + +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_buffers.cpp + test_builtin_casters.cpp + test_call_policies.cpp + test_callbacks.cpp + test_chrono.cpp + test_class.cpp + test_constants_and_functions.cpp + test_copy_move.cpp + test_docstring_options.cpp + test_eigen.cpp + test_enum.cpp + test_eval.cpp + test_exceptions.cpp + test_factory_constructors.cpp + test_gil_scoped.cpp + test_iostream.cpp + test_kwargs_and_defaults.cpp + test_local_bindings.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_pytypes.cpp + test_sequences_and_iterators.cpp + test_smart_ptr.cpp + test_stl.cpp + test_stl_binders.cpp + test_tagbased_polymorphic.cpp + test_virtual_functions.cpp +) + +# Invoking cmake with something like: +# cmake -DPYBIND11_TEST_OVERRIDE="test_callbacks.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}") + +# Contains the set of test files that require pybind11_cross_module_tests to be +# built; if none of these are built (i.e. because TEST_OVERRIDE is used and +# doesn't include them) the second module doesn't get built. +set(PYBIND11_CROSS_MODULE_TESTS + test_exceptions.py + test_local_bindings.py + test_stl.py + test_stl_binders.py +) + +# 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) + # Try loading via newer Eigen's Eigen3Config first (bypassing tools/FindEigen3.cmake). + # Eigen 3.3.1+ exports a cmake 3.0+ target for handling dependency requirements, but also + # produces a fatal error if loaded from a pre-3.0 cmake. + if (NOT CMAKE_VERSION VERSION_LESS 3.0) + find_package(Eigen3 3.2.7 QUIET CONFIG) + if (EIGEN3_FOUND) + if (EIGEN3_VERSION_STRING AND NOT EIGEN3_VERSION_STRING VERSION_LESS 3.3.1) + set(PYBIND11_EIGEN_VIA_TARGET 1) + endif() + endif() + endif() + if (NOT EIGEN3_FOUND) + # Couldn't load via target, so fall back to allowing module mode finding, which will pick up + # tools/FindEigen3.cmake + find_package(Eigen3 3.2.7 QUIET) + endif() + + if(EIGEN3_FOUND) + # Eigen 3.3.1+ cmake sets EIGEN3_VERSION_STRING (and hard codes the version when installed + # rather than looking it up in the cmake script); older versions, and the + # tools/FindEigen3.cmake, set EIGEN3_VERSION instead. + if(NOT EIGEN3_VERSION AND EIGEN3_VERSION_STRING) + set(EIGEN3_VERSION ${EIGEN3_VERSION_STRING}) + endif() + 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() + +# Optional dependency for some tests (boost::variant is only supported with version >= 1.56) +find_package(Boost 1.56) + +# 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 -Wcast-qual -Wdeprecated) + 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(test_targets pybind11_tests) + +# Build pybind11_cross_module_tests if any test_whatever.py are being built that require it +foreach(t ${PYBIND11_CROSS_MODULE_TESTS}) + list(FIND PYBIND11_PYTEST_FILES ${t} i) + if (i GREATER -1) + list(APPEND test_targets pybind11_cross_module_tests) + break() + endif() +endforeach() + +set(testdir ${CMAKE_CURRENT_SOURCE_DIR}) +foreach(target ${test_targets}) + set(test_files ${PYBIND11_TEST_FILES}) + if(NOT target STREQUAL "pybind11_tests") + set(test_files "") + endif() + + # Create the binding library + pybind11_add_module(${target} THIN_LTO ${target}.cpp ${test_files} ${PYBIND11_HEADERS}) + pybind11_enable_warnings(${target}) + + if(MSVC) + target_compile_options(${target} PRIVATE /utf-8) + endif() + + if(EIGEN3_FOUND) + if (PYBIND11_EIGEN_VIA_TARGET) + target_link_libraries(${target} PRIVATE Eigen3::Eigen) + else() + target_include_directories(${target} PRIVATE ${EIGEN3_INCLUDE_DIR}) + endif() + target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_EIGEN) + endif() + + if(Boost_FOUND) + target_include_directories(${target} PRIVATE ${Boost_INCLUDE_DIRS}) + target_compile_definitions(${target} PRIVATE -DPYBIND11_TEST_BOOST) + endif() + + # Always write the output file directly into the 'tests' directory (even on MSVC) + if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) + set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${testdir}) + foreach(config ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${config} config) + set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} ${testdir}) + endforeach() + endif() +endforeach() + +# Make sure pytest is found or produce a fatal error +if(NOT PYBIND11_PYTEST_FOUND) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import pytest; print(pytest.__version__)" + RESULT_VARIABLE pytest_not_found OUTPUT_VARIABLE pytest_version ERROR_QUIET) + if(pytest_not_found) + message(FATAL_ERROR "Running the tests requires pytest. Please install it manually" + " (try: ${PYTHON_EXECUTABLE} -m pip install pytest)") + elseif(pytest_version VERSION_LESS 3.0) + message(FATAL_ERROR "Running the tests requires pytest >= 3.0. Found: ${pytest_version}" + "Please update it (try: ${PYTHON_EXECUTABLE} -m pip install -U pytest)") + endif() + set(PYBIND11_PYTEST_FOUND TRUE CACHE INTERNAL "") +endif() + +if(CMAKE_VERSION VERSION_LESS 3.2) + set(PYBIND11_USES_TERMINAL "") +else() + set(PYBIND11_USES_TERMINAL "USES_TERMINAL") +endif() + +# A single command to compile and run the tests +add_custom_target(pytest COMMAND ${PYTHON_EXECUTABLE} -m pytest ${PYBIND11_PYTEST_FILES} + DEPENDS ${test_targets} WORKING_DIRECTORY ${testdir} ${PYBIND11_USES_TERMINAL}) + +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() + +# Add a check target to run all the tests, starting with pytest (we add dependencies to this below) +add_custom_target(check DEPENDS pytest) + +# The remaining tests only apply when being built as part of the pybind11 project, but not if the +# tests are being built independently. +if (NOT PROJECT_NAME STREQUAL "pybind11") + return() +endif() + +# Add a post-build comment to show the primary test suite .so size and, if a previous size, compare it: +add_custom_command(TARGET pybind11_tests POST_BUILD + COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/libsize.py + $ ${CMAKE_CURRENT_BINARY_DIR}/sosize-$.txt) + +# Test embedding the interpreter. Provides the `cpptest` target. +add_subdirectory(test_embed) + +# Test CMake build using functions and targets from subdirectory or installed location +add_subdirectory(test_cmake_build) diff --git a/pybind11/tests/conftest.py b/pybind11/tests/conftest.py new file mode 100644 index 0000000..f4c2282 --- /dev/null +++ b/pybind11/tests/conftest.py @@ -0,0 +1,241 @@ +"""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 +import platform +import gc + +_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(capsys): + """Extended `capsys` with context manager and custom equality operators""" + return Capture(capsys) + + +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 gc_collect(): + ''' Run the garbage collector twice (needed when running + reference counting tests with PyPy) ''' + gc.collect() + gc.collect() + + +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.eigen import have_eigen + except ImportError: + have_eigen = False + pypy = platform.python_implementation() == "PyPy" + + 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"), + 'unsupported_on_pypy': skipif(pypy, reason="unsupported on PyPy"), + 'unsupported_on_py2': skipif(sys.version_info.major < 3, + reason="unsupported on Python 2.x"), + 'gc_collect': gc_collect + } + + +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/pybind11/tests/constructor_stats.h b/pybind11/tests/constructor_stats.h new file mode 100644 index 0000000..f026e70 --- /dev/null +++ b/pybind11/tests/constructor_stats.h @@ -0,0 +1,276 @@ +#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 testing .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 pybind11_tests 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()"); + } + + static void gc() { + // Force garbage collection to ensure any pending destructors are invoked: +#if defined(PYPY_VERSION) + PyObject *globals = PyEval_GetGlobals(); + PyObject *result = PyRun_String( + "import gc\n" + "for i in range(2):" + " gc.collect()\n", + Py_file_input, globals, globals); + if (result == nullptr) + throw py::error_already_set(); + Py_DECREF(result); +#else + py::module::import("gc").attr("collect")(); +#endif + } + + int alive() { + gc(); + 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() { +#if defined(PYPY_VERSION) + gc(); +#endif + 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((PyTypeObject *) class_.ptr()).at(0); + for (auto &p : internals.registered_types_cpp) { + if (p.second == type_info) { + if (t1) { + t2 = &p.first; + break; + } + t1 = &p.first; + } + } + } + catch (const 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/pybind11/tests/local_bindings.h b/pybind11/tests/local_bindings.h new file mode 100644 index 0000000..b6afb80 --- /dev/null +++ b/pybind11/tests/local_bindings.h @@ -0,0 +1,64 @@ +#pragma once +#include "pybind11_tests.h" + +/// Simple class used to test py::local: +template class LocalBase { +public: + LocalBase(int i) : i(i) { } + int i = -1; +}; + +/// Registered with py::module_local in both main and secondary modules: +using LocalType = LocalBase<0>; +/// Registered without py::module_local in both modules: +using NonLocalType = LocalBase<1>; +/// A second non-local type (for stl_bind tests): +using NonLocal2 = LocalBase<2>; +/// Tests within-module, different-compilation-unit local definition conflict: +using LocalExternal = LocalBase<3>; +/// Mixed: registered local first, then global +using MixedLocalGlobal = LocalBase<4>; +/// Mixed: global first, then local +using MixedGlobalLocal = LocalBase<5>; + +/// Registered with py::module_local only in the secondary module: +using ExternalType1 = LocalBase<6>; +using ExternalType2 = LocalBase<7>; + +using LocalVec = std::vector; +using LocalVec2 = std::vector; +using LocalMap = std::unordered_map; +using NonLocalVec = std::vector; +using NonLocalVec2 = std::vector; +using NonLocalMap = std::unordered_map; +using NonLocalMap2 = std::unordered_map; + +PYBIND11_MAKE_OPAQUE(LocalVec); +PYBIND11_MAKE_OPAQUE(LocalVec2); +PYBIND11_MAKE_OPAQUE(LocalMap); +PYBIND11_MAKE_OPAQUE(NonLocalVec); +//PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2 +PYBIND11_MAKE_OPAQUE(NonLocalMap); +PYBIND11_MAKE_OPAQUE(NonLocalMap2); + + +// Simple bindings (used with the above): +template +py::class_ bind_local(Args && ...args) { + return py::class_(std::forward(args)...) + .def(py::init()) + .def("get", [](T &i) { return i.i + Adjust; }); +}; + +// Simulate a foreign library base class (to match the example in the docs): +namespace pets { +class Pet { +public: + Pet(std::string name) : name_(name) {} + std::string name_; + const std::string &name() { return name_; } +}; +} + +struct MixGL { int i; MixGL(int i) : i{i} {} }; +struct MixGL2 { int i; MixGL2(int i) : i{i} {} }; diff --git a/pybind11/tests/object.h b/pybind11/tests/object.h new file mode 100644 index 0000000..9235f19 --- /dev/null +++ b/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_ptr() { return m_ptr; } + + /// Return a pointer to the referenced object + const T* get_ptr() const { return m_ptr; } +private: + T *m_ptr; +}; + +#endif /* __OBJECT_H */ diff --git a/pybind11/tests/pybind11_cross_module_tests.cpp b/pybind11/tests/pybind11_cross_module_tests.cpp new file mode 100644 index 0000000..f705e31 --- /dev/null +++ b/pybind11/tests/pybind11_cross_module_tests.cpp @@ -0,0 +1,123 @@ +/* + tests/pybind11_cross_module_tests.cpp -- contains tests that require multiple modules + + Copyright (c) 2017 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" +#include "local_bindings.h" +#include +#include + +PYBIND11_MODULE(pybind11_cross_module_tests, m) { + m.doc() = "pybind11 cross-module test module"; + + // test_local_bindings.py tests: + // + // Definitions here are tested by importing both this module and the + // relevant pybind11_tests submodule from a test_whatever.py + + // test_load_external + bind_local(m, "ExternalType1", py::module_local()); + bind_local(m, "ExternalType2", py::module_local()); + + // test_exceptions.py + m.def("raise_runtime_error", []() { PyErr_SetString(PyExc_RuntimeError, "My runtime error"); throw py::error_already_set(); }); + m.def("raise_value_error", []() { PyErr_SetString(PyExc_ValueError, "My value error"); throw py::error_already_set(); }); + m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); }); + m.def("throw_pybind_type_error", []() { throw py::type_error("pybind11 type error"); }); + m.def("throw_stop_iteration", []() { throw py::stop_iteration(); }); + + // test_local_bindings.py + // Local to both: + bind_local(m, "LocalType", py::module_local()) + .def("get2", [](LocalType &t) { return t.i + 2; }) + ; + + // Can only be called with our python type: + m.def("local_value", [](LocalType &l) { return l.i; }); + + // test_nonlocal_failure + // This registration will fail (global registration when LocalFail is already registered + // globally in the main test module): + m.def("register_nonlocal", [m]() { + bind_local(m, "NonLocalType"); + }); + + // test_stl_bind_local + // stl_bind.h binders defaults to py::module_local if the types are local or converting: + py::bind_vector(m, "LocalVec"); + py::bind_map(m, "LocalMap"); + + // test_stl_bind_global + // and global if the type (or one of the types, for the map) is global (so these will fail, + // assuming pybind11_tests is already loaded): + m.def("register_nonlocal_vec", [m]() { + py::bind_vector(m, "NonLocalVec"); + }); + m.def("register_nonlocal_map", [m]() { + py::bind_map(m, "NonLocalMap"); + }); + // The default can, however, be overridden to global using `py::module_local()` or + // `py::module_local(false)`. + // Explicitly made local: + py::bind_vector(m, "NonLocalVec2", py::module_local()); + // Explicitly made global (and so will fail to bind): + m.def("register_nonlocal_map2", [m]() { + py::bind_map(m, "NonLocalMap2", py::module_local(false)); + }); + + // test_mixed_local_global + // We try this both with the global type registered first and vice versa (the order shouldn't + // matter). + m.def("register_mixed_global_local", [m]() { + bind_local(m, "MixedGlobalLocal", py::module_local()); + }); + m.def("register_mixed_local_global", [m]() { + bind_local(m, "MixedLocalGlobal", py::module_local(false)); + }); + m.def("get_mixed_gl", [](int i) { return MixedGlobalLocal(i); }); + m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); }); + + // test_internal_locals_differ + m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::registered_local_types_cpp(); }); + + // test_stl_caster_vs_stl_bind + py::bind_vector>(m, "VectorInt"); + + m.def("load_vector_via_binding", [](std::vector &v) { + return std::accumulate(v.begin(), v.end(), 0); + }); + + // test_cross_module_calls + m.def("return_self", [](LocalVec *v) { return v; }); + m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); }); + + class Dog : public pets::Pet { public: Dog(std::string name) : Pet(name) {}; }; + py::class_(m, "Pet", py::module_local()) + .def("name", &pets::Pet::name); + // Binding for local extending class: + py::class_(m, "Dog") + .def(py::init()); + m.def("pet_name", [](pets::Pet &p) { return p.name(); }); + + py::class_(m, "MixGL", py::module_local()).def(py::init()); + m.def("get_gl_value", [](MixGL &o) { return o.i + 100; }); + + py::class_(m, "MixGL2", py::module_local()).def(py::init()); + + // test_vector_bool + // We can't test both stl.h and stl_bind.h conversions of `std::vector` within + // the same module (it would be an ODR violation). Therefore `bind_vector` of `bool` + // is defined here and tested in `test_stl_binders.py`. + py::bind_vector>(m, "VectorBool"); + + // test_missing_header_message + // The main module already includes stl.h, but we need to test the error message + // which appears when this header is missing. + m.def("missing_header_arg", [](std::vector) { }); + m.def("missing_header_return", []() { return std::vector(); }); +} diff --git a/pybind11/tests/pybind11_tests.cpp b/pybind11/tests/pybind11_tests.cpp new file mode 100644 index 0000000..bc7d2c3 --- /dev/null +++ b/pybind11/tests/pybind11_tests.cpp @@ -0,0 +1,93 @@ +/* + 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" + +#include +#include + +/* +For testing purposes, we define a static global variable here in a function that each individual +test .cpp calls with its initialization lambda. It's convenient here because we can just not +compile some test files to disable/ignore some of the test code. + +It is NOT recommended as a way to use pybind11 in practice, however: the initialization order will +be essentially random, which is okay for our test scripts (there are no dependencies between the +individual pybind11 test .cpp files), but most likely not what you want when using pybind11 +productively. + +Instead, see the "How can I reduce the build time?" question in the "Frequently asked questions" +section of the documentation for good practice on splitting binding code over multiple files. +*/ +std::list> &initializers() { + static std::list> inits; + return inits; +} + +test_initializer::test_initializer(Initializer init) { + initializers().push_back(init); +} + +test_initializer::test_initializer(const char *submodule_name, Initializer init) { + initializers().push_back([=](py::module &parent) { + auto m = parent.def_submodule(submodule_name); + init(m); + }); +} + +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) + + // Not exactly ConstructorStats, but related: expose the internal pybind number of registered instances + // to allow instance cleanup checks (invokes a GC first) + .def_static("detail_reg_inst", []() { + ConstructorStats::gc(); + return py::detail::get_internals().registered_instances.size(); + }) + ; +} + +PYBIND11_MODULE(pybind11_tests, m) { + m.doc() = "pybind11 test module"; + + bind_ConstructorStats(m); + +#if !defined(NDEBUG) + m.attr("debug_enabled") = true; +#else + m.attr("debug_enabled") = false; +#endif + + py::class_(m, "UserType", "A `py::class_` type for testing") + .def(py::init<>()) + .def(py::init()) + .def("get_value", &UserType::value, "Get value using a method") + .def("set_value", &UserType::set, "Set value using a method") + .def_property("value", &UserType::value, &UserType::set, "Get/set value using a property") + .def("__repr__", [](const UserType& u) { return "UserType({})"_s.format(u.value()); }); + + py::class_(m, "IncType") + .def(py::init<>()) + .def(py::init()) + .def("__repr__", [](const IncType& u) { return "IncType({})"_s.format(u.value()); }); + + for (const auto &initializer : initializers()) + initializer(m); + + if (!py::hasattr(m, "have_eigen")) m.attr("have_eigen") = false; +} diff --git a/pybind11/tests/pybind11_tests.h b/pybind11/tests/pybind11_tests.h new file mode 100644 index 0000000..90963a5 --- /dev/null +++ b/pybind11/tests/pybind11_tests.h @@ -0,0 +1,65 @@ +#pragma once +#include + +#if defined(_MSC_VER) && _MSC_VER < 1910 +// We get some really long type names here which causes MSVC 2015 to emit warnings +# pragma warning(disable: 4503) // warning C4503: decorated name length exceeded, name was truncated +#endif + +namespace py = pybind11; +using namespace pybind11::literals; + +class test_initializer { + using Initializer = void (*)(py::module &); + +public: + test_initializer(Initializer init); + test_initializer(const char *submodule_name, Initializer init); +}; + +#define TEST_SUBMODULE(name, variable) \ + void test_submodule_##name(py::module &); \ + test_initializer name(#name, test_submodule_##name); \ + void test_submodule_##name(py::module &variable) + + +/// Dummy type which is not exported anywhere -- something to trigger a conversion error +struct UnregisteredType { }; + +/// A user-defined type which is exported and can be used by any test +class UserType { +public: + UserType() = default; + UserType(int i) : i(i) { } + + int value() const { return i; } + void set(int set) { i = set; } + +private: + int i = -1; +}; + +/// Like UserType, but increments `value` on copy for quick reference vs. copy tests +class IncType : public UserType { +public: + using UserType::UserType; + IncType() = default; + IncType(const IncType &other) : IncType(other.value() + 1) { } + IncType(IncType &&) = delete; + IncType &operator=(const IncType &) = delete; + IncType &operator=(IncType &&) = delete; +}; + +/// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast context. +/// Used to test recursive casters (e.g. std::tuple, stl containers). +struct RValueCaster {}; +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) +template<> class type_caster { +public: + PYBIND11_TYPE_CASTER(RValueCaster, _("RValueCaster")); + static handle cast(RValueCaster &&, return_value_policy, handle) { return py::str("rvalue").release(); } + static handle cast(const RValueCaster &, return_value_policy, handle) { return py::str("lvalue").release(); } +}; +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/pybind11/tests/pytest.ini b/pybind11/tests/pytest.ini new file mode 100644 index 0000000..1e44f0a --- /dev/null +++ b/pybind11/tests/pytest.ini @@ -0,0 +1,15 @@ +[pytest] +minversion = 3.0 +norecursedirs = test_cmake_build test_embed +addopts = + # show summary of skipped tests + -rs + # capture only Python print and C++ py::print, but not C output (low-level Python errors) + --capture=sys +filterwarnings = + # make warnings into errors but ignore certain third-party extension issues + error + # importing scipy submodules on some version of Python + ignore::ImportWarning + # bogus numpy ABI warning (see numpy/#432) + ignore:.*numpy.dtype size changed.*:RuntimeWarning diff --git a/pybind11/tests/test_buffers.cpp b/pybind11/tests/test_buffers.cpp new file mode 100644 index 0000000..5199cf6 --- /dev/null +++ b/pybind11/tests/test_buffers.cpp @@ -0,0 +1,169 @@ +/* + 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" + +TEST_SUBMODULE(buffers, m) { + // test_from_python / test_to_python: + class Matrix { + public: + Matrix(ssize_t rows, ssize_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[(size_t) (rows*cols)]; + memset(m_data, 0, sizeof(float) * (size_t) (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[(size_t) (m_rows * m_cols)]; + memcpy(m_data, s.m_data, sizeof(float) * (size_t) (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[(size_t) (m_rows * m_cols)]; + memcpy(m_data, s.m_data, sizeof(float) * (size_t) (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()(ssize_t i, ssize_t j) const { + return m_data[(size_t) (i*m_cols + j)]; + } + + float &operator()(ssize_t i, ssize_t j) { + return m_data[(size_t) (i*m_cols + j)]; + } + + float *data() { return m_data; } + + ssize_t rows() const { return m_rows; } + ssize_t cols() const { return m_cols; } + private: + ssize_t m_rows; + ssize_t m_cols; + float *m_data; + }; + py::class_(m, "Matrix", py::buffer_protocol()) + .def(py::init()) + /// Construct from a buffer + .def(py::init([](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!"); + + auto v = new Matrix(info.shape[0], info.shape[1]); + memcpy(v->data(), info.ptr, sizeof(float) * (size_t) (v->rows() * v->cols())); + return v; + })) + + .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 */ + { m.rows(), m.cols() }, /* Buffer dimensions */ + { sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */ + sizeof(float) } + ); + }) + ; + + + // test_inherited_protocol + class SquareMatrix : public Matrix { + public: + SquareMatrix(ssize_t n) : Matrix(n, n) { } + }; + // Derived classes inherit the buffer protocol and the buffer access function + py::class_(m, "SquareMatrix") + .def(py::init()); + + + // test_pointer_to_member_fn + // Tests that passing a pointer to member to the base class works in + // the derived class. + struct Buffer { + int32_t value = 0; + + py::buffer_info get_buffer_info() { + return py::buffer_info(&value, sizeof(value), + py::format_descriptor::format(), 1); + } + }; + py::class_(m, "Buffer", py::buffer_protocol()) + .def(py::init<>()) + .def_readwrite("value", &Buffer::value) + .def_buffer(&Buffer::get_buffer_info); + + + class ConstBuffer { + std::unique_ptr value; + + public: + int32_t get_value() const { return *value; } + void set_value(int32_t v) { *value = v; } + + py::buffer_info get_buffer_info() const { + return py::buffer_info(value.get(), sizeof(*value), + py::format_descriptor::format(), 1); + } + + ConstBuffer() : value(new int32_t{0}) { }; + }; + py::class_(m, "ConstBuffer", py::buffer_protocol()) + .def(py::init<>()) + .def_property("value", &ConstBuffer::get_value, &ConstBuffer::set_value) + .def_buffer(&ConstBuffer::get_buffer_info); + + struct DerivedBuffer : public Buffer { }; + py::class_(m, "DerivedBuffer", py::buffer_protocol()) + .def(py::init<>()) + .def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value) + .def_buffer(&DerivedBuffer::get_buffer_info); + +} diff --git a/pybind11/tests/test_buffers.py b/pybind11/tests/test_buffers.py new file mode 100644 index 0000000..f006552 --- /dev/null +++ b/pybind11/tests/test_buffers.py @@ -0,0 +1,87 @@ +import struct +import pytest +from pybind11_tests import buffers as m +from pybind11_tests import ConstructorStats + +pytestmark = pytest.requires_numpy + +with pytest.suppress(ImportError): + import numpy as np + + +def test_from_python(): + with pytest.raises(RuntimeError) as excinfo: + m.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 = m.Matrix(m3) + + for i in range(m4.rows()): + for j in range(m4.cols()): + assert m3[i, j] == m4[i, j] + + cstats = ConstructorStats.get(m.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 + + +# PyPy: Memory leak in the "np.array(m, copy=False)" call +# https://bitbucket.org/pypy/pypy/issues/2444 +@pytest.unsupported_on_pypy +def test_to_python(): + mat = m.Matrix(5, 4) + assert memoryview(mat).shape == (5, 4) + + assert mat[2, 3] == 0 + mat[2, 3] = 4.0 + mat[3, 2] = 7.0 + assert mat[2, 3] == 4 + assert mat[3, 2] == 7 + assert struct.unpack_from('f', mat, (3 * 4 + 2) * 4) == (7, ) + assert struct.unpack_from('f', mat, (2 * 4 + 3) * 4) == (4, ) + + mat2 = np.array(mat, copy=False) + assert mat2.shape == (5, 4) + assert abs(mat2).sum() == 11 + assert mat2[2, 3] == 4 and mat2[3, 2] == 7 + mat2[2, 3] = 5 + assert mat2[2, 3] == 5 + + cstats = ConstructorStats.get(m.Matrix) + assert cstats.alive() == 1 + del mat + pytest.gc_collect() + assert cstats.alive() == 1 + del mat2 # holds a mat reference + pytest.gc_collect() + assert cstats.alive() == 0 + assert cstats.values() == ["5x4 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.unsupported_on_pypy +def test_inherited_protocol(): + """SquareMatrix is derived from Matrix and inherits the buffer protocol""" + + matrix = m.SquareMatrix(5) + assert memoryview(matrix).shape == (5, 5) + assert np.asarray(matrix).shape == (5, 5) + + +@pytest.unsupported_on_pypy +def test_pointer_to_member_fn(): + for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]: + buf = cls() + buf.value = 0x12345678 + value = struct.unpack('i', bytearray(buf))[0] + assert value == 0x12345678 diff --git a/pybind11/tests/test_builtin_casters.cpp b/pybind11/tests/test_builtin_casters.cpp new file mode 100644 index 0000000..e026127 --- /dev/null +++ b/pybind11/tests/test_builtin_casters.cpp @@ -0,0 +1,170 @@ +/* + tests/test_builtin_casters.cpp -- Casters available without any additional headers + + Copyright (c) 2017 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 + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +TEST_SUBMODULE(builtin_casters, m) { + // test_simple_string + m.def("string_roundtrip", [](const char *s) { return s; }); + + // test_unicode_conversion + // Some test characters in utf16 and utf32 encodings. The last one (the 𝐀) contains a null byte + char32_t a32 = 0x61 /*a*/, z32 = 0x7a /*z*/, ib32 = 0x203d /*‽*/, cake32 = 0x1f382 /*🎂*/, mathbfA32 = 0x1d400 /*𝐀*/; + char16_t b16 = 0x62 /*b*/, z16 = 0x7a, ib16 = 0x203d, cake16_1 = 0xd83c, cake16_2 = 0xdf82, mathbfA16_1 = 0xd835, mathbfA16_2 = 0xdc00; + std::wstring wstr; + wstr.push_back(0x61); // a + wstr.push_back(0x2e18); // ⸘ + if (sizeof(wchar_t) == 2) { wstr.push_back(mathbfA16_1); wstr.push_back(mathbfA16_2); } // 𝐀, utf16 + else { wstr.push_back((wchar_t) mathbfA32); } // 𝐀, utf32 + wstr.push_back(0x7a); // z + + m.def("good_utf8_string", []() { return std::string(u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 𝐀 + m.def("good_utf16_string", [=]() { return std::u16string({ b16, ib16, cake16_1, cake16_2, mathbfA16_1, mathbfA16_2, z16 }); }); // b‽🎂𝐀z + m.def("good_utf32_string", [=]() { return std::u32string({ a32, mathbfA32, cake32, ib32, z32 }); }); // a𝐀🎂‽z + m.def("good_wchar_string", [=]() { return wstr; }); // a‽𝐀z + m.def("bad_utf8_string", []() { return std::string("abc\xd0" "def"); }); + m.def("bad_utf16_string", [=]() { return std::u16string({ b16, char16_t(0xd800), z16 }); }); + // Under Python 2.7, invalid unicode UTF-32 characters don't appear to trigger UnicodeDecodeError + if (PY_MAJOR_VERSION >= 3) + m.def("bad_utf32_string", [=]() { return std::u32string({ a32, char32_t(0xd800), z32 }); }); + if (PY_MAJOR_VERSION >= 3 || sizeof(wchar_t) == 2) + m.def("bad_wchar_string", [=]() { return std::wstring({ wchar_t(0x61), wchar_t(0xd800) }); }); + m.def("u8_Z", []() -> char { return 'Z'; }); + m.def("u8_eacute", []() -> char { return '\xe9'; }); + m.def("u16_ibang", [=]() -> char16_t { return ib16; }); + m.def("u32_mathbfA", [=]() -> char32_t { return mathbfA32; }); + m.def("wchar_heart", []() -> wchar_t { return 0x2665; }); + + // test_single_char_arguments + m.attr("wchar_size") = py::cast(sizeof(wchar_t)); + m.def("ord_char", [](char c) -> int { return static_cast(c); }); + m.def("ord_char_lv", [](char &c) -> int { return static_cast(c); }); + m.def("ord_char16", [](char16_t c) -> uint16_t { return c; }); + m.def("ord_char16_lv", [](char16_t &c) -> uint16_t { return c; }); + m.def("ord_char32", [](char32_t c) -> uint32_t { return c; }); + m.def("ord_wchar", [](wchar_t c) -> int { return c; }); + + // test_bytes_to_string + m.def("strlen", [](char *s) { return strlen(s); }); + m.def("string_length", [](std::string s) { return s.length(); }); + + // test_string_view +#ifdef PYBIND11_HAS_STRING_VIEW + m.attr("has_string_view") = true; + m.def("string_view_print", [](std::string_view s) { py::print(s, s.size()); }); + m.def("string_view16_print", [](std::u16string_view s) { py::print(s, s.size()); }); + m.def("string_view32_print", [](std::u32string_view s) { py::print(s, s.size()); }); + m.def("string_view_chars", [](std::string_view s) { py::list l; for (auto c : s) l.append((std::uint8_t) c); return l; }); + m.def("string_view16_chars", [](std::u16string_view s) { py::list l; for (auto c : s) l.append((int) c); return l; }); + m.def("string_view32_chars", [](std::u32string_view s) { py::list l; for (auto c : s) l.append((int) c); return l; }); + m.def("string_view_return", []() { return std::string_view(u8"utf8 secret \U0001f382"); }); + m.def("string_view16_return", []() { return std::u16string_view(u"utf16 secret \U0001f382"); }); + m.def("string_view32_return", []() { return std::u32string_view(U"utf32 secret \U0001f382"); }); +#endif + + // test_integer_casting + m.def("i32_str", [](std::int32_t v) { return std::to_string(v); }); + m.def("u32_str", [](std::uint32_t v) { return std::to_string(v); }); + m.def("i64_str", [](std::int64_t v) { return std::to_string(v); }); + m.def("u64_str", [](std::uint64_t v) { return std::to_string(v); }); + + // test_tuple + m.def("pair_passthrough", [](std::pair input) { + return std::make_pair(input.second, input.first); + }, "Return a pair in reversed order"); + m.def("tuple_passthrough", [](std::tuple input) { + return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input)); + }, "Return a triple in reversed order"); + m.def("empty_tuple", []() { return std::tuple<>(); }); + static std::pair lvpair; + static std::tuple lvtuple; + static std::pair>> lvnested; + m.def("rvalue_pair", []() { return std::make_pair(RValueCaster{}, RValueCaster{}); }); + m.def("lvalue_pair", []() -> const decltype(lvpair) & { return lvpair; }); + m.def("rvalue_tuple", []() { return std::make_tuple(RValueCaster{}, RValueCaster{}, RValueCaster{}); }); + m.def("lvalue_tuple", []() -> const decltype(lvtuple) & { return lvtuple; }); + m.def("rvalue_nested", []() { + return std::make_pair(RValueCaster{}, std::make_tuple(RValueCaster{}, std::make_pair(RValueCaster{}, RValueCaster{}))); }); + m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; }); + + // test_builtins_cast_return_none + m.def("return_none_string", []() -> std::string * { return nullptr; }); + m.def("return_none_char", []() -> const char * { return nullptr; }); + m.def("return_none_bool", []() -> bool * { return nullptr; }); + m.def("return_none_int", []() -> int * { return nullptr; }); + m.def("return_none_float", []() -> float * { return nullptr; }); + + // test_none_deferred + m.def("defer_none_cstring", [](char *) { return false; }); + m.def("defer_none_cstring", [](py::none) { return true; }); + m.def("defer_none_custom", [](UserType *) { return false; }); + m.def("defer_none_custom", [](py::none) { return true; }); + m.def("nodefer_none_void", [](void *) { return true; }); + m.def("nodefer_none_void", [](py::none) { return false; }); + + // test_void_caster + m.def("load_nullptr_t", [](std::nullptr_t) {}); // not useful, but it should still compile + m.def("cast_nullptr_t", []() { return std::nullptr_t{}; }); + + // test_bool_caster + m.def("bool_passthrough", [](bool arg) { return arg; }); + m.def("bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg().noconvert()); + + // test_reference_wrapper + m.def("refwrap_builtin", [](std::reference_wrapper p) { return 10 * p.get(); }); + m.def("refwrap_usertype", [](std::reference_wrapper p) { return p.get().value(); }); + // Not currently supported (std::pair caster has return-by-value cast operator); + // triggers static_assert failure. + //m.def("refwrap_pair", [](std::reference_wrapper>) { }); + + m.def("refwrap_list", [](bool copy) { + static IncType x1(1), x2(2); + py::list l; + for (auto &f : {std::ref(x1), std::ref(x2)}) { + l.append(py::cast(f, copy ? py::return_value_policy::copy + : py::return_value_policy::reference)); + } + return l; + }, "copy"_a); + + m.def("refwrap_iiw", [](const IncType &w) { return w.value(); }); + m.def("refwrap_call_iiw", [](IncType &w, py::function f) { + py::list l; + l.append(f(std::ref(w))); + l.append(f(std::cref(w))); + IncType x(w.value()); + l.append(f(std::ref(x))); + IncType y(w.value()); + auto r3 = std::ref(y); + l.append(f(r3)); + return l; + }); + + // test_complex + m.def("complex_cast", [](float x) { return "{}"_s.format(x); }); + m.def("complex_cast", [](std::complex x) { return "({}, {})"_s.format(x.real(), x.imag()); }); + + // test int vs. long (Python 2) + m.def("int_cast", []() {return (int) 42;}); + m.def("long_cast", []() {return (long) 42;}); + m.def("longlong_cast", []() {return ULLONG_MAX;}); + + /// test void* cast operator + m.def("test_void_caster", []() -> bool { + void *v = (void *) 0xabcd; + py::object o = py::cast(v); + return py::cast(o) == v; + }); +} diff --git a/pybind11/tests/test_builtin_casters.py b/pybind11/tests/test_builtin_casters.py new file mode 100644 index 0000000..73cc465 --- /dev/null +++ b/pybind11/tests/test_builtin_casters.py @@ -0,0 +1,342 @@ +# Python < 3 needs this: coding=utf-8 +import pytest + +from pybind11_tests import builtin_casters as m +from pybind11_tests import UserType, IncType + + +def test_simple_string(): + assert m.string_roundtrip("const char *") == "const char *" + + +def test_unicode_conversion(): + """Tests unicode conversion and error reporting.""" + assert m.good_utf8_string() == u"Say utf8‽ 🎂 𝐀" + assert m.good_utf16_string() == u"b‽🎂𝐀z" + assert m.good_utf32_string() == u"a𝐀🎂‽z" + assert m.good_wchar_string() == u"a⸘𝐀z" + + with pytest.raises(UnicodeDecodeError): + m.bad_utf8_string() + + with pytest.raises(UnicodeDecodeError): + m.bad_utf16_string() + + # These are provided only if they actually fail (they don't when 32-bit and under Python 2.7) + if hasattr(m, "bad_utf32_string"): + with pytest.raises(UnicodeDecodeError): + m.bad_utf32_string() + if hasattr(m, "bad_wchar_string"): + with pytest.raises(UnicodeDecodeError): + m.bad_wchar_string() + + assert m.u8_Z() == 'Z' + assert m.u8_eacute() == u'é' + assert m.u16_ibang() == u'‽' + assert m.u32_mathbfA() == u'𝐀' + assert m.wchar_heart() == u'♥' + + +def test_single_char_arguments(): + """Tests failures for passing invalid inputs to char-accepting functions""" + def toobig_message(r): + return "Character code point not in range({0:#x})".format(r) + toolong_message = "Expected a character, but multi-character string found" + + assert m.ord_char(u'a') == 0x61 # simple ASCII + assert m.ord_char_lv(u'b') == 0x62 + assert m.ord_char(u'é') == 0xE9 # requires 2 bytes in utf-8, but can be stuffed in a char + with pytest.raises(ValueError) as excinfo: + assert m.ord_char(u'Ā') == 0x100 # requires 2 bytes, doesn't fit in a char + assert str(excinfo.value) == toobig_message(0x100) + with pytest.raises(ValueError) as excinfo: + assert m.ord_char(u'ab') + assert str(excinfo.value) == toolong_message + + assert m.ord_char16(u'a') == 0x61 + assert m.ord_char16(u'é') == 0xE9 + assert m.ord_char16_lv(u'ê') == 0xEA + assert m.ord_char16(u'Ā') == 0x100 + assert m.ord_char16(u'‽') == 0x203d + assert m.ord_char16(u'♥') == 0x2665 + assert m.ord_char16_lv(u'♡') == 0x2661 + with pytest.raises(ValueError) as excinfo: + assert m.ord_char16(u'🎂') == 0x1F382 # requires surrogate pair + assert str(excinfo.value) == toobig_message(0x10000) + with pytest.raises(ValueError) as excinfo: + assert m.ord_char16(u'aa') + assert str(excinfo.value) == toolong_message + + assert m.ord_char32(u'a') == 0x61 + assert m.ord_char32(u'é') == 0xE9 + assert m.ord_char32(u'Ā') == 0x100 + assert m.ord_char32(u'‽') == 0x203d + assert m.ord_char32(u'♥') == 0x2665 + assert m.ord_char32(u'🎂') == 0x1F382 + with pytest.raises(ValueError) as excinfo: + assert m.ord_char32(u'aa') + assert str(excinfo.value) == toolong_message + + assert m.ord_wchar(u'a') == 0x61 + assert m.ord_wchar(u'é') == 0xE9 + assert m.ord_wchar(u'Ā') == 0x100 + assert m.ord_wchar(u'‽') == 0x203d + assert m.ord_wchar(u'♥') == 0x2665 + if m.wchar_size == 2: + with pytest.raises(ValueError) as excinfo: + assert m.ord_wchar(u'🎂') == 0x1F382 # requires surrogate pair + assert str(excinfo.value) == toobig_message(0x10000) + else: + assert m.ord_wchar(u'🎂') == 0x1F382 + with pytest.raises(ValueError) as excinfo: + assert m.ord_wchar(u'aa') + assert str(excinfo.value) == toolong_message + + +def test_bytes_to_string(): + """Tests the ability to pass bytes to C++ string-accepting functions. Note that this is + one-way: the only way to return bytes to Python is via the pybind11::bytes class.""" + # Issue #816 + import sys + byte = bytes if sys.version_info[0] < 3 else str + + assert m.strlen(byte("hi")) == 2 + assert m.string_length(byte("world")) == 5 + assert m.string_length(byte("a\x00b")) == 3 + assert m.strlen(byte("a\x00b")) == 1 # C-string limitation + + # passing in a utf8 encoded string should work + assert m.string_length(u'💩'.encode("utf8")) == 4 + + +@pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no ") +def test_string_view(capture): + """Tests support for C++17 string_view arguments and return values""" + assert m.string_view_chars("Hi") == [72, 105] + assert m.string_view_chars("Hi 🎂") == [72, 105, 32, 0xf0, 0x9f, 0x8e, 0x82] + assert m.string_view16_chars("Hi 🎂") == [72, 105, 32, 0xd83c, 0xdf82] + assert m.string_view32_chars("Hi 🎂") == [72, 105, 32, 127874] + + assert m.string_view_return() == "utf8 secret 🎂" + assert m.string_view16_return() == "utf16 secret 🎂" + assert m.string_view32_return() == "utf32 secret 🎂" + + with capture: + m.string_view_print("Hi") + m.string_view_print("utf8 🎂") + m.string_view16_print("utf16 🎂") + m.string_view32_print("utf32 🎂") + assert capture == """ + Hi 2 + utf8 🎂 9 + utf16 🎂 8 + utf32 🎂 7 + """ + + with capture: + m.string_view_print("Hi, ascii") + m.string_view_print("Hi, utf8 🎂") + m.string_view16_print("Hi, utf16 🎂") + m.string_view32_print("Hi, utf32 🎂") + assert capture == """ + Hi, ascii 9 + Hi, utf8 🎂 13 + Hi, utf16 🎂 12 + Hi, utf32 🎂 11 + """ + + +def test_integer_casting(): + """Issue #929 - out-of-range integer values shouldn't be accepted""" + import sys + assert m.i32_str(-1) == "-1" + assert m.i64_str(-1) == "-1" + assert m.i32_str(2000000000) == "2000000000" + assert m.u32_str(2000000000) == "2000000000" + if sys.version_info < (3,): + assert m.i32_str(long(-1)) == "-1" # noqa: F821 undefined name 'long' + assert m.i64_str(long(-1)) == "-1" # noqa: F821 undefined name 'long' + assert m.i64_str(long(-999999999999)) == "-999999999999" # noqa: F821 undefined name + assert m.u64_str(long(999999999999)) == "999999999999" # noqa: F821 undefined name 'long' + else: + assert m.i64_str(-999999999999) == "-999999999999" + assert m.u64_str(999999999999) == "999999999999" + + with pytest.raises(TypeError) as excinfo: + m.u32_str(-1) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.u64_str(-1) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.i32_str(-3000000000) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.i32_str(3000000000) + assert "incompatible function arguments" in str(excinfo.value) + + if sys.version_info < (3,): + with pytest.raises(TypeError) as excinfo: + m.u32_str(long(-1)) # noqa: F821 undefined name 'long' + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.u64_str(long(-1)) # noqa: F821 undefined name 'long' + assert "incompatible function arguments" in str(excinfo.value) + + +def test_tuple(doc): + """std::pair <-> tuple & std::tuple <-> tuple""" + assert m.pair_passthrough((True, "test")) == ("test", True) + assert m.tuple_passthrough((True, "test", 5)) == (5, "test", True) + # Any sequence can be cast to a std::pair or std::tuple + assert m.pair_passthrough([True, "test"]) == ("test", True) + assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True) + assert m.empty_tuple() == () + + assert doc(m.pair_passthrough) == """ + pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool] + + Return a pair in reversed order + """ + assert doc(m.tuple_passthrough) == """ + tuple_passthrough(arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool] + + Return a triple in reversed order + """ + + assert m.rvalue_pair() == ("rvalue", "rvalue") + assert m.lvalue_pair() == ("lvalue", "lvalue") + assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue") + assert m.lvalue_tuple() == ("lvalue", "lvalue", "lvalue") + assert m.rvalue_nested() == ("rvalue", ("rvalue", ("rvalue", "rvalue"))) + assert m.lvalue_nested() == ("lvalue", ("lvalue", ("lvalue", "lvalue"))) + + +def test_builtins_cast_return_none(): + """Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None""" + assert m.return_none_string() is None + assert m.return_none_char() is None + assert m.return_none_bool() is None + assert m.return_none_int() is None + assert m.return_none_float() is None + + +def test_none_deferred(): + """None passed as various argument types should defer to other overloads""" + assert not m.defer_none_cstring("abc") + assert m.defer_none_cstring(None) + assert not m.defer_none_custom(UserType()) + assert m.defer_none_custom(None) + assert m.nodefer_none_void(None) + + +def test_void_caster(): + assert m.load_nullptr_t(None) is None + assert m.cast_nullptr_t() is None + + +def test_reference_wrapper(): + """std::reference_wrapper for builtin and user types""" + assert m.refwrap_builtin(42) == 420 + assert m.refwrap_usertype(UserType(42)) == 42 + + with pytest.raises(TypeError) as excinfo: + m.refwrap_builtin(None) + assert "incompatible function arguments" in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + m.refwrap_usertype(None) + assert "incompatible function arguments" in str(excinfo.value) + + a1 = m.refwrap_list(copy=True) + a2 = m.refwrap_list(copy=True) + assert [x.value for x in a1] == [2, 3] + assert [x.value for x in a2] == [2, 3] + assert not a1[0] is a2[0] and not a1[1] is a2[1] + + b1 = m.refwrap_list(copy=False) + b2 = m.refwrap_list(copy=False) + assert [x.value for x in b1] == [1, 2] + assert [x.value for x in b2] == [1, 2] + assert b1[0] is b2[0] and b1[1] is b2[1] + + assert m.refwrap_iiw(IncType(5)) == 5 + assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10] + + +def test_complex_cast(): + """std::complex casts""" + assert m.complex_cast(1) == "1.0" + assert m.complex_cast(2j) == "(0.0, 2.0)" + + +def test_bool_caster(): + """Test bool caster implicit conversions.""" + convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert + + def require_implicit(v): + pytest.raises(TypeError, noconvert, v) + + def cant_convert(v): + pytest.raises(TypeError, convert, v) + + # straight up bool + assert convert(True) is True + assert convert(False) is False + assert noconvert(True) is True + assert noconvert(False) is False + + # None requires implicit conversion + require_implicit(None) + assert convert(None) is False + + class A(object): + def __init__(self, x): + self.x = x + + def __nonzero__(self): + return self.x + + def __bool__(self): + return self.x + + class B(object): + pass + + # Arbitrary objects are not accepted + cant_convert(object()) + cant_convert(B()) + + # Objects with __nonzero__ / __bool__ defined can be converted + require_implicit(A(True)) + assert convert(A(True)) is True + assert convert(A(False)) is False + + +@pytest.requires_numpy +def test_numpy_bool(): + import numpy as np + convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert + + # np.bool_ is not considered implicit + assert convert(np.bool_(True)) is True + assert convert(np.bool_(False)) is False + assert noconvert(np.bool_(True)) is True + assert noconvert(np.bool_(False)) is False + + +def test_int_long(): + """In Python 2, a C++ int should return a Python int rather than long + if possible: longs are not always accepted where ints are used (such + as the argument to sys.exit()). A C++ long long is always a Python + long.""" + + import sys + must_be_long = type(getattr(sys, 'maxint', 1) + 1) + assert isinstance(m.int_cast(), int) + assert isinstance(m.long_cast(), int) + assert isinstance(m.longlong_cast(), must_be_long) + + +def test_void_caster_2(): + assert m.test_void_caster() diff --git a/pybind11/tests/test_call_policies.cpp b/pybind11/tests/test_call_policies.cpp new file mode 100644 index 0000000..fd24557 --- /dev/null +++ b/pybind11/tests/test_call_policies.cpp @@ -0,0 +1,100 @@ +/* + tests/test_call_policies.cpp -- keep_alive and call_guard + + 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 CustomGuard { + static bool enabled; + + CustomGuard() { enabled = true; } + ~CustomGuard() { enabled = false; } + + static const char *report_status() { return enabled ? "guarded" : "unguarded"; } +}; +bool CustomGuard::enabled = false; + +struct DependentGuard { + static bool enabled; + + DependentGuard() { enabled = CustomGuard::enabled; } + ~DependentGuard() { enabled = false; } + + static const char *report_status() { return enabled ? "guarded" : "unguarded"; } +}; +bool DependentGuard::enabled = false; + +TEST_SUBMODULE(call_policies, m) { + // Parent/Child are used in: + // test_keep_alive_argument, test_keep_alive_return_value, test_alive_gc_derived, + // test_alive_gc_multi_derived, test_return_none, test_keep_alive_constructor + class Child { + public: + Child() { py::print("Allocating child."); } + Child(const Child &) = default; + Child(Child &&) = default; + ~Child() { py::print("Releasing child."); } + }; + py::class_(m, "Child") + .def(py::init<>()); + + 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; } + }; + py::class_(m, "Parent") + .def(py::init<>()) + .def(py::init([](Child *) { return new Parent(); }), py::keep_alive<1, 2>()) + .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>()); + +#if !defined(PYPY_VERSION) + // test_alive_gc + class ParentGC : public Parent { + public: + using Parent::Parent; + }; + py::class_(m, "ParentGC", py::dynamic_attr()) + .def(py::init<>()); +#endif + + // test_call_guard + m.def("unguarded_call", &CustomGuard::report_status); + m.def("guarded_call", &CustomGuard::report_status, py::call_guard()); + + m.def("multiple_guards_correct_order", []() { + return CustomGuard::report_status() + std::string(" & ") + DependentGuard::report_status(); + }, py::call_guard()); + + m.def("multiple_guards_wrong_order", []() { + return DependentGuard::report_status() + std::string(" & ") + CustomGuard::report_status(); + }, py::call_guard()); + +#if defined(WITH_THREAD) && !defined(PYPY_VERSION) + // `py::call_guard()` should work in PyPy as well, + // but it's unclear how to test it without `PyGILState_GetThisThreadState`. + auto report_gil_status = []() { + auto is_gil_held = false; + if (auto tstate = py::detail::get_thread_state_unchecked()) + is_gil_held = (tstate == PyGILState_GetThisThreadState()); + + return is_gil_held ? "GIL held" : "GIL released"; + }; + + m.def("with_gil", report_gil_status); + m.def("without_gil", report_gil_status, py::call_guard()); +#endif +} diff --git a/pybind11/tests/test_call_policies.py b/pybind11/tests/test_call_policies.py new file mode 100644 index 0000000..7c83559 --- /dev/null +++ b/pybind11/tests/test_call_policies.py @@ -0,0 +1,187 @@ +import pytest +from pybind11_tests import call_policies as m +from pybind11_tests import ConstructorStats + + +def test_keep_alive_argument(capture): + n_inst = ConstructorStats.detail_reg_inst() + with capture: + p = m.Parent() + assert capture == "Allocating parent." + with capture: + p.addChild(m.Child()) + assert ConstructorStats.detail_reg_inst() == n_inst + 1 + assert capture == """ + Allocating child. + Releasing child. + """ + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == "Releasing parent." + + with capture: + p = m.Parent() + assert capture == "Allocating parent." + with capture: + p.addChildKeepAlive(m.Child()) + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + assert capture == "Allocating child." + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == """ + Releasing parent. + Releasing child. + """ + + +def test_keep_alive_return_value(capture): + n_inst = ConstructorStats.detail_reg_inst() + with capture: + p = m.Parent() + assert capture == "Allocating parent." + with capture: + p.returnChild() + assert ConstructorStats.detail_reg_inst() == n_inst + 1 + assert capture == """ + Allocating child. + Releasing child. + """ + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == "Releasing parent." + + with capture: + p = m.Parent() + assert capture == "Allocating parent." + with capture: + p.returnChildKeepAlive() + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + assert capture == "Allocating child." + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == """ + Releasing parent. + Releasing child. + """ + + +# https://bitbucket.org/pypy/pypy/issues/2447 +@pytest.unsupported_on_pypy +def test_alive_gc(capture): + n_inst = ConstructorStats.detail_reg_inst() + p = m.ParentGC() + p.addChildKeepAlive(m.Child()) + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + lst = [p] + lst.append(lst) # creates a circular reference + with capture: + del p, lst + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == """ + Releasing parent. + Releasing child. + """ + + +def test_alive_gc_derived(capture): + class Derived(m.Parent): + pass + + n_inst = ConstructorStats.detail_reg_inst() + p = Derived() + p.addChildKeepAlive(m.Child()) + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + lst = [p] + lst.append(lst) # creates a circular reference + with capture: + del p, lst + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == """ + Releasing parent. + Releasing child. + """ + + +def test_alive_gc_multi_derived(capture): + class Derived(m.Parent, m.Child): + def __init__(self): + m.Parent.__init__(self) + m.Child.__init__(self) + + n_inst = ConstructorStats.detail_reg_inst() + p = Derived() + p.addChildKeepAlive(m.Child()) + # +3 rather than +2 because Derived corresponds to two registered instances + assert ConstructorStats.detail_reg_inst() == n_inst + 3 + lst = [p] + lst.append(lst) # creates a circular reference + with capture: + del p, lst + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == """ + Releasing parent. + Releasing child. + Releasing child. + """ + + +def test_return_none(capture): + n_inst = ConstructorStats.detail_reg_inst() + with capture: + p = m.Parent() + assert capture == "Allocating parent." + with capture: + p.returnNullChildKeepAliveChild() + assert ConstructorStats.detail_reg_inst() == n_inst + 1 + assert capture == "" + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == "Releasing parent." + + with capture: + p = m.Parent() + assert capture == "Allocating parent." + with capture: + p.returnNullChildKeepAliveParent() + assert ConstructorStats.detail_reg_inst() == n_inst + 1 + assert capture == "" + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == "Releasing parent." + + +def test_keep_alive_constructor(capture): + n_inst = ConstructorStats.detail_reg_inst() + + with capture: + p = m.Parent(m.Child()) + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + assert capture == """ + Allocating child. + Allocating parent. + """ + with capture: + del p + assert ConstructorStats.detail_reg_inst() == n_inst + assert capture == """ + Releasing parent. + Releasing child. + """ + + +def test_call_guard(): + assert m.unguarded_call() == "unguarded" + assert m.guarded_call() == "guarded" + + assert m.multiple_guards_correct_order() == "guarded & guarded" + assert m.multiple_guards_wrong_order() == "unguarded & guarded" + + if hasattr(m, "with_gil"): + assert m.with_gil() == "GIL held" + assert m.without_gil() == "GIL released" diff --git a/pybind11/tests/test_callbacks.cpp b/pybind11/tests/test_callbacks.cpp new file mode 100644 index 0000000..273eacc --- /dev/null +++ b/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 + + +int dummy_function(int i) { return i + 1; } + +TEST_SUBMODULE(callbacks, m) { + // test_callbacks, test_function_signatures + m.def("test_callback1", [](py::object func) { return func(); }); + m.def("test_callback2", [](py::object func) { return func("Hello", 'x', true, 5); }); + m.def("test_callback3", [](const std::function &func) { + return "func(43) = " + std::to_string(func(43)); }); + m.def("test_callback4", []() -> std::function { return [](int i) { return i+1; }; }); + m.def("test_callback5", []() { + return py::cpp_function([](int i) { return i+1; }, py::arg("number")); + }); + + // 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, UnregisteredType(), "kw"_a=567); + }); + + m.def("test_arg_conversion_error2", [](py::function f) { + f(234, "expected_name"_a=UnregisteredType(), "kw"_a=567); + }); + + // test_lambda_closure_cleanup + struct Payload { + Payload() { print_default_created(this); } + ~Payload() { print_destroyed(this); } + Payload(const Payload &) { print_copy_created(this); } + Payload(Payload &&) { print_move_created(this); } + }; + // Export the payload constructor statistics for testing purposes: + m.def("payload_cstats", &ConstructorStats::get); + /* 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 */ + (void) p; + }; + }); + + // test_cpp_function_roundtrip + /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */ + m.def("dummy_function", &dummy_function); + m.def("dummy_function2", [](int i, int j) { return i + j; }); + m.def("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; + }, py::arg("f"), py::arg("expect_none")=false); + m.def("test_dummy_function", [](const std::function &f) -> std::string { + 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!"; + } + }); + + class AbstractBase { public: virtual unsigned int func() = 0; }; + m.def("func_accepting_func_accepting_base", [](std::function) { }); + + struct MovableObject { + bool valid = true; + + MovableObject() = default; + MovableObject(const MovableObject &) = default; + MovableObject &operator=(const MovableObject &) = default; + MovableObject(MovableObject &&o) : valid(o.valid) { o.valid = false; } + MovableObject &operator=(MovableObject &&o) { + valid = o.valid; + o.valid = false; + return *this; + } + }; + py::class_(m, "MovableObject"); + + // test_movable_object + m.def("callback_with_movable", [](std::function f) { + auto x = MovableObject(); + f(x); // lvalue reference shouldn't move out object + return x.valid; // must still return `true` + }); + + // test_bound_method_callback + struct CppBoundMethodTest {}; + py::class_(m, "CppBoundMethodTest") + .def(py::init<>()) + .def("triple", [](CppBoundMethodTest &, int val) { return 3 * val; }); +} diff --git a/pybind11/tests/test_callbacks.py b/pybind11/tests/test_callbacks.py new file mode 100644 index 0000000..93c42c2 --- /dev/null +++ b/pybind11/tests/test_callbacks.py @@ -0,0 +1,107 @@ +import pytest +from pybind11_tests import callbacks as m + + +def test_callbacks(): + from functools import partial + + def func1(): + return "func1" + + def func2(a, b, c, d): + return "func2", a, b, c, d + + def func3(a): + return "func3({})".format(a) + + assert m.test_callback1(func1) == "func1" + assert m.test_callback2(func2) == ("func2", "Hello", "x", True, 5) + assert m.test_callback1(partial(func2, 1, 2, 3, 4)) == ("func2", 1, 2, 3, 4) + assert m.test_callback1(partial(func3, "partial")) == "func3(partial)" + assert m.test_callback3(lambda i: i + 1) == "func(43) = 44" + + f = m.test_callback4() + assert f(43) == 44 + f = m.test_callback5() + assert f(number=43) == 44 + + +def test_bound_method_callback(): + # Bound Python method: + class MyClass: + def double(self, val): + return 2 * val + + z = MyClass() + assert m.test_callback3(z.double) == "func(43) = 86" + + z = m.CppBoundMethodTest() + assert m.test_callback3(z.triple) == "func(43) = 129" + + +def test_keyword_args_and_generalized_unpacking(): + + def f(*args, **kwargs): + return args, kwargs + + assert m.test_tuple_unpacking(f) == (("positional", 1, 2, 3, 4, 5, 6), {}) + assert m.test_dict_unpacking(f) == (("positional", 1), {"key": "value", "a": 1, "b": 2}) + assert m.test_keyword_args(f) == ((), {"x": 10, "y": 20}) + assert m.test_unpacking_and_keywords1(f) == ((1, 2), {"c": 3, "d": 4}) + assert m.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: + m.test_unpacking_error1(f) + assert "Got multiple values for keyword argument" in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + m.test_unpacking_error2(f) + assert "Got multiple values for keyword argument" in str(excinfo.value) + + with pytest.raises(RuntimeError) as excinfo: + m.test_arg_conversion_error1(f) + assert "Unable to convert call argument" in str(excinfo.value) + + with pytest.raises(RuntimeError) as excinfo: + m.test_arg_conversion_error2(f) + assert "Unable to convert call argument" in str(excinfo.value) + + +def test_lambda_closure_cleanup(): + m.test_cleanup() + cstats = m.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""" + + assert m.test_dummy_function(m.dummy_function) == "matches dummy_function: eval(1) = 2" + assert (m.test_dummy_function(m.roundtrip(m.dummy_function)) == + "matches dummy_function: eval(1) = 2") + assert m.roundtrip(None, expect_none=True) is None + assert (m.test_dummy_function(lambda x: x + 2) == + "can't convert to function pointer: eval(1) = 3") + + with pytest.raises(TypeError) as excinfo: + m.test_dummy_function(m.dummy_function2) + assert "incompatible function arguments" in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + m.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): + assert doc(m.test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str" + assert doc(m.test_callback4) == "test_callback4() -> Callable[[int], int]" + + +def test_movable_object(): + assert m.callback_with_movable(lambda _: None) is True diff --git a/pybind11/tests/test_chrono.cpp b/pybind11/tests/test_chrono.cpp new file mode 100644 index 0000000..195a93b --- /dev/null +++ b/pybind11/tests/test_chrono.cpp @@ -0,0 +1,47 @@ +/* + 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 + +TEST_SUBMODULE(chrono, m) { + using system_time = std::chrono::system_clock::time_point; + using steady_time = std::chrono::steady_clock::time_point; + // test_chrono_system_clock + // Return the current time off the wall clock + m.def("test_chrono1", []() { return std::chrono::system_clock::now(); }); + + // test_chrono_system_clock_roundtrip + // Round trip the passed in system clock time + m.def("test_chrono2", [](system_time t) { return t; }); + + // test_chrono_duration_roundtrip + // Round trip the passed in duration + m.def("test_chrono3", [](std::chrono::system_clock::duration d) { return d; }); + + // test_chrono_duration_subtraction_equivalence + // Difference between two passed in time_points + m.def("test_chrono4", [](system_time a, system_time b) { return a - b; }); + + // test_chrono_steady_clock + // Return the current time off the steady_clock + m.def("test_chrono5", []() { return std::chrono::steady_clock::now(); }); + + // test_chrono_steady_clock_roundtrip + // Round trip a steady clock timepoint + m.def("test_chrono6", [](steady_time t) { return t; }); + + // test_floating_point_duration + // Roundtrip a duration in microseconds from a float argument + m.def("test_chrono7", [](std::chrono::microseconds t) { return t; }); + // Float durations (issue #719) + m.def("test_chrono_float_diff", [](std::chrono::duration a, std::chrono::duration b) { + return a - b; }); +} diff --git a/pybind11/tests/test_chrono.py b/pybind11/tests/test_chrono.py new file mode 100644 index 0000000..2b75bd1 --- /dev/null +++ b/pybind11/tests/test_chrono.py @@ -0,0 +1,101 @@ +from pybind11_tests import chrono as m +import datetime + + +def test_chrono_system_clock(): + + # Get the time from both c++ and datetime + date1 = m.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(): + date1 = datetime.datetime.today() + + # Roundtrip the time + date2 = m.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(): + + # 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 = m.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(): + + date1 = datetime.datetime.today() + date2 = datetime.datetime.today() + + diff = date2 - date1 + cpp_diff = m.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(): + time1 = m.test_chrono5() + assert isinstance(time1, datetime.timedelta) + + +def test_chrono_steady_clock_roundtrip(): + time1 = datetime.timedelta(days=10, seconds=10, microseconds=100) + time2 = m.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(): + # Test using a floating point number in seconds + time = m.test_chrono7(35.525123) + + assert isinstance(time, datetime.timedelta) + + assert time.seconds == 35 + assert 525122 <= time.microseconds <= 525123 + + diff = m.test_chrono_float_diff(43.789012, 1.123456) + assert diff.seconds == 42 + assert 665556 <= diff.microseconds <= 665557 diff --git a/pybind11/tests/test_class.cpp b/pybind11/tests/test_class.cpp new file mode 100644 index 0000000..499d0cc --- /dev/null +++ b/pybind11/tests/test_class.cpp @@ -0,0 +1,422 @@ +/* + tests/test_class.cpp -- test py::class_ definitions and basic functionality + + 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 "local_bindings.h" +#include + +#if defined(_MSC_VER) +# pragma warning(disable: 4324) // warning C4324: structure was padded due to alignment specifier +#endif + +// test_brace_initialization +struct NoBraceInitialization { + NoBraceInitialization(std::vector v) : vec{std::move(v)} {} + template + NoBraceInitialization(std::initializer_list l) : vec(l) {} + + std::vector vec; +}; + +TEST_SUBMODULE(class_, m) { + // test_instance + struct NoConstructor { + NoConstructor() = default; + NoConstructor(const NoConstructor &) = default; + NoConstructor(NoConstructor &&) = default; + static NoConstructor *new_instance() { + auto *ptr = new NoConstructor(); + print_created(ptr, "via new_instance"); + return ptr; + } + ~NoConstructor() { print_destroyed(this); } + }; + + py::class_(m, "NoConstructor") + .def_static("new_instance", &NoConstructor::new_instance, "Return an instance"); + + // test_inheritance + 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") {} + }; + + class Chimera : public Pet { + Chimera() : Pet("Kimmy", "chimera") {} + }; + + 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()); + + /* Constructors are not inherited by default */ + py::class_(m, "Chimera"); + + m.def("pet_name_species", [](const Pet &pet) { return pet.name() + " is a " + pet.species(); }); + m.def("dog_bark", [](const Dog &dog) { return dog.bark(); }); + + // test_automatic_upcasting + struct BaseClass { + BaseClass() = default; + BaseClass(const BaseClass &) = default; + BaseClass(BaseClass &&) = default; + virtual ~BaseClass() {} + }; + struct DerivedClass1 : BaseClass { }; + struct DerivedClass2 : BaseClass { }; + + 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; }); + + // test_isinstance + m.def("check_instances", [](py::list l) { + 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]) + ); + }); + + // test_mismatched_holder + struct MismatchBase1 { }; + struct MismatchDerived1 : MismatchBase1 { }; + + struct MismatchBase2 { }; + struct MismatchDerived2 : MismatchBase2 { }; + + m.def("mismatched_holder_1", []() { + auto mod = py::module::import("__main__"); + py::class_>(mod, "MismatchBase1"); + py::class_(mod, "MismatchDerived1"); + }); + m.def("mismatched_holder_2", []() { + auto mod = py::module::import("__main__"); + py::class_(mod, "MismatchBase2"); + py::class_, + MismatchBase2>(mod, "MismatchDerived2"); + }); + + // test_override_static + // #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_(m, "MyBase") + .def_static("make", &MyBase::make); + + py::class_(m, "MyDerived") + .def_static("make", &MyDerived::make) + .def_static("make2", &MyDerived::make); + + // test_implicit_conversion_life_support + struct ConvertibleFromUserType { + int i; + + ConvertibleFromUserType(UserType u) : i(u.value()) { } + }; + + py::class_(m, "AcceptsUserType") + .def(py::init()); + py::implicitly_convertible(); + + m.def("implicitly_convert_argument", [](const ConvertibleFromUserType &r) { return r.i; }); + m.def("implicitly_convert_variable", [](py::object o) { + // `o` is `UserType` and `r` is a reference to a temporary created by implicit + // conversion. This is valid when called inside a bound function because the temp + // object is attached to the same life support system as the arguments. + const auto &r = o.cast(); + return r.i; + }); + m.add_object("implicitly_convert_variable_fail", [&] { + auto f = [](PyObject *, PyObject *args) -> PyObject * { + auto o = py::reinterpret_borrow(args)[0]; + try { // It should fail here because there is no life support. + o.cast(); + } catch (const py::cast_error &e) { + return py::str(e.what()).release().ptr(); + } + return py::str().release().ptr(); + }; + + auto def = new PyMethodDef{"f", f, METH_VARARGS, nullptr}; + return py::reinterpret_steal(PyCFunction_NewEx(def, nullptr, m.ptr())); + }()); + + // test_operator_new_delete + struct HasOpNewDel { + std::uint64_t i; + static void *operator new(size_t s) { py::print("A new", s); return ::operator new(s); } + static void *operator new(size_t s, void *ptr) { py::print("A placement-new", s); return ptr; } + static void operator delete(void *p) { py::print("A delete"); return ::operator delete(p); } + }; + struct HasOpNewDelSize { + std::uint32_t i; + static void *operator new(size_t s) { py::print("B new", s); return ::operator new(s); } + static void *operator new(size_t s, void *ptr) { py::print("B placement-new", s); return ptr; } + static void operator delete(void *p, size_t s) { py::print("B delete", s); return ::operator delete(p); } + }; + struct AliasedHasOpNewDelSize { + std::uint64_t i; + static void *operator new(size_t s) { py::print("C new", s); return ::operator new(s); } + static void *operator new(size_t s, void *ptr) { py::print("C placement-new", s); return ptr; } + static void operator delete(void *p, size_t s) { py::print("C delete", s); return ::operator delete(p); } + virtual ~AliasedHasOpNewDelSize() = default; + }; + struct PyAliasedHasOpNewDelSize : AliasedHasOpNewDelSize { + PyAliasedHasOpNewDelSize() = default; + PyAliasedHasOpNewDelSize(int) { } + std::uint64_t j; + }; + struct HasOpNewDelBoth { + std::uint32_t i[8]; + static void *operator new(size_t s) { py::print("D new", s); return ::operator new(s); } + static void *operator new(size_t s, void *ptr) { py::print("D placement-new", s); return ptr; } + static void operator delete(void *p) { py::print("D delete"); return ::operator delete(p); } + static void operator delete(void *p, size_t s) { py::print("D wrong delete", s); return ::operator delete(p); } + }; + py::class_(m, "HasOpNewDel").def(py::init<>()); + py::class_(m, "HasOpNewDelSize").def(py::init<>()); + py::class_(m, "HasOpNewDelBoth").def(py::init<>()); + py::class_ aliased(m, "AliasedHasOpNewDelSize"); + aliased.def(py::init<>()); + aliased.attr("size_noalias") = py::int_(sizeof(AliasedHasOpNewDelSize)); + aliased.attr("size_alias") = py::int_(sizeof(PyAliasedHasOpNewDelSize)); + + // This test is actually part of test_local_bindings (test_duplicate_local), but we need a + // definition in a different compilation unit within the same module: + bind_local(m, "LocalExternal", py::module_local()); + + // test_bind_protected_functions + class ProtectedA { + protected: + int foo() const { return value; } + + private: + int value = 42; + }; + + class PublicistA : public ProtectedA { + public: + using ProtectedA::foo; + }; + + py::class_(m, "ProtectedA") + .def(py::init<>()) +#if !defined(_MSC_VER) || _MSC_VER >= 1910 + .def("foo", &PublicistA::foo); +#else + .def("foo", static_cast(&PublicistA::foo)); +#endif + + class ProtectedB { + public: + virtual ~ProtectedB() = default; + + protected: + virtual int foo() const { return value; } + + private: + int value = 42; + }; + + class TrampolineB : public ProtectedB { + public: + int foo() const override { PYBIND11_OVERLOAD(int, ProtectedB, foo, ); } + }; + + class PublicistB : public ProtectedB { + public: + using ProtectedB::foo; + }; + + py::class_(m, "ProtectedB") + .def(py::init<>()) +#if !defined(_MSC_VER) || _MSC_VER >= 1910 + .def("foo", &PublicistB::foo); +#else + .def("foo", static_cast(&PublicistB::foo)); +#endif + + // test_brace_initialization + struct BraceInitialization { + int field1; + std::string field2; + }; + + py::class_(m, "BraceInitialization") + .def(py::init()) + .def_readwrite("field1", &BraceInitialization::field1) + .def_readwrite("field2", &BraceInitialization::field2); + // We *don't* want to construct using braces when the given constructor argument maps to a + // constructor, because brace initialization could go to the wrong place (in particular when + // there is also an `initializer_list`-accept constructor): + py::class_(m, "NoBraceInitialization") + .def(py::init>()) + .def_readonly("vec", &NoBraceInitialization::vec); + + // test_reentrant_implicit_conversion_failure + // #1035: issue with runaway reentrant implicit conversion + struct BogusImplicitConversion { + BogusImplicitConversion(const BogusImplicitConversion &) { } + }; + + py::class_(m, "BogusImplicitConversion") + .def(py::init()); + + py::implicitly_convertible(); + + // test_qualname + // #1166: nested class docstring doesn't show nested name + // Also related: tests that __qualname__ is set properly + struct NestBase {}; + struct Nested {}; + py::class_ base(m, "NestBase"); + base.def(py::init<>()); + py::class_(base, "Nested") + .def(py::init<>()) + .def("fn", [](Nested &, int, NestBase &, Nested &) {}) + .def("fa", [](Nested &, int, NestBase &, Nested &) {}, + "a"_a, "b"_a, "c"_a); + base.def("g", [](NestBase &, Nested &) {}); + base.def("h", []() { return NestBase(); }); + + // test_error_after_conversion + // The second-pass path through dispatcher() previously didn't + // remember which overload was used, and would crash trying to + // generate a useful error message + + struct NotRegistered {}; + struct StringWrapper { std::string str; }; + m.def("test_error_after_conversions", [](int) {}); + m.def("test_error_after_conversions", + [](StringWrapper) -> NotRegistered { return {}; }); + py::class_(m, "StringWrapper").def(py::init()); + py::implicitly_convertible(); + + #if defined(PYBIND11_CPP17) + struct alignas(1024) Aligned { + std::uintptr_t ptr() const { return (uintptr_t) this; } + }; + py::class_(m, "Aligned") + .def(py::init<>()) + .def("ptr", &Aligned::ptr); + #endif +} + +template class BreaksBase { public: virtual ~BreaksBase() = default; }; +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); diff --git a/pybind11/tests/test_class.py b/pybind11/tests/test_class.py new file mode 100644 index 0000000..ed63ca8 --- /dev/null +++ b/pybind11/tests/test_class.py @@ -0,0 +1,281 @@ +import pytest + +from pybind11_tests import class_ as m +from pybind11_tests import UserType, ConstructorStats + + +def test_repr(): + # In Python 3.3+, repr() accesses __qualname__ + assert "pybind11_type" in repr(type(UserType)) + assert "UserType" in repr(UserType) + + +def test_instance(msg): + with pytest.raises(TypeError) as excinfo: + m.NoConstructor() + assert msg(excinfo.value) == "m.class_.NoConstructor: No constructor defined!" + + instance = m.NoConstructor.new_instance() + + cstats = ConstructorStats.get(m.NoConstructor) + assert cstats.alive() == 1 + del instance + assert cstats.alive() == 0 + + +def test_docstrings(doc): + assert doc(UserType) == "A `py::class_` type for testing" + assert UserType.__name__ == "UserType" + assert UserType.__module__ == "pybind11_tests" + assert UserType.get_value.__name__ == "get_value" + assert UserType.get_value.__module__ == "pybind11_tests" + + assert doc(UserType.get_value) == """ + get_value(self: m.UserType) -> int + + Get value using a method + """ + assert doc(UserType.value) == "Get/set value using a property" + + assert doc(m.NoConstructor.new_instance) == """ + new_instance() -> m.class_.NoConstructor + + Return an instance + """ + + +def test_qualname(doc): + """Tests that a properly qualified name is set in __qualname__ (even in pre-3.3, where we + backport the attribute) and that generated docstrings properly use it and the module name""" + assert m.NestBase.__qualname__ == "NestBase" + assert m.NestBase.Nested.__qualname__ == "NestBase.Nested" + + assert doc(m.NestBase.__init__) == """ + __init__(self: m.class_.NestBase) -> None + """ + assert doc(m.NestBase.g) == """ + g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None + """ + assert doc(m.NestBase.Nested.__init__) == """ + __init__(self: m.class_.NestBase.Nested) -> None + """ + assert doc(m.NestBase.Nested.fn) == """ + fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None + """ # noqa: E501 line too long + assert doc(m.NestBase.Nested.fa) == """ + fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None + """ # noqa: E501 line too long + assert m.NestBase.__module__ == "pybind11_tests.class_" + assert m.NestBase.Nested.__module__ == "pybind11_tests.class_" + + +def test_inheritance(msg): + roger = m.Rabbit('Rabbit') + assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot" + assert m.pet_name_species(roger) == "Rabbit is a parrot" + + polly = m.Pet('Polly', 'parrot') + assert polly.name() + " is a " + polly.species() == "Polly is a parrot" + assert m.pet_name_species(polly) == "Polly is a parrot" + + molly = m.Dog('Molly') + assert molly.name() + " is a " + molly.species() == "Molly is a dog" + assert m.pet_name_species(molly) == "Molly is a dog" + + fred = m.Hamster('Fred') + assert fred.name() + " is a " + fred.species() == "Fred is a rodent" + + assert m.dog_bark(molly) == "Woof!" + + with pytest.raises(TypeError) as excinfo: + m.dog_bark(polly) + assert msg(excinfo.value) == """ + dog_bark(): incompatible function arguments. The following argument types are supported: + 1. (arg0: m.class_.Dog) -> str + + Invoked with: + """ + + with pytest.raises(TypeError) as excinfo: + m.Chimera("lion", "goat") + assert "No constructor defined!" in str(excinfo.value) + + +def test_automatic_upcasting(): + assert type(m.return_class_1()).__name__ == "DerivedClass1" + assert type(m.return_class_2()).__name__ == "DerivedClass2" + assert type(m.return_none()).__name__ == "NoneType" + # Repeat these a few times in a random order to ensure no invalid caching is applied + assert type(m.return_class_n(1)).__name__ == "DerivedClass1" + assert type(m.return_class_n(2)).__name__ == "DerivedClass2" + assert type(m.return_class_n(0)).__name__ == "BaseClass" + assert type(m.return_class_n(2)).__name__ == "DerivedClass2" + assert type(m.return_class_n(2)).__name__ == "DerivedClass2" + assert type(m.return_class_n(0)).__name__ == "BaseClass" + assert type(m.return_class_n(1)).__name__ == "DerivedClass1" + + +def test_isinstance(): + objects = [tuple(), dict(), m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4 + expected = (True, True, True, True, True, False, False) + assert m.check_instances(objects) == expected + + +def test_mismatched_holder(): + import re + + with pytest.raises(RuntimeError) as excinfo: + m.mismatched_holder_1() + assert re.match('generic_type: type ".*MismatchDerived1" does not have a non-default ' + 'holder type while its base ".*MismatchBase1" does', str(excinfo.value)) + + with pytest.raises(RuntimeError) as excinfo: + m.mismatched_holder_2() + assert re.match('generic_type: type ".*MismatchDerived2" has a non-default holder type ' + 'while its base ".*MismatchBase2" does not', str(excinfo.value)) + + +def test_override_static(): + """#511: problem with inheritance + overwritten def_static""" + b = m.MyBase.make() + d1 = m.MyDerived.make2() + d2 = m.MyDerived.make() + + assert isinstance(b, m.MyBase) + assert isinstance(d1, m.MyDerived) + assert isinstance(d2, m.MyDerived) + + +def test_implicit_conversion_life_support(): + """Ensure the lifetime of temporary objects created for implicit conversions""" + assert m.implicitly_convert_argument(UserType(5)) == 5 + assert m.implicitly_convert_variable(UserType(5)) == 5 + + assert "outside a bound function" in m.implicitly_convert_variable_fail(UserType(5)) + + +def test_operator_new_delete(capture): + """Tests that class-specific operator new/delete functions are invoked""" + + class SubAliased(m.AliasedHasOpNewDelSize): + pass + + with capture: + a = m.HasOpNewDel() + b = m.HasOpNewDelSize() + d = m.HasOpNewDelBoth() + assert capture == """ + A new 8 + B new 4 + D new 32 + """ + sz_alias = str(m.AliasedHasOpNewDelSize.size_alias) + sz_noalias = str(m.AliasedHasOpNewDelSize.size_noalias) + with capture: + c = m.AliasedHasOpNewDelSize() + c2 = SubAliased() + assert capture == ( + "C new " + sz_noalias + "\n" + + "C new " + sz_alias + "\n" + ) + + with capture: + del a + pytest.gc_collect() + del b + pytest.gc_collect() + del d + pytest.gc_collect() + assert capture == """ + A delete + B delete 4 + D delete + """ + + with capture: + del c + pytest.gc_collect() + del c2 + pytest.gc_collect() + assert capture == ( + "C delete " + sz_noalias + "\n" + + "C delete " + sz_alias + "\n" + ) + + +def test_bind_protected_functions(): + """Expose protected member functions to Python using a helper class""" + a = m.ProtectedA() + assert a.foo() == 42 + + b = m.ProtectedB() + assert b.foo() == 42 + + class C(m.ProtectedB): + def __init__(self): + m.ProtectedB.__init__(self) + + def foo(self): + return 0 + + c = C() + assert c.foo() == 0 + + +def test_brace_initialization(): + """ Tests that simple POD classes can be constructed using C++11 brace initialization """ + a = m.BraceInitialization(123, "test") + assert a.field1 == 123 + assert a.field2 == "test" + + # Tests that a non-simple class doesn't get brace initialization (if the + # class defines an initializer_list constructor, in particular, it would + # win over the expected constructor). + b = m.NoBraceInitialization([123, 456]) + assert b.vec == [123, 456] + + +@pytest.unsupported_on_pypy +def test_class_refcount(): + """Instances must correctly increase/decrease the reference count of their types (#1029)""" + from sys import getrefcount + + class PyDog(m.Dog): + pass + + for cls in m.Dog, PyDog: + refcount_1 = getrefcount(cls) + molly = [cls("Molly") for _ in range(10)] + refcount_2 = getrefcount(cls) + + del molly + pytest.gc_collect() + refcount_3 = getrefcount(cls) + + assert refcount_1 == refcount_3 + assert refcount_2 > refcount_1 + + +def test_reentrant_implicit_conversion_failure(msg): + # ensure that there is no runaway reentrant implicit conversion (#1035) + with pytest.raises(TypeError) as excinfo: + m.BogusImplicitConversion(0) + assert msg(excinfo.value) == ''' + __init__(): incompatible constructor arguments. The following argument types are supported: + 1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion) + + Invoked with: 0 + ''' + + +def test_error_after_conversions(): + with pytest.raises(TypeError) as exc_info: + m.test_error_after_conversions("hello") + assert str(exc_info.value).startswith( + "Unable to convert function return value to a Python type!") + + +def test_aligned(): + if hasattr(m, "Aligned"): + p = m.Aligned().ptr() + assert p % 1024 == 0 diff --git a/pybind11/tests/test_cmake_build/CMakeLists.txt b/pybind11/tests/test_cmake_build/CMakeLists.txt new file mode 100644 index 0000000..c9b5fcb --- /dev/null +++ b/pybind11/tests/test_cmake_build/CMakeLists.txt @@ -0,0 +1,58 @@ +add_custom_target(test_cmake_build) + +if(CMAKE_VERSION VERSION_LESS 3.1) + # 3.0 needed for interface library for subdirectory_target/installed_target + # 3.1 needed for cmake -E env for testing + return() +endif() + +include(CMakeParseArguments) +function(pybind11_add_build_test name) + cmake_parse_arguments(ARG "INSTALL" "" "" ${ARGN}) + + set(build_options "-DCMAKE_PREFIX_PATH=${PROJECT_BINARY_DIR}/mock_install" + "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + "-DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE}" + "-DPYBIND11_CPP_STANDARD=${PYBIND11_CPP_STANDARD}") + if(NOT ARG_INSTALL) + list(APPEND build_options "-DPYBIND11_PROJECT_DIR=${PROJECT_SOURCE_DIR}") + endif() + + add_custom_target(test_${name} ${CMAKE_CTEST_COMMAND} + --quiet --output-log ${name}.log + --build-and-test "${CMAKE_CURRENT_SOURCE_DIR}/${name}" + "${CMAKE_CURRENT_BINARY_DIR}/${name}" + --build-config Release + --build-noclean + --build-generator ${CMAKE_GENERATOR} + $<$:--build-generator-platform> ${CMAKE_GENERATOR_PLATFORM} + --build-makeprogram ${CMAKE_MAKE_PROGRAM} + --build-target check + --build-options ${build_options} + ) + if(ARG_INSTALL) + add_dependencies(test_${name} mock_install) + endif() + add_dependencies(test_cmake_build test_${name}) +endfunction() + +pybind11_add_build_test(subdirectory_function) +pybind11_add_build_test(subdirectory_target) +if(NOT ${PYTHON_MODULE_EXTENSION} MATCHES "pypy") + pybind11_add_build_test(subdirectory_embed) +endif() + +if(PYBIND11_INSTALL) + add_custom_target(mock_install ${CMAKE_COMMAND} + "-DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR}/mock_install" + -P "${PROJECT_BINARY_DIR}/cmake_install.cmake" + ) + + pybind11_add_build_test(installed_function INSTALL) + pybind11_add_build_test(installed_target INSTALL) + if(NOT ${PYTHON_MODULE_EXTENSION} MATCHES "pypy") + pybind11_add_build_test(installed_embed INSTALL) + endif() +endif() + +add_dependencies(check test_cmake_build) diff --git a/pybind11/tests/test_cmake_build/embed.cpp b/pybind11/tests/test_cmake_build/embed.cpp new file mode 100644 index 0000000..b9581d2 --- /dev/null +++ b/pybind11/tests/test_cmake_build/embed.cpp @@ -0,0 +1,21 @@ +#include +namespace py = pybind11; + +PYBIND11_EMBEDDED_MODULE(test_cmake_build, m) { + m.def("add", [](int i, int j) { return i + j; }); +} + +int main(int argc, char *argv[]) { + if (argc != 2) + throw std::runtime_error("Expected test.py file as the first argument"); + auto test_py_file = argv[1]; + + py::scoped_interpreter guard{}; + + auto m = py::module::import("test_cmake_build"); + if (m.attr("add")(1, 2).cast() != 3) + throw std::runtime_error("embed.cpp failed"); + + py::module::import("sys").attr("argv") = py::make_tuple("test.py", "embed.cpp"); + py::eval_file(test_py_file, py::globals()); +} diff --git a/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt b/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt new file mode 100644 index 0000000..f7fc09c --- /dev/null +++ b/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.0) +project(test_installed_embed CXX) + +set(CMAKE_MODULE_PATH "") +find_package(pybind11 CONFIG REQUIRED) +message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}") + +add_executable(test_cmake_build ../embed.cpp) +target_link_libraries(test_cmake_build PRIVATE pybind11::embed) + +# Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::embed). +# This may be needed to resolve header conflicts, e.g. between Python release and debug headers. +set_target_properties(test_cmake_build PROPERTIES NO_SYSTEM_FROM_IMPORTED ON) + +add_custom_target(check $ ${PROJECT_SOURCE_DIR}/../test.py) diff --git a/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt b/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt new file mode 100644 index 0000000..e0c20a8 --- /dev/null +++ b/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 2.8.12) +project(test_installed_module CXX) + +set(CMAKE_MODULE_PATH "") + +find_package(pybind11 CONFIG REQUIRED) +message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}") + +pybind11_add_module(test_cmake_build SHARED NO_EXTRAS ../main.cpp) + +add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$ + ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) diff --git a/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt b/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt new file mode 100644 index 0000000..cd3ae6f --- /dev/null +++ b/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.0) +project(test_installed_target CXX) + +set(CMAKE_MODULE_PATH "") + +find_package(pybind11 CONFIG REQUIRED) +message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}") + +add_library(test_cmake_build MODULE ../main.cpp) + +target_link_libraries(test_cmake_build PRIVATE pybind11::module) + +# make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib +set_target_properties(test_cmake_build PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" + SUFFIX "${PYTHON_MODULE_EXTENSION}") + +# Do not treat includes from IMPORTED target as SYSTEM (Python headers in pybind11::module). +# This may be needed to resolve header conflicts, e.g. between Python release and debug headers. +set_target_properties(test_cmake_build PROPERTIES NO_SYSTEM_FROM_IMPORTED ON) + +add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$ + ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) diff --git a/pybind11/tests/test_cmake_build/main.cpp b/pybind11/tests/test_cmake_build/main.cpp new file mode 100644 index 0000000..e30f2c4 --- /dev/null +++ b/pybind11/tests/test_cmake_build/main.cpp @@ -0,0 +1,6 @@ +#include +namespace py = pybind11; + +PYBIND11_MODULE(test_cmake_build, m) { + m.def("add", [](int i, int j) { return i + j; }); +} diff --git a/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt b/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt new file mode 100644 index 0000000..88ba60d --- /dev/null +++ b/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.0) +project(test_subdirectory_embed CXX) + +set(PYBIND11_INSTALL ON CACHE BOOL "") +set(PYBIND11_EXPORT_NAME test_export) + +add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11) + +# Test basic target functionality +add_executable(test_cmake_build ../embed.cpp) +target_link_libraries(test_cmake_build PRIVATE pybind11::embed) + +add_custom_target(check $ ${PROJECT_SOURCE_DIR}/../test.py) + +# Test custom export group -- PYBIND11_EXPORT_NAME +add_library(test_embed_lib ../embed.cpp) +target_link_libraries(test_embed_lib PRIVATE pybind11::embed) + +install(TARGETS test_embed_lib + EXPORT test_export + ARCHIVE DESTINATION bin + LIBRARY DESTINATION lib + RUNTIME DESTINATION lib) +install(EXPORT test_export + DESTINATION lib/cmake/test_export/test_export-Targets.cmake) diff --git a/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt b/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt new file mode 100644 index 0000000..278007a --- /dev/null +++ b/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 2.8.12) +project(test_subdirectory_module CXX) + +add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11) +pybind11_add_module(test_cmake_build THIN_LTO ../main.cpp) + +add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$ + ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) diff --git a/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt b/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt new file mode 100644 index 0000000..6b142d6 --- /dev/null +++ b/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.0) +project(test_subdirectory_target CXX) + +add_subdirectory(${PYBIND11_PROJECT_DIR} pybind11) + +add_library(test_cmake_build MODULE ../main.cpp) + +target_link_libraries(test_cmake_build PRIVATE pybind11::module) + +# make sure result is, for example, test_installed_target.so, not libtest_installed_target.dylib +set_target_properties(test_cmake_build PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" + SUFFIX "${PYTHON_MODULE_EXTENSION}") + +add_custom_target(check ${CMAKE_COMMAND} -E env PYTHONPATH=$ + ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/../test.py ${PROJECT_NAME}) diff --git a/pybind11/tests/test_cmake_build/test.py b/pybind11/tests/test_cmake_build/test.py new file mode 100644 index 0000000..1467a61 --- /dev/null +++ b/pybind11/tests/test_cmake_build/test.py @@ -0,0 +1,5 @@ +import sys +import test_cmake_build + +assert test_cmake_build.add(1, 2) == 3 +print("{} imports, runs, and adds: 1 + 2 = 3".format(sys.argv[1])) diff --git a/pybind11/tests/test_constants_and_functions.cpp b/pybind11/tests/test_constants_and_functions.cpp new file mode 100644 index 0000000..e8ec74b --- /dev/null +++ b/pybind11/tests/test_constants_and_functions.cpp @@ -0,0 +1,127 @@ +/* + 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::str test_function4() { return "test_function()"; } +py::str test_function4(char *) { return "test_function(char *)"; } +py::str test_function4(int, float) { return "test_function(int, float)"; } +py::str test_function4(float, int) { return "test_function(float, int)"; } + +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 that we properly handle C++17 exception specifiers (which are part of the function signature +// in C++17). These should all still work before C++17, but don't affect the function signature. +namespace test_exc_sp { +int f1(int x) noexcept { return x+1; } +int f2(int x) noexcept(true) { return x+2; } +int f3(int x) noexcept(false) { return x+3; } +#if defined(__GNUG__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated" +#endif +int f4(int x) throw() { return x+4; } // Deprecated equivalent to noexcept(true) +#if defined(__GNUG__) +# pragma GCC diagnostic pop +#endif +struct C { + int m1(int x) noexcept { return x-1; } + int m2(int x) const noexcept { return x-2; } + int m3(int x) noexcept(true) { return x-3; } + int m4(int x) const noexcept(true) { return x-4; } + int m5(int x) noexcept(false) { return x-5; } + int m6(int x) const noexcept(false) { return x-6; } +#if defined(__GNUG__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated" +#endif + int m7(int x) throw() { return x-7; } + int m8(int x) const throw() { return x-8; } +#if defined(__GNUG__) +# pragma GCC diagnostic pop +#endif +}; +} + + +TEST_SUBMODULE(constants_and_functions, m) { + // test_constants + m.attr("some_constant") = py::int_(14); + + // test_function_overloading + m.def("test_function", &test_function1); + m.def("test_function", &test_function2); + m.def("test_function", &test_function3); + +#if defined(PYBIND11_OVERLOAD_CAST) + m.def("test_function", py::overload_cast<>(&test_function4)); + m.def("test_function", py::overload_cast(&test_function4)); + m.def("test_function", py::overload_cast(&test_function4)); + m.def("test_function", py::overload_cast(&test_function4)); +#else + m.def("test_function", static_cast(&test_function4)); + m.def("test_function", static_cast(&test_function4)); + m.def("test_function", static_cast(&test_function4)); + m.def("test_function", static_cast(&test_function4)); +#endif + + py::enum_(m, "MyEnum") + .value("EFirstEntry", EFirstEntry) + .value("ESecondEntry", ESecondEntry) + .export_values(); + + // test_bytes + m.def("return_bytes", &return_bytes); + m.def("print_bytes", &print_bytes); + + // test_exception_specifiers + using namespace test_exc_sp; + py::class_(m, "C") + .def(py::init<>()) + .def("m1", &C::m1) + .def("m2", &C::m2) + .def("m3", &C::m3) + .def("m4", &C::m4) + .def("m5", &C::m5) + .def("m6", &C::m6) + .def("m7", &C::m7) + .def("m8", &C::m8) + ; + m.def("f1", f1); + m.def("f2", f2); + m.def("f3", f3); + m.def("f4", f4); +} diff --git a/pybind11/tests/test_constants_and_functions.py b/pybind11/tests/test_constants_and_functions.py new file mode 100644 index 0000000..472682d --- /dev/null +++ b/pybind11/tests/test_constants_and_functions.py @@ -0,0 +1,39 @@ +from pybind11_tests import constants_and_functions as m + + +def test_constants(): + assert m.some_constant == 14 + + +def test_function_overloading(): + assert m.test_function() == "test_function()" + assert m.test_function(7) == "test_function(7)" + assert m.test_function(m.MyEnum.EFirstEntry) == "test_function(enum=1)" + assert m.test_function(m.MyEnum.ESecondEntry) == "test_function(enum=2)" + + assert m.test_function() == "test_function()" + assert m.test_function("abcd") == "test_function(char *)" + assert m.test_function(1, 1.0) == "test_function(int, float)" + assert m.test_function(1, 1.0) == "test_function(int, float)" + assert m.test_function(2.0, 2) == "test_function(float, int)" + + +def test_bytes(): + assert m.print_bytes(m.return_bytes()) == "bytes[1 0 2 0]" + + +def test_exception_specifiers(): + c = m.C() + assert c.m1(2) == 1 + assert c.m2(3) == 1 + assert c.m3(5) == 2 + assert c.m4(7) == 3 + assert c.m5(10) == 5 + assert c.m6(14) == 8 + assert c.m7(20) == 13 + assert c.m8(29) == 21 + + assert m.f1(33) == 34 + assert m.f2(53) == 55 + assert m.f3(86) == 89 + assert m.f4(140) == 144 diff --git a/pybind11/tests/test_copy_move.cpp b/pybind11/tests/test_copy_move.cpp new file mode 100644 index 0000000..98d5e0a --- /dev/null +++ b/pybind11/tests/test_copy_move.cpp @@ -0,0 +1,213 @@ +/* + tests/test_copy_move_policies.cpp -- 'copy' and 'move' return value policies + and related tests + + 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" +#include "constructor_stats.h" +#include + +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_ = {}; + +/* Custom type caster move/copy test classes */ +class MoveOnlyInt { +public: + MoveOnlyInt() { print_default_created(this); } + MoveOnlyInt(int v) : value{std::move(v)} { print_created(this, value); } + MoveOnlyInt(MoveOnlyInt &&m) { print_move_created(this, m.value); std::swap(value, m.value); } + MoveOnlyInt &operator=(MoveOnlyInt &&m) { print_move_assigned(this, m.value); std::swap(value, m.value); return *this; } + MoveOnlyInt(const MoveOnlyInt &) = delete; + MoveOnlyInt &operator=(const MoveOnlyInt &) = delete; + ~MoveOnlyInt() { print_destroyed(this); } + + int value; +}; +class MoveOrCopyInt { +public: + MoveOrCopyInt() { print_default_created(this); } + MoveOrCopyInt(int v) : value{std::move(v)} { print_created(this, value); } + MoveOrCopyInt(MoveOrCopyInt &&m) { print_move_created(this, m.value); std::swap(value, m.value); } + MoveOrCopyInt &operator=(MoveOrCopyInt &&m) { print_move_assigned(this, m.value); std::swap(value, m.value); return *this; } + MoveOrCopyInt(const MoveOrCopyInt &c) { print_copy_created(this, c.value); value = c.value; } + MoveOrCopyInt &operator=(const MoveOrCopyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; } + ~MoveOrCopyInt() { print_destroyed(this); } + + int value; +}; +class CopyOnlyInt { +public: + CopyOnlyInt() { print_default_created(this); } + CopyOnlyInt(int v) : value{std::move(v)} { print_created(this, value); } + CopyOnlyInt(const CopyOnlyInt &c) { print_copy_created(this, c.value); value = c.value; } + CopyOnlyInt &operator=(const CopyOnlyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; } + ~CopyOnlyInt() { print_destroyed(this); } + + int value; +}; +NAMESPACE_BEGIN(pybind11) +NAMESPACE_BEGIN(detail) +template <> struct type_caster { + PYBIND11_TYPE_CASTER(MoveOnlyInt, _("MoveOnlyInt")); + bool load(handle src, bool) { value = MoveOnlyInt(src.cast()); return true; } + static handle cast(const MoveOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); } +}; + +template <> struct type_caster { + PYBIND11_TYPE_CASTER(MoveOrCopyInt, _("MoveOrCopyInt")); + bool load(handle src, bool) { value = MoveOrCopyInt(src.cast()); return true; } + static handle cast(const MoveOrCopyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); } +}; + +template <> struct type_caster { +protected: + CopyOnlyInt value; +public: + static constexpr auto name = _("CopyOnlyInt"); + bool load(handle src, bool) { value = CopyOnlyInt(src.cast()); return true; } + static handle cast(const CopyOnlyInt &m, return_value_policy r, handle p) { return pybind11::cast(m.value, r, p); } + static handle cast(const CopyOnlyInt *src, return_value_policy policy, handle parent) { + if (!src) return none().release(); + return cast(*src, policy, parent); + } + operator CopyOnlyInt*() { return &value; } + operator CopyOnlyInt&() { return value; } + template using cast_op_type = pybind11::detail::cast_op_type; +}; +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) + +TEST_SUBMODULE(copy_move_policies, m) { + // test_lacking_copy_ctor + py::class_(m, "lacking_copy_ctor") + .def_static("get_one", &lacking_copy_ctor::get_one, + py::return_value_policy::copy); + // test_lacking_move_ctor + py::class_(m, "lacking_move_ctor") + .def_static("get_one", &lacking_move_ctor::get_one, + py::return_value_policy::move); + + // test_move_and_copy_casts + m.def("move_and_copy_casts", [](py::object o) { + int r = 0; + r += py::cast(o).value; /* moves */ + r += py::cast(o).value; /* moves */ + r += py::cast(o).value; /* copies */ + MoveOrCopyInt m1(py::cast(o)); /* moves */ + MoveOnlyInt m2(py::cast(o)); /* moves */ + CopyOnlyInt m3(py::cast(o)); /* copies */ + r += m1.value + m2.value + m3.value; + + return r; + }); + + // test_move_and_copy_loads + m.def("move_only", [](MoveOnlyInt m) { return m.value; }); + m.def("move_or_copy", [](MoveOrCopyInt m) { return m.value; }); + m.def("copy_only", [](CopyOnlyInt m) { return m.value; }); + m.def("move_pair", [](std::pair p) { + return p.first.value + p.second.value; + }); + m.def("move_tuple", [](std::tuple t) { + return std::get<0>(t).value + std::get<1>(t).value + std::get<2>(t).value; + }); + m.def("copy_tuple", [](std::tuple t) { + return std::get<0>(t).value + std::get<1>(t).value; + }); + m.def("move_copy_nested", [](std::pair>, MoveOrCopyInt>> x) { + return x.first.value + std::get<0>(x.second.first).value + std::get<1>(x.second.first).value + + std::get<0>(std::get<2>(x.second.first)).value + x.second.second.value; + }); + m.def("move_and_copy_cstats", []() { + ConstructorStats::gc(); + // Reset counts to 0 so that previous tests don't affect later ones: + auto &mc = ConstructorStats::get(); + mc.move_assignments = mc.move_constructions = mc.copy_assignments = mc.copy_constructions = 0; + auto &mo = ConstructorStats::get(); + mo.move_assignments = mo.move_constructions = mo.copy_assignments = mo.copy_constructions = 0; + auto &co = ConstructorStats::get(); + co.move_assignments = co.move_constructions = co.copy_assignments = co.copy_constructions = 0; + py::dict d; + d["MoveOrCopyInt"] = py::cast(mc, py::return_value_policy::reference); + d["MoveOnlyInt"] = py::cast(mo, py::return_value_policy::reference); + d["CopyOnlyInt"] = py::cast(co, py::return_value_policy::reference); + return d; + }); +#ifdef PYBIND11_HAS_OPTIONAL + // test_move_and_copy_load_optional + m.attr("has_optional") = true; + m.def("move_optional", [](std::optional o) { + return o->value; + }); + m.def("move_or_copy_optional", [](std::optional o) { + return o->value; + }); + m.def("copy_optional", [](std::optional o) { + return o->value; + }); + m.def("move_optional_tuple", [](std::optional> x) { + return std::get<0>(*x).value + std::get<1>(*x).value + std::get<2>(*x).value; + }); +#else + m.attr("has_optional") = false; +#endif + + // #70 compilation issue if operator new is not public + struct PrivateOpNew { + int value = 1; + private: +#if defined(_MSC_VER) +# pragma warning(disable: 4822) // warning C4822: local class member function does not have a body +#endif + void *operator new(size_t bytes); + }; + py::class_(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value); + m.def("private_op_new_value", []() { return PrivateOpNew(); }); + m.def("private_op_new_reference", []() -> const PrivateOpNew & { + static PrivateOpNew x{}; + return x; + }, py::return_value_policy::reference); + + // test_move_fallback + // #389: rvp::move should fall-through to copy on non-movable objects + struct MoveIssue1 { + int v; + MoveIssue1(int v) : v{v} {} + MoveIssue1(const MoveIssue1 &c) = default; + MoveIssue1(MoveIssue1 &&) = delete; + }; + py::class_(m, "MoveIssue1").def(py::init()).def_readwrite("value", &MoveIssue1::v); + + struct MoveIssue2 { + int v; + MoveIssue2(int v) : v{v} {} + MoveIssue2(MoveIssue2 &&) = default; + }; + py::class_(m, "MoveIssue2").def(py::init()).def_readwrite("value", &MoveIssue2::v); + + m.def("get_moveissue1", [](int i) { return new MoveIssue1(i); }, py::return_value_policy::move); + m.def("get_moveissue2", [](int i) { return MoveIssue2(i); }, py::return_value_policy::move); +} diff --git a/pybind11/tests/test_copy_move.py b/pybind11/tests/test_copy_move.py new file mode 100644 index 0000000..aff2d99 --- /dev/null +++ b/pybind11/tests/test_copy_move.py @@ -0,0 +1,112 @@ +import pytest +from pybind11_tests import copy_move_policies as m + + +def test_lacking_copy_ctor(): + with pytest.raises(RuntimeError) as excinfo: + m.lacking_copy_ctor.get_one() + assert "the object is non-copyable!" in str(excinfo.value) + + +def test_lacking_move_ctor(): + with pytest.raises(RuntimeError) as excinfo: + m.lacking_move_ctor.get_one() + assert "the object is neither movable nor copyable!" in str(excinfo.value) + + +def test_move_and_copy_casts(): + """Cast some values in C++ via custom type casters and count the number of moves/copies.""" + + cstats = m.move_and_copy_cstats() + c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"] + + # The type move constructions/assignments below each get incremented: the move assignment comes + # from the type_caster load; the move construction happens when extracting that via a cast or + # loading into an argument. + assert m.move_and_copy_casts(3) == 18 + assert c_m.copy_assignments + c_m.copy_constructions == 0 + assert c_m.move_assignments == 2 + assert c_m.move_constructions >= 2 + assert c_mc.alive() == 0 + assert c_mc.copy_assignments + c_mc.copy_constructions == 0 + assert c_mc.move_assignments == 2 + assert c_mc.move_constructions >= 2 + assert c_c.alive() == 0 + assert c_c.copy_assignments == 2 + assert c_c.copy_constructions >= 2 + assert c_m.alive() + c_mc.alive() + c_c.alive() == 0 + + +def test_move_and_copy_loads(): + """Call some functions that load arguments via custom type casters and count the number of + moves/copies.""" + + cstats = m.move_and_copy_cstats() + c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"] + + assert m.move_only(10) == 10 # 1 move, c_m + assert m.move_or_copy(11) == 11 # 1 move, c_mc + assert m.copy_only(12) == 12 # 1 copy, c_c + assert m.move_pair((13, 14)) == 27 # 1 c_m move, 1 c_mc move + assert m.move_tuple((15, 16, 17)) == 48 # 2 c_m moves, 1 c_mc move + assert m.copy_tuple((18, 19)) == 37 # 2 c_c copies + # Direct constructions: 2 c_m moves, 2 c_mc moves, 1 c_c copy + # Extra moves/copies when moving pairs/tuples: 3 c_m, 3 c_mc, 2 c_c + assert m.move_copy_nested((1, ((2, 3, (4,)), 5))) == 15 + + assert c_m.copy_assignments + c_m.copy_constructions == 0 + assert c_m.move_assignments == 6 + assert c_m.move_constructions == 9 + assert c_mc.copy_assignments + c_mc.copy_constructions == 0 + assert c_mc.move_assignments == 5 + assert c_mc.move_constructions == 8 + assert c_c.copy_assignments == 4 + assert c_c.copy_constructions == 6 + assert c_m.alive() + c_mc.alive() + c_c.alive() == 0 + + +@pytest.mark.skipif(not m.has_optional, reason='no ') +def test_move_and_copy_load_optional(): + """Tests move/copy loads of std::optional arguments""" + + cstats = m.move_and_copy_cstats() + c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"] + + # The extra move/copy constructions below come from the std::optional move (which has to move + # its arguments): + assert m.move_optional(10) == 10 # c_m: 1 move assign, 2 move construct + assert m.move_or_copy_optional(11) == 11 # c_mc: 1 move assign, 2 move construct + assert m.copy_optional(12) == 12 # c_c: 1 copy assign, 2 copy construct + # 1 move assign + move construct moves each of c_m, c_mc, 1 c_c copy + # +1 move/copy construct each from moving the tuple + # +1 move/copy construct each from moving the optional (which moves the tuple again) + assert m.move_optional_tuple((3, 4, 5)) == 12 + + assert c_m.copy_assignments + c_m.copy_constructions == 0 + assert c_m.move_assignments == 2 + assert c_m.move_constructions == 5 + assert c_mc.copy_assignments + c_mc.copy_constructions == 0 + assert c_mc.move_assignments == 2 + assert c_mc.move_constructions == 5 + assert c_c.copy_assignments == 2 + assert c_c.copy_constructions == 5 + assert c_m.alive() + c_mc.alive() + c_c.alive() == 0 + + +def test_private_op_new(): + """An object with a private `operator new` cannot be returned by value""" + + with pytest.raises(RuntimeError) as excinfo: + m.private_op_new_value() + assert "the object is neither movable nor copyable" in str(excinfo.value) + + assert m.private_op_new_reference().value == 1 + + +def test_move_fallback(): + """#389: rvp::move should fall-through to copy on non-movable objects""" + + m2 = m.get_moveissue2(2) + assert m2.value == 2 + m1 = m.get_moveissue1(1) + assert m1.value == 1 diff --git a/pybind11/tests/test_docstring_options.cpp b/pybind11/tests/test_docstring_options.cpp new file mode 100644 index 0000000..8c8f79f --- /dev/null +++ b/pybind11/tests/test_docstring_options.cpp @@ -0,0 +1,61 @@ +/* + 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" + +TEST_SUBMODULE(docstring_options, m) { + // test_docstring_options + { + 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"); + + m.def("test_overloaded1", [](int) {}, py::arg("i"), "Overload docstring"); + m.def("test_overloaded1", [](double) {}, py::arg("d")); + + m.def("test_overloaded2", [](int) {}, py::arg("i"), "overload docstring 1"); + m.def("test_overloaded2", [](double) {}, py::arg("d"), "overload docstring 2"); + + m.def("test_overloaded3", [](int) {}, py::arg("i")); + m.def("test_overloaded3", [](double) {}, py::arg("d"), "Overload docstr"); + + 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(); + + struct DocstringTestFoo { + int value; + void setValue(int v) { value = v; } + int getValue() const { return value; } + }; + 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/pybind11/tests/test_docstring_options.py b/pybind11/tests/test_docstring_options.py new file mode 100644 index 0000000..0dbca60 --- /dev/null +++ b/pybind11/tests/test_docstring_options.py @@ -0,0 +1,38 @@ +from pybind11_tests import docstring_options as m + + +def test_docstring_options(): + # options.disable_function_signatures() + assert not m.test_function1.__doc__ + + assert m.test_function2.__doc__ == "A custom docstring" + + # docstring specified on just the first overload definition: + assert m.test_overloaded1.__doc__ == "Overload docstring" + + # docstring on both overloads: + assert m.test_overloaded2.__doc__ == "overload docstring 1\noverload docstring 2" + + # docstring on only second overload: + assert m.test_overloaded3.__doc__ == "Overload docstr" + + # options.enable_function_signatures() + assert m.test_function3.__doc__ .startswith("test_function3(a: int, b: int) -> None") + + assert m.test_function4.__doc__ .startswith("test_function4(a: int, b: int) -> None") + assert m.test_function4.__doc__ .endswith("A custom docstring\n") + + # options.disable_function_signatures() + # options.disable_user_defined_docstrings() + assert not m.test_function5.__doc__ + + # nested options.enable_user_defined_docstrings() + assert m.test_function6.__doc__ == "A custom docstring" + + # RAII destructor + assert m.test_function7.__doc__ .startswith("test_function7(a: int, b: int) -> None") + assert m.test_function7.__doc__ .endswith("A custom docstring\n") + + # Suppression of user-defined docstrings for non-function objects + assert not m.DocstringTestFoo.__doc__ + assert not m.DocstringTestFoo.value_prop.__doc__ diff --git a/pybind11/tests/test_eigen.cpp b/pybind11/tests/test_eigen.cpp new file mode 100644 index 0000000..aba088d --- /dev/null +++ b/pybind11/tests/test_eigen.cpp @@ -0,0 +1,329 @@ +/* + 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 "constructor_stats.h" +#include +#include + +#if defined(_MSC_VER) +# pragma warning(disable: 4996) // C4996: std::unary_negation is deprecated +#endif + +#include + +using MatrixXdR = Eigen::Matrix; + + + +// Sets/resets a testing reference matrix to have values of 10*r + c, where r and c are the +// (1-based) row/column number. +template void reset_ref(M &x) { + for (int i = 0; i < x.rows(); i++) for (int j = 0; j < x.cols(); j++) + x(i, j) = 11 + 10*i + j; +} + +// Returns a static, column-major matrix +Eigen::MatrixXd &get_cm() { + static Eigen::MatrixXd *x; + if (!x) { + x = new Eigen::MatrixXd(3, 3); + reset_ref(*x); + } + return *x; +} +// Likewise, but row-major +MatrixXdR &get_rm() { + static MatrixXdR *x; + if (!x) { + x = new MatrixXdR(3, 3); + reset_ref(*x); + } + return *x; +} +// Resets the values of the static matrices returned by get_cm()/get_rm() +void reset_refs() { + reset_ref(get_cm()); + reset_ref(get_rm()); +} + +// Returns element 2,1 from a matrix (used to test copy/nocopy) +double get_elem(Eigen::Ref m) { return m(2, 1); }; + + +// Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix +// reference is referencing rows/columns correctly). +template Eigen::MatrixXd adjust_matrix(MatrixArgType m) { + Eigen::MatrixXd ret(m); + for (int c = 0; c < m.cols(); c++) for (int r = 0; r < m.rows(); r++) + ret(r, c) += 10*r + 100*c; + return ret; +} + +struct CustomOperatorNew { + CustomOperatorNew() = default; + + Eigen::Matrix4d a = Eigen::Matrix4d::Zero(); + Eigen::Matrix4d b = Eigen::Matrix4d::Identity(); + + EIGEN_MAKE_ALIGNED_OPERATOR_NEW; +}; + +TEST_SUBMODULE(eigen, m) { + using FixedMatrixR = Eigen::Matrix; + using FixedMatrixC = Eigen::Matrix; + using DenseMatrixR = Eigen::Matrix; + using DenseMatrixC = Eigen::Matrix; + using FourRowMatrixC = Eigen::Matrix; + using FourColMatrixC = Eigen::Matrix; + using FourRowMatrixR = Eigen::Matrix; + using FourColMatrixR = Eigen::Matrix; + using SparseMatrixR = Eigen::SparseMatrix; + using SparseMatrixC = Eigen::SparseMatrix; + + m.attr("have_eigen") = true; + + // various tests + m.def("double_col", [](const Eigen::VectorXf &x) -> Eigen::VectorXf { return 2.0f * x; }); + m.def("double_row", [](const Eigen::RowVectorXf &x) -> Eigen::RowVectorXf { return 2.0f * x; }); + m.def("double_complex", [](const Eigen::VectorXcf &x) -> Eigen::VectorXcf { return 2.0f * x; }); + m.def("double_threec", [](py::EigenDRef x) { x *= 2; }); + m.def("double_threer", [](py::EigenDRef x) { x *= 2; }); + m.def("double_mat_cm", [](Eigen::MatrixXf x) -> Eigen::MatrixXf { return 2.0f * x; }); + m.def("double_mat_rm", [](DenseMatrixR x) -> DenseMatrixR { return 2.0f * x; }); + + // test_eigen_ref_to_python + // Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended + m.def("cholesky1", [](Eigen::Ref x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); + m.def("cholesky2", [](const Eigen::Ref &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); + m.def("cholesky3", [](const Eigen::Ref &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); + m.def("cholesky4", [](Eigen::Ref x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); + + // test_eigen_ref_mutators + // Mutators: these add some value to the given element using Eigen, but Eigen should be mapping into + // the numpy array data and so the result should show up there. There are three versions: one that + // works on a contiguous-row matrix (numpy's default), one for a contiguous-column matrix, and one + // for any matrix. + auto add_rm = [](Eigen::Ref x, int r, int c, double v) { x(r,c) += v; }; + auto add_cm = [](Eigen::Ref x, int r, int c, double v) { x(r,c) += v; }; + + // Mutators (Eigen maps into numpy variables): + m.def("add_rm", add_rm); // Only takes row-contiguous + m.def("add_cm", add_cm); // Only takes column-contiguous + // Overloaded versions that will accept either row or column contiguous: + m.def("add1", add_rm); + m.def("add1", add_cm); + m.def("add2", add_cm); + m.def("add2", add_rm); + // This one accepts a matrix of any stride: + m.def("add_any", [](py::EigenDRef x, int r, int c, double v) { x(r,c) += v; }); + + // Return mutable references (numpy maps into eigen variables) + m.def("get_cm_ref", []() { return Eigen::Ref(get_cm()); }); + m.def("get_rm_ref", []() { return Eigen::Ref(get_rm()); }); + // The same references, but non-mutable (numpy maps into eigen variables, but is !writeable) + m.def("get_cm_const_ref", []() { return Eigen::Ref(get_cm()); }); + m.def("get_rm_const_ref", []() { return Eigen::Ref(get_rm()); }); + + m.def("reset_refs", reset_refs); // Restores get_{cm,rm}_ref to original values + + // Increments and returns ref to (same) matrix + m.def("incr_matrix", [](Eigen::Ref m, double v) { + m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v); + return m; + }, py::return_value_policy::reference); + + // Same, but accepts a matrix of any strides + m.def("incr_matrix_any", [](py::EigenDRef m, double v) { + m += Eigen::MatrixXd::Constant(m.rows(), m.cols(), v); + return m; + }, py::return_value_policy::reference); + + // Returns an eigen slice of even rows + m.def("even_rows", [](py::EigenDRef m) { + return py::EigenDMap( + m.data(), (m.rows() + 1) / 2, m.cols(), + py::EigenDStride(m.outerStride(), 2 * m.innerStride())); + }, py::return_value_policy::reference); + + // Returns an eigen slice of even columns + m.def("even_cols", [](py::EigenDRef m) { + return py::EigenDMap( + m.data(), m.rows(), (m.cols() + 1) / 2, + py::EigenDStride(2 * m.outerStride(), m.innerStride())); + }, py::return_value_policy::reference); + + // 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); + }); + + // test_eigen_return_references, test_eigen_keepalive + // return value referencing/copying tests: + class ReturnTester { + Eigen::MatrixXd mat = create(); + public: + ReturnTester() { print_created(this); } + ~ReturnTester() { print_destroyed(this); } + static Eigen::MatrixXd create() { return Eigen::MatrixXd::Ones(10, 10); } + static const Eigen::MatrixXd createConst() { return Eigen::MatrixXd::Ones(10, 10); } + Eigen::MatrixXd &get() { return mat; } + Eigen::MatrixXd *getPtr() { return &mat; } + const Eigen::MatrixXd &view() { return mat; } + const Eigen::MatrixXd *viewPtr() { return &mat; } + Eigen::Ref ref() { return mat; } + Eigen::Ref refConst() { return mat; } + Eigen::Block block(int r, int c, int nrow, int ncol) { return mat.block(r, c, nrow, ncol); } + Eigen::Block blockConst(int r, int c, int nrow, int ncol) const { return mat.block(r, c, nrow, ncol); } + py::EigenDMap corners() { return py::EigenDMap(mat.data(), + py::EigenDStride(mat.outerStride() * (mat.outerSize()-1), mat.innerStride() * (mat.innerSize()-1))); } + py::EigenDMap cornersConst() const { return py::EigenDMap(mat.data(), + py::EigenDStride(mat.outerStride() * (mat.outerSize()-1), mat.innerStride() * (mat.innerSize()-1))); } + }; + using rvp = py::return_value_policy; + py::class_(m, "ReturnTester") + .def(py::init<>()) + .def_static("create", &ReturnTester::create) + .def_static("create_const", &ReturnTester::createConst) + .def("get", &ReturnTester::get, rvp::reference_internal) + .def("get_ptr", &ReturnTester::getPtr, rvp::reference_internal) + .def("view", &ReturnTester::view, rvp::reference_internal) + .def("view_ptr", &ReturnTester::view, rvp::reference_internal) + .def("copy_get", &ReturnTester::get) // Default rvp: copy + .def("copy_view", &ReturnTester::view) // " + .def("ref", &ReturnTester::ref) // Default for Ref is to reference + .def("ref_const", &ReturnTester::refConst) // Likewise, but const + .def("ref_safe", &ReturnTester::ref, rvp::reference_internal) + .def("ref_const_safe", &ReturnTester::refConst, rvp::reference_internal) + .def("copy_ref", &ReturnTester::ref, rvp::copy) + .def("copy_ref_const", &ReturnTester::refConst, rvp::copy) + .def("block", &ReturnTester::block) + .def("block_safe", &ReturnTester::block, rvp::reference_internal) + .def("block_const", &ReturnTester::blockConst, rvp::reference_internal) + .def("copy_block", &ReturnTester::block, rvp::copy) + .def("corners", &ReturnTester::corners, rvp::reference_internal) + .def("corners_const", &ReturnTester::cornersConst, rvp::reference_internal) + ; + + // test_special_matrix_objects + // 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(); + }); + + // Test matrix for various functions below. + 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; + + // test_fixed, and various other tests + m.def("fixed_r", [mat]() -> FixedMatrixR { return FixedMatrixR(mat); }); + m.def("fixed_r_const", [mat]() -> const FixedMatrixR { return FixedMatrixR(mat); }); + m.def("fixed_c", [mat]() -> FixedMatrixC { return FixedMatrixC(mat); }); + m.def("fixed_copy_r", [](const FixedMatrixR &m) -> FixedMatrixR { return m; }); + m.def("fixed_copy_c", [](const FixedMatrixC &m) -> FixedMatrixC { return m; }); + // test_mutator_descriptors + m.def("fixed_mutator_r", [](Eigen::Ref) {}); + m.def("fixed_mutator_c", [](Eigen::Ref) {}); + m.def("fixed_mutator_a", [](py::EigenDRef) {}); + // test_dense + m.def("dense_r", [mat]() -> DenseMatrixR { return DenseMatrixR(mat); }); + m.def("dense_c", [mat]() -> DenseMatrixC { return DenseMatrixC(mat); }); + m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; }); + m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; }); + // test_sparse, test_sparse_signature + m.def("sparse_r", [mat]() -> SparseMatrixR { return Eigen::SparseView(mat); }); + m.def("sparse_c", [mat]() -> SparseMatrixC { return Eigen::SparseView(mat); }); + m.def("sparse_copy_r", [](const SparseMatrixR &m) -> SparseMatrixR { return m; }); + m.def("sparse_copy_c", [](const SparseMatrixC &m) -> SparseMatrixC { return m; }); + // test_partially_fixed + m.def("partial_copy_four_rm_r", [](const FourRowMatrixR &m) -> FourRowMatrixR { return m; }); + m.def("partial_copy_four_rm_c", [](const FourColMatrixR &m) -> FourColMatrixR { return m; }); + m.def("partial_copy_four_cm_r", [](const FourRowMatrixC &m) -> FourRowMatrixC { return m; }); + m.def("partial_copy_four_cm_c", [](const FourColMatrixC &m) -> FourColMatrixC { return m; }); + + // test_cpp_casting + // Test that we can cast a numpy object to a Eigen::MatrixXd explicitly + m.def("cpp_copy", [](py::handle m) { return m.cast()(1, 0); }); + m.def("cpp_ref_c", [](py::handle m) { return m.cast>()(1, 0); }); + m.def("cpp_ref_r", [](py::handle m) { return m.cast>()(1, 0); }); + m.def("cpp_ref_any", [](py::handle m) { return m.cast>()(1, 0); }); + + + // test_nocopy_wrapper + // Test that we can prevent copying into an argument that would normally copy: First a version + // that would allow copying (if types or strides don't match) for comparison: + m.def("get_elem", &get_elem); + // Now this alternative that calls the tells pybind to fail rather than copy: + m.def("get_elem_nocopy", [](Eigen::Ref m) -> double { return get_elem(m); }, + py::arg().noconvert()); + // Also test a row-major-only no-copy const ref: + m.def("get_elem_rm_nocopy", [](Eigen::Ref> &m) -> long { return m(2, 1); }, + py::arg().noconvert()); + + // test_issue738 + // Issue #738: 1xN or Nx1 2D matrices were neither accepted nor properly copied with an + // incompatible stride value on the length-1 dimension--but that should be allowed (without + // requiring a copy!) because the stride value can be safely ignored on a size-1 dimension. + m.def("iss738_f1", &adjust_matrix &>, py::arg().noconvert()); + m.def("iss738_f2", &adjust_matrix> &>, py::arg().noconvert()); + + // test_issue1105 + // Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense + // eigen Vector or RowVector, the argument would fail to load because the numpy copy would fail: + // numpy won't broadcast a Nx1 into a 1-dimensional vector. + m.def("iss1105_col", [](Eigen::VectorXd) { return true; }); + m.def("iss1105_row", [](Eigen::RowVectorXd) { return true; }); + + // test_named_arguments + // Make sure named arguments are working properly: + m.def("matrix_multiply", [](const py::EigenDRef A, const py::EigenDRef B) + -> Eigen::MatrixXd { + if (A.cols() != B.rows()) throw std::domain_error("Nonconformable matrices!"); + return A * B; + }, py::arg("A"), py::arg("B")); + + // test_custom_operator_new + py::class_(m, "CustomOperatorNew") + .def(py::init<>()) + .def_readonly("a", &CustomOperatorNew::a) + .def_readonly("b", &CustomOperatorNew::b); + + // test_eigen_ref_life_support + // In case of a failure (the caster's temp array does not live long enough), creating + // a new array (np.ones(10)) increases the chances that the temp array will be garbage + // collected and/or that its memory will be overridden with different values. + m.def("get_elem_direct", [](Eigen::Ref v) { + py::module::import("numpy").attr("ones")(10); + return v(5); + }); + m.def("get_elem_indirect", [](std::vector> v) { + py::module::import("numpy").attr("ones")(10); + return v[0](5); + }); +} diff --git a/pybind11/tests/test_eigen.py b/pybind11/tests/test_eigen.py new file mode 100644 index 0000000..45f64ca --- /dev/null +++ b/pybind11/tests/test_eigen.py @@ -0,0 +1,694 @@ +import pytest +from pybind11_tests import ConstructorStats + +pytestmark = pytest.requires_eigen_and_numpy + +with pytest.suppress(ImportError): + from pybind11_tests import eigen as m + 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.toarray()) + + +def test_fixed(): + assert_equal_ref(m.fixed_c()) + assert_equal_ref(m.fixed_r()) + assert_equal_ref(m.fixed_copy_r(m.fixed_r())) + assert_equal_ref(m.fixed_copy_c(m.fixed_c())) + assert_equal_ref(m.fixed_copy_r(m.fixed_c())) + assert_equal_ref(m.fixed_copy_c(m.fixed_r())) + + +def test_dense(): + assert_equal_ref(m.dense_r()) + assert_equal_ref(m.dense_c()) + assert_equal_ref(m.dense_copy_r(m.dense_r())) + assert_equal_ref(m.dense_copy_c(m.dense_c())) + assert_equal_ref(m.dense_copy_r(m.dense_c())) + assert_equal_ref(m.dense_copy_c(m.dense_r())) + + +def test_partially_fixed(): + ref2 = np.array([[0., 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]) + np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2), ref2) + np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2), ref2) + np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, 1]), ref2[:, [1]]) + np.testing.assert_array_equal(m.partial_copy_four_rm_c(ref2[0, :]), ref2[[0], :]) + np.testing.assert_array_equal(m.partial_copy_four_rm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)]) + np.testing.assert_array_equal( + m.partial_copy_four_rm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]) + + np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2), ref2) + np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2), ref2) + np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, 1]), ref2[:, [1]]) + np.testing.assert_array_equal(m.partial_copy_four_cm_c(ref2[0, :]), ref2[[0], :]) + np.testing.assert_array_equal(m.partial_copy_four_cm_r(ref2[:, (0, 2)]), ref2[:, (0, 2)]) + np.testing.assert_array_equal( + m.partial_copy_four_cm_c(ref2[(3, 1, 2), :]), ref2[(3, 1, 2), :]) + + # TypeError should be raise for a shape mismatch + functions = [m.partial_copy_four_rm_r, m.partial_copy_four_rm_c, + m.partial_copy_four_cm_r, m.partial_copy_four_cm_c] + matrix_with_wrong_shape = [[1, 2], + [3, 4]] + for f in functions: + with pytest.raises(TypeError) as excinfo: + f(matrix_with_wrong_shape) + assert "incompatible function arguments" in str(excinfo.value) + + +def test_mutator_descriptors(): + zr = np.arange(30, dtype='float32').reshape(5, 6) # row-major + zc = zr.reshape(6, 5).transpose() # column-major + + m.fixed_mutator_r(zr) + m.fixed_mutator_c(zc) + m.fixed_mutator_a(zr) + m.fixed_mutator_a(zc) + with pytest.raises(TypeError) as excinfo: + m.fixed_mutator_r(zc) + assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.c_contiguous]) -> None' + in str(excinfo.value)) + with pytest.raises(TypeError) as excinfo: + m.fixed_mutator_c(zr) + assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable, flags.f_contiguous]) -> None' + in str(excinfo.value)) + with pytest.raises(TypeError) as excinfo: + m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype='float32')) + assert ('(arg0: numpy.ndarray[float32[5, 6], flags.writeable]) -> None' + in str(excinfo.value)) + zr.flags.writeable = False + with pytest.raises(TypeError): + m.fixed_mutator_r(zr) + with pytest.raises(TypeError): + m.fixed_mutator_a(zr) + + +def test_cpp_casting(): + assert m.cpp_copy(m.fixed_r()) == 22. + assert m.cpp_copy(m.fixed_c()) == 22. + z = np.array([[5., 6], [7, 8]]) + assert m.cpp_copy(z) == 7. + assert m.cpp_copy(m.get_cm_ref()) == 21. + assert m.cpp_copy(m.get_rm_ref()) == 21. + assert m.cpp_ref_c(m.get_cm_ref()) == 21. + assert m.cpp_ref_r(m.get_rm_ref()) == 21. + with pytest.raises(RuntimeError) as excinfo: + # Can't reference m.fixed_c: it contains floats, m.cpp_ref_any wants doubles + m.cpp_ref_any(m.fixed_c()) + assert 'Unable to cast Python instance' in str(excinfo.value) + with pytest.raises(RuntimeError) as excinfo: + # Can't reference m.fixed_r: it contains floats, m.cpp_ref_any wants doubles + m.cpp_ref_any(m.fixed_r()) + assert 'Unable to cast Python instance' in str(excinfo.value) + assert m.cpp_ref_any(m.ReturnTester.create()) == 1. + + assert m.cpp_ref_any(m.get_cm_ref()) == 21. + assert m.cpp_ref_any(m.get_cm_ref()) == 21. + + +def test_pass_readonly_array(): + z = np.full((5, 6), 42.0) + z.flags.writeable = False + np.testing.assert_array_equal(z, m.fixed_copy_r(z)) + np.testing.assert_array_equal(m.fixed_r_const(), m.fixed_r()) + assert not m.fixed_r_const().flags.writeable + np.testing.assert_array_equal(m.fixed_copy_r(m.fixed_r_const()), m.fixed_r_const()) + + +def test_nonunit_stride_from_python(): + counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3)) + second_row = counting_mat[1, :] + second_col = counting_mat[:, 1] + np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row) + np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row) + np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row) + np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col) + np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col) + np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_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): + np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat) + np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat) + + # Mutator: + m.double_threer(second_row) + m.double_threec(second_col) + np.testing.assert_array_equal(counting_mat, [[0., 2, 2], [6, 16, 10], [6, 14, 8]]) + + +def test_negative_stride_from_python(msg): + """Eigen doesn't support (as of yet) negative strides. When a function takes an Eigen matrix by + copy or const reference, we can pass a numpy array that has negative strides. Otherwise, an + exception will be thrown as Eigen will not be able to map the numpy array.""" + + counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3)) + counting_mat = counting_mat[::-1, ::-1] + second_row = counting_mat[1, :] + second_col = counting_mat[:, 1] + np.testing.assert_array_equal(m.double_row(second_row), 2.0 * second_row) + np.testing.assert_array_equal(m.double_col(second_row), 2.0 * second_row) + np.testing.assert_array_equal(m.double_complex(second_row), 2.0 * second_row) + np.testing.assert_array_equal(m.double_row(second_col), 2.0 * second_col) + np.testing.assert_array_equal(m.double_col(second_col), 2.0 * second_col) + np.testing.assert_array_equal(m.double_complex(second_col), 2.0 * second_col) + + counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3)) + counting_3d = counting_3d[::-1, ::-1, ::-1] + slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]] + for slice_idx, ref_mat in enumerate(slices): + np.testing.assert_array_equal(m.double_mat_cm(ref_mat), 2.0 * ref_mat) + np.testing.assert_array_equal(m.double_mat_rm(ref_mat), 2.0 * ref_mat) + + # Mutator: + with pytest.raises(TypeError) as excinfo: + m.double_threer(second_row) + assert msg(excinfo.value) == """ + double_threer(): incompatible function arguments. The following argument types are supported: + 1. (arg0: numpy.ndarray[float32[1, 3], flags.writeable]) -> None + + Invoked with: """ + repr(np.array([ 5., 4., 3.], dtype='float32')) # noqa: E501 line too long + + with pytest.raises(TypeError) as excinfo: + m.double_threec(second_col) + assert msg(excinfo.value) == """ + double_threec(): incompatible function arguments. The following argument types are supported: + 1. (arg0: numpy.ndarray[float32[3, 1], flags.writeable]) -> None + + Invoked with: """ + repr(np.array([ 7., 4., 1.], dtype='float32')) # noqa: E501 line too long + + +def test_nonunit_stride_to_python(): + assert np.all(m.diagonal(ref) == ref.diagonal()) + assert np.all(m.diagonal_1(ref) == ref.diagonal(1)) + for i in range(-5, 7): + assert np.all(m.diagonal_n(ref, i) == ref.diagonal(i)), "m.diagonal_n({})".format(i) + + assert np.all(m.block(ref, 2, 1, 3, 3) == ref[2:5, 1:4]) + assert np.all(m.block(ref, 1, 4, 4, 2) == ref[1:, 4:]) + assert np.all(m.block(ref, 1, 4, 3, 2) == ref[1:4, 4:]) + + +def test_eigen_ref_to_python(): + chols = [m.cholesky1, m.cholesky2, m.cholesky3, m.cholesky4] + 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) + + +def assign_both(a1, a2, r, c, v): + a1[r, c] = v + a2[r, c] = v + + +def array_copy_but_one(a, r, c, v): + z = np.array(a, copy=True) + z[r, c] = v + return z + + +def test_eigen_return_references(): + """Tests various ways of returning references and non-referencing copies""" + + master = np.ones((10, 10)) + a = m.ReturnTester() + a_get1 = a.get() + assert not a_get1.flags.owndata and a_get1.flags.writeable + assign_both(a_get1, master, 3, 3, 5) + a_get2 = a.get_ptr() + assert not a_get2.flags.owndata and a_get2.flags.writeable + assign_both(a_get1, master, 2, 3, 6) + + a_view1 = a.view() + assert not a_view1.flags.owndata and not a_view1.flags.writeable + with pytest.raises(ValueError): + a_view1[2, 3] = 4 + a_view2 = a.view_ptr() + assert not a_view2.flags.owndata and not a_view2.flags.writeable + with pytest.raises(ValueError): + a_view2[2, 3] = 4 + + a_copy1 = a.copy_get() + assert a_copy1.flags.owndata and a_copy1.flags.writeable + np.testing.assert_array_equal(a_copy1, master) + a_copy1[7, 7] = -44 # Shouldn't affect anything else + c1want = array_copy_but_one(master, 7, 7, -44) + a_copy2 = a.copy_view() + assert a_copy2.flags.owndata and a_copy2.flags.writeable + np.testing.assert_array_equal(a_copy2, master) + a_copy2[4, 4] = -22 # Shouldn't affect anything else + c2want = array_copy_but_one(master, 4, 4, -22) + + a_ref1 = a.ref() + assert not a_ref1.flags.owndata and a_ref1.flags.writeable + assign_both(a_ref1, master, 1, 1, 15) + a_ref2 = a.ref_const() + assert not a_ref2.flags.owndata and not a_ref2.flags.writeable + with pytest.raises(ValueError): + a_ref2[5, 5] = 33 + a_ref3 = a.ref_safe() + assert not a_ref3.flags.owndata and a_ref3.flags.writeable + assign_both(a_ref3, master, 0, 7, 99) + a_ref4 = a.ref_const_safe() + assert not a_ref4.flags.owndata and not a_ref4.flags.writeable + with pytest.raises(ValueError): + a_ref4[7, 0] = 987654321 + + a_copy3 = a.copy_ref() + assert a_copy3.flags.owndata and a_copy3.flags.writeable + np.testing.assert_array_equal(a_copy3, master) + a_copy3[8, 1] = 11 + c3want = array_copy_but_one(master, 8, 1, 11) + a_copy4 = a.copy_ref_const() + assert a_copy4.flags.owndata and a_copy4.flags.writeable + np.testing.assert_array_equal(a_copy4, master) + a_copy4[8, 4] = 88 + c4want = array_copy_but_one(master, 8, 4, 88) + + a_block1 = a.block(3, 3, 2, 2) + assert not a_block1.flags.owndata and a_block1.flags.writeable + a_block1[0, 0] = 55 + master[3, 3] = 55 + a_block2 = a.block_safe(2, 2, 3, 2) + assert not a_block2.flags.owndata and a_block2.flags.writeable + a_block2[2, 1] = -123 + master[4, 3] = -123 + a_block3 = a.block_const(6, 7, 4, 3) + assert not a_block3.flags.owndata and not a_block3.flags.writeable + with pytest.raises(ValueError): + a_block3[2, 2] = -44444 + + a_copy5 = a.copy_block(2, 2, 2, 3) + assert a_copy5.flags.owndata and a_copy5.flags.writeable + np.testing.assert_array_equal(a_copy5, master[2:4, 2:5]) + a_copy5[1, 1] = 777 + c5want = array_copy_but_one(master[2:4, 2:5], 1, 1, 777) + + a_corn1 = a.corners() + assert not a_corn1.flags.owndata and a_corn1.flags.writeable + a_corn1 *= 50 + a_corn1[1, 1] = 999 + master[0, 0] = 50 + master[0, 9] = 50 + master[9, 0] = 50 + master[9, 9] = 999 + a_corn2 = a.corners_const() + assert not a_corn2.flags.owndata and not a_corn2.flags.writeable + with pytest.raises(ValueError): + a_corn2[1, 0] = 51 + + # All of the changes made all the way along should be visible everywhere + # now (except for the copies, of course) + np.testing.assert_array_equal(a_get1, master) + np.testing.assert_array_equal(a_get2, master) + np.testing.assert_array_equal(a_view1, master) + np.testing.assert_array_equal(a_view2, master) + np.testing.assert_array_equal(a_ref1, master) + np.testing.assert_array_equal(a_ref2, master) + np.testing.assert_array_equal(a_ref3, master) + np.testing.assert_array_equal(a_ref4, master) + np.testing.assert_array_equal(a_block1, master[3:5, 3:5]) + np.testing.assert_array_equal(a_block2, master[2:5, 2:4]) + np.testing.assert_array_equal(a_block3, master[6:10, 7:10]) + np.testing.assert_array_equal(a_corn1, master[0::master.shape[0] - 1, 0::master.shape[1] - 1]) + np.testing.assert_array_equal(a_corn2, master[0::master.shape[0] - 1, 0::master.shape[1] - 1]) + + np.testing.assert_array_equal(a_copy1, c1want) + np.testing.assert_array_equal(a_copy2, c2want) + np.testing.assert_array_equal(a_copy3, c3want) + np.testing.assert_array_equal(a_copy4, c4want) + np.testing.assert_array_equal(a_copy5, c5want) + + +def assert_keeps_alive(cl, method, *args): + cstats = ConstructorStats.get(cl) + start_with = cstats.alive() + a = cl() + assert cstats.alive() == start_with + 1 + z = method(a, *args) + assert cstats.alive() == start_with + 1 + del a + # Here's the keep alive in action: + assert cstats.alive() == start_with + 1 + del z + # Keep alive should have expired: + assert cstats.alive() == start_with + + +def test_eigen_keepalive(): + a = m.ReturnTester() + cstats = ConstructorStats.get(m.ReturnTester) + assert cstats.alive() == 1 + unsafe = [a.ref(), a.ref_const(), a.block(1, 2, 3, 4)] + copies = [a.copy_get(), a.copy_view(), a.copy_ref(), a.copy_ref_const(), + a.copy_block(4, 3, 2, 1)] + del a + assert cstats.alive() == 0 + del unsafe + del copies + + for meth in [m.ReturnTester.get, m.ReturnTester.get_ptr, m.ReturnTester.view, + m.ReturnTester.view_ptr, m.ReturnTester.ref_safe, m.ReturnTester.ref_const_safe, + m.ReturnTester.corners, m.ReturnTester.corners_const]: + assert_keeps_alive(m.ReturnTester, meth) + + for meth in [m.ReturnTester.block_safe, m.ReturnTester.block_const]: + assert_keeps_alive(m.ReturnTester, meth, 4, 3, 2, 1) + + +def test_eigen_ref_mutators(): + """Tests Eigen's ability to mutate numpy values""" + + orig = np.array([[1., 2, 3], [4, 5, 6], [7, 8, 9]]) + zr = np.array(orig) + zc = np.array(orig, order='F') + m.add_rm(zr, 1, 0, 100) + assert np.all(zr == np.array([[1., 2, 3], [104, 5, 6], [7, 8, 9]])) + m.add_cm(zc, 1, 0, 200) + assert np.all(zc == np.array([[1., 2, 3], [204, 5, 6], [7, 8, 9]])) + + m.add_any(zr, 1, 0, 20) + assert np.all(zr == np.array([[1., 2, 3], [124, 5, 6], [7, 8, 9]])) + m.add_any(zc, 1, 0, 10) + assert np.all(zc == np.array([[1., 2, 3], [214, 5, 6], [7, 8, 9]])) + + # Can't reference a col-major array with a row-major Ref, and vice versa: + with pytest.raises(TypeError): + m.add_rm(zc, 1, 0, 1) + with pytest.raises(TypeError): + m.add_cm(zr, 1, 0, 1) + + # Overloads: + m.add1(zr, 1, 0, -100) + m.add2(zr, 1, 0, -20) + assert np.all(zr == orig) + m.add1(zc, 1, 0, -200) + m.add2(zc, 1, 0, -10) + assert np.all(zc == orig) + + # a non-contiguous slice (this won't work on either the row- or + # column-contiguous refs, but should work for the any) + cornersr = zr[0::2, 0::2] + cornersc = zc[0::2, 0::2] + + assert np.all(cornersr == np.array([[1., 3], [7, 9]])) + assert np.all(cornersc == np.array([[1., 3], [7, 9]])) + + with pytest.raises(TypeError): + m.add_rm(cornersr, 0, 1, 25) + with pytest.raises(TypeError): + m.add_cm(cornersr, 0, 1, 25) + with pytest.raises(TypeError): + m.add_rm(cornersc, 0, 1, 25) + with pytest.raises(TypeError): + m.add_cm(cornersc, 0, 1, 25) + m.add_any(cornersr, 0, 1, 25) + m.add_any(cornersc, 0, 1, 44) + assert np.all(zr == np.array([[1., 2, 28], [4, 5, 6], [7, 8, 9]])) + assert np.all(zc == np.array([[1., 2, 47], [4, 5, 6], [7, 8, 9]])) + + # You shouldn't be allowed to pass a non-writeable array to a mutating Eigen method: + zro = zr[0:4, 0:4] + zro.flags.writeable = False + with pytest.raises(TypeError): + m.add_rm(zro, 0, 0, 0) + with pytest.raises(TypeError): + m.add_any(zro, 0, 0, 0) + with pytest.raises(TypeError): + m.add1(zro, 0, 0, 0) + with pytest.raises(TypeError): + m.add2(zro, 0, 0, 0) + + # integer array shouldn't be passable to a double-matrix-accepting mutating func: + zi = np.array([[1, 2], [3, 4]]) + with pytest.raises(TypeError): + m.add_rm(zi) + + +def test_numpy_ref_mutators(): + """Tests numpy mutating Eigen matrices (for returned Eigen::Ref<...>s)""" + + m.reset_refs() # In case another test already changed it + + zc = m.get_cm_ref() + zcro = m.get_cm_const_ref() + zr = m.get_rm_ref() + zrro = m.get_rm_const_ref() + + assert [zc[1, 2], zcro[1, 2], zr[1, 2], zrro[1, 2]] == [23] * 4 + + assert not zc.flags.owndata and zc.flags.writeable + assert not zr.flags.owndata and zr.flags.writeable + assert not zcro.flags.owndata and not zcro.flags.writeable + assert not zrro.flags.owndata and not zrro.flags.writeable + + zc[1, 2] = 99 + expect = np.array([[11., 12, 13], [21, 22, 99], [31, 32, 33]]) + # We should have just changed zc, of course, but also zcro and the original eigen matrix + assert np.all(zc == expect) + assert np.all(zcro == expect) + assert np.all(m.get_cm_ref() == expect) + + zr[1, 2] = 99 + assert np.all(zr == expect) + assert np.all(zrro == expect) + assert np.all(m.get_rm_ref() == expect) + + # Make sure the readonly ones are numpy-readonly: + with pytest.raises(ValueError): + zcro[1, 2] = 6 + with pytest.raises(ValueError): + zrro[1, 2] = 6 + + # We should be able to explicitly copy like this (and since we're copying, + # the const should drop away) + y1 = np.array(m.get_cm_const_ref()) + + assert y1.flags.owndata and y1.flags.writeable + # We should get copies of the eigen data, which was modified above: + assert y1[1, 2] == 99 + y1[1, 2] += 12 + assert y1[1, 2] == 111 + assert zc[1, 2] == 99 # Make sure we aren't referencing the original + + +def test_both_ref_mutators(): + """Tests a complex chain of nested eigen/numpy references""" + + m.reset_refs() # In case another test already changed it + + z = m.get_cm_ref() # numpy -> eigen + z[0, 2] -= 3 + z2 = m.incr_matrix(z, 1) # numpy -> eigen -> numpy -> eigen + z2[1, 1] += 6 + z3 = m.incr_matrix(z, 2) # (numpy -> eigen)^3 + z3[2, 2] += -5 + z4 = m.incr_matrix(z, 3) # (numpy -> eigen)^4 + z4[1, 1] -= 1 + z5 = m.incr_matrix(z, 4) # (numpy -> eigen)^5 + z5[0, 0] = 0 + assert np.all(z == z2) + assert np.all(z == z3) + assert np.all(z == z4) + assert np.all(z == z5) + expect = np.array([[0., 22, 20], [31, 37, 33], [41, 42, 38]]) + assert np.all(z == expect) + + y = np.array(range(100), dtype='float64').reshape(10, 10) + y2 = m.incr_matrix_any(y, 10) # np -> eigen -> np + y3 = m.incr_matrix_any(y2[0::2, 0::2], -33) # np -> eigen -> np slice -> np -> eigen -> np + y4 = m.even_rows(y3) # numpy -> eigen slice -> (... y3) + y5 = m.even_cols(y4) # numpy -> eigen slice -> (... y4) + y6 = m.incr_matrix_any(y5, 1000) # numpy -> eigen -> (... y5) + + # Apply same mutations using just numpy: + yexpect = np.array(range(100), dtype='float64').reshape(10, 10) + yexpect += 10 + yexpect[0::2, 0::2] -= 33 + yexpect[0::4, 0::4] += 1000 + assert np.all(y6 == yexpect[0::4, 0::4]) + assert np.all(y5 == yexpect[0::4, 0::4]) + assert np.all(y4 == yexpect[0::4, 0::2]) + assert np.all(y3 == yexpect[0::2, 0::2]) + assert np.all(y2 == yexpect) + assert np.all(y == yexpect) + + +def test_nocopy_wrapper(): + # get_elem requires a column-contiguous matrix reference, but should be + # callable with other types of matrix (via copying): + int_matrix_colmajor = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], order='F') + dbl_matrix_colmajor = np.array(int_matrix_colmajor, dtype='double', order='F', copy=True) + int_matrix_rowmajor = np.array(int_matrix_colmajor, order='C', copy=True) + dbl_matrix_rowmajor = np.array(int_matrix_rowmajor, dtype='double', order='C', copy=True) + + # All should be callable via get_elem: + assert m.get_elem(int_matrix_colmajor) == 8 + assert m.get_elem(dbl_matrix_colmajor) == 8 + assert m.get_elem(int_matrix_rowmajor) == 8 + assert m.get_elem(dbl_matrix_rowmajor) == 8 + + # All but the second should fail with m.get_elem_nocopy: + with pytest.raises(TypeError) as excinfo: + m.get_elem_nocopy(int_matrix_colmajor) + assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and + ', flags.f_contiguous' in str(excinfo.value)) + assert m.get_elem_nocopy(dbl_matrix_colmajor) == 8 + with pytest.raises(TypeError) as excinfo: + m.get_elem_nocopy(int_matrix_rowmajor) + assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and + ', flags.f_contiguous' in str(excinfo.value)) + with pytest.raises(TypeError) as excinfo: + m.get_elem_nocopy(dbl_matrix_rowmajor) + assert ('get_elem_nocopy(): incompatible function arguments.' in str(excinfo.value) and + ', flags.f_contiguous' in str(excinfo.value)) + + # For the row-major test, we take a long matrix in row-major, so only the third is allowed: + with pytest.raises(TypeError) as excinfo: + m.get_elem_rm_nocopy(int_matrix_colmajor) + assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and + ', flags.c_contiguous' in str(excinfo.value)) + with pytest.raises(TypeError) as excinfo: + m.get_elem_rm_nocopy(dbl_matrix_colmajor) + assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and + ', flags.c_contiguous' in str(excinfo.value)) + assert m.get_elem_rm_nocopy(int_matrix_rowmajor) == 8 + with pytest.raises(TypeError) as excinfo: + m.get_elem_rm_nocopy(dbl_matrix_rowmajor) + assert ('get_elem_rm_nocopy(): incompatible function arguments.' in str(excinfo.value) and + ', flags.c_contiguous' in str(excinfo.value)) + + +def test_eigen_ref_life_support(): + """Ensure the lifetime of temporary arrays created by the `Ref` caster + + The `Ref` caster sometimes creates a copy which needs to stay alive. This needs to + happen both for directs casts (just the array) or indirectly (e.g. list of arrays). + """ + + a = np.full(shape=10, fill_value=8, dtype=np.int8) + assert m.get_elem_direct(a) == 8 + + list_of_a = [a] + assert m.get_elem_indirect(list_of_a) == 8 + + +def test_special_matrix_objects(): + assert np.all(m.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(m.symmetric_lower(asymm) == symm_lower) + assert np.all(m.symmetric_upper(asymm) == symm_upper) + + +def test_dense_signature(doc): + assert doc(m.double_col) == """ + double_col(arg0: numpy.ndarray[float32[m, 1]]) -> numpy.ndarray[float32[m, 1]] + """ + assert doc(m.double_row) == """ + double_row(arg0: numpy.ndarray[float32[1, n]]) -> numpy.ndarray[float32[1, n]] + """ + assert doc(m.double_complex) == """ + double_complex(arg0: numpy.ndarray[complex64[m, 1]]) -> numpy.ndarray[complex64[m, 1]] + """ + assert doc(m.double_mat_rm) == """ + double_mat_rm(arg0: numpy.ndarray[float32[m, n]]) -> numpy.ndarray[float32[m, n]] + """ + + +def test_named_arguments(): + a = np.array([[1.0, 2], [3, 4], [5, 6]]) + b = np.ones((2, 1)) + + assert np.all(m.matrix_multiply(a, b) == np.array([[3.], [7], [11]])) + assert np.all(m.matrix_multiply(A=a, B=b) == np.array([[3.], [7], [11]])) + assert np.all(m.matrix_multiply(B=b, A=a) == np.array([[3.], [7], [11]])) + + with pytest.raises(ValueError) as excinfo: + m.matrix_multiply(b, a) + assert str(excinfo.value) == 'Nonconformable matrices!' + + with pytest.raises(ValueError) as excinfo: + m.matrix_multiply(A=b, B=a) + assert str(excinfo.value) == 'Nonconformable matrices!' + + with pytest.raises(ValueError) as excinfo: + m.matrix_multiply(B=a, A=b) + assert str(excinfo.value) == 'Nonconformable matrices!' + + +@pytest.requires_eigen_and_scipy +def test_sparse(): + assert_sparse_equal_ref(m.sparse_r()) + assert_sparse_equal_ref(m.sparse_c()) + assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_r())) + assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_c())) + assert_sparse_equal_ref(m.sparse_copy_r(m.sparse_c())) + assert_sparse_equal_ref(m.sparse_copy_c(m.sparse_r())) + + +@pytest.requires_eigen_and_scipy +def test_sparse_signature(doc): + assert doc(m.sparse_copy_r) == """ + sparse_copy_r(arg0: scipy.sparse.csr_matrix[float32]) -> scipy.sparse.csr_matrix[float32] + """ # noqa: E501 line too long + assert doc(m.sparse_copy_c) == """ + sparse_copy_c(arg0: scipy.sparse.csc_matrix[float32]) -> scipy.sparse.csc_matrix[float32] + """ # noqa: E501 line too long + + +def test_issue738(): + """Ignore strides on a length-1 dimension (even if they would be incompatible length > 1)""" + assert np.all(m.iss738_f1(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]])) + assert np.all(m.iss738_f1(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]])) + + assert np.all(m.iss738_f2(np.array([[1., 2, 3]])) == np.array([[1., 102, 203]])) + assert np.all(m.iss738_f2(np.array([[1.], [2], [3]])) == np.array([[1.], [12], [23]])) + + +def test_issue1105(): + """Issue 1105: 1xN or Nx1 input arrays weren't accepted for eigen + compile-time row vectors or column vector""" + assert m.iss1105_row(np.ones((1, 7))) + assert m.iss1105_col(np.ones((7, 1))) + + # These should still fail (incompatible dimensions): + with pytest.raises(TypeError) as excinfo: + m.iss1105_row(np.ones((7, 1))) + assert "incompatible function arguments" in str(excinfo) + with pytest.raises(TypeError) as excinfo: + m.iss1105_col(np.ones((1, 7))) + assert "incompatible function arguments" in str(excinfo) + + +def test_custom_operator_new(): + """Using Eigen types as member variables requires a class-specific + operator new with proper alignment""" + + o = m.CustomOperatorNew() + np.testing.assert_allclose(o.a, 0.0) + np.testing.assert_allclose(o.b.diagonal(), 1.0) diff --git a/pybind11/tests/test_embed/CMakeLists.txt b/pybind11/tests/test_embed/CMakeLists.txt new file mode 100644 index 0000000..8b4f1f8 --- /dev/null +++ b/pybind11/tests/test_embed/CMakeLists.txt @@ -0,0 +1,41 @@ +if(${PYTHON_MODULE_EXTENSION} MATCHES "pypy") + add_custom_target(cpptest) # Dummy target on PyPy. Embedding is not supported. + set(_suppress_unused_variable_warning "${DOWNLOAD_CATCH}") + return() +endif() + +find_package(Catch 1.9.3) +if(CATCH_FOUND) + message(STATUS "Building interpreter tests using Catch v${CATCH_VERSION}") +else() + message(STATUS "Catch not detected. Interpreter tests will be skipped. Install Catch headers" + " manually or use `cmake -DDOWNLOAD_CATCH=1` to fetch them automatically.") + return() +endif() + +add_executable(test_embed + catch.cpp + test_interpreter.cpp +) +target_include_directories(test_embed PRIVATE ${CATCH_INCLUDE_DIR}) +pybind11_enable_warnings(test_embed) + +if(NOT CMAKE_VERSION VERSION_LESS 3.0) + target_link_libraries(test_embed PRIVATE pybind11::embed) +else() + target_include_directories(test_embed PRIVATE ${PYBIND11_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS}) + target_compile_options(test_embed PRIVATE ${PYBIND11_CPP_STANDARD}) + target_link_libraries(test_embed PRIVATE ${PYTHON_LIBRARIES}) +endif() + +find_package(Threads REQUIRED) +target_link_libraries(test_embed PUBLIC ${CMAKE_THREAD_LIBS_INIT}) + +add_custom_target(cpptest COMMAND $ + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +pybind11_add_module(external_module THIN_LTO external_module.cpp) +set_target_properties(external_module PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +add_dependencies(cpptest external_module) + +add_dependencies(check cpptest) diff --git a/pybind11/tests/test_embed/catch.cpp b/pybind11/tests/test_embed/catch.cpp new file mode 100644 index 0000000..dd13738 --- /dev/null +++ b/pybind11/tests/test_embed/catch.cpp @@ -0,0 +1,22 @@ +// The Catch implementation is compiled here. This is a standalone +// translation unit to avoid recompiling it for every test change. + +#include + +#ifdef _MSC_VER +// Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to catch +// 2.0.1; this should be fixed in the next catch release after 2.0.1). +# pragma warning(disable: 4996) +#endif + +#define CATCH_CONFIG_RUNNER +#include + +namespace py = pybind11; + +int main(int argc, char *argv[]) { + py::scoped_interpreter guard{}; + auto result = Catch::Session().run(argc, argv); + + return result < 0xff ? result : 0xff; +} diff --git a/pybind11/tests/test_embed/external_module.cpp b/pybind11/tests/test_embed/external_module.cpp new file mode 100644 index 0000000..e9a6058 --- /dev/null +++ b/pybind11/tests/test_embed/external_module.cpp @@ -0,0 +1,23 @@ +#include + +namespace py = pybind11; + +/* Simple test module/test class to check that the referenced internals data of external pybind11 + * modules aren't preserved over a finalize/initialize. + */ + +PYBIND11_MODULE(external_module, m) { + class A { + public: + A(int value) : v{value} {}; + int v; + }; + + py::class_(m, "A") + .def(py::init()) + .def_readwrite("value", &A::v); + + m.def("internals_at", []() { + return reinterpret_cast(&py::detail::get_internals()); + }); +} diff --git a/pybind11/tests/test_embed/test_interpreter.cpp b/pybind11/tests/test_embed/test_interpreter.cpp new file mode 100644 index 0000000..222bd56 --- /dev/null +++ b/pybind11/tests/test_embed/test_interpreter.cpp @@ -0,0 +1,284 @@ +#include + +#ifdef _MSC_VER +// Silence MSVC C++17 deprecation warning from Catch regarding std::uncaught_exceptions (up to catch +// 2.0.1; this should be fixed in the next catch release after 2.0.1). +# pragma warning(disable: 4996) +#endif + +#include + +#include +#include +#include + +namespace py = pybind11; +using namespace py::literals; + +class Widget { +public: + Widget(std::string message) : message(message) { } + virtual ~Widget() = default; + + std::string the_message() const { return message; } + virtual int the_answer() const = 0; + +private: + std::string message; +}; + +class PyWidget final : public Widget { + using Widget::Widget; + + int the_answer() const override { PYBIND11_OVERLOAD_PURE(int, Widget, the_answer); } +}; + +PYBIND11_EMBEDDED_MODULE(widget_module, m) { + py::class_(m, "Widget") + .def(py::init()) + .def_property_readonly("the_message", &Widget::the_message); + + m.def("add", [](int i, int j) { return i + j; }); +} + +PYBIND11_EMBEDDED_MODULE(throw_exception, ) { + throw std::runtime_error("C++ Error"); +} + +PYBIND11_EMBEDDED_MODULE(throw_error_already_set, ) { + auto d = py::dict(); + d["missing"].cast(); +} + +TEST_CASE("Pass classes and data between modules defined in C++ and Python") { + auto module = py::module::import("test_interpreter"); + REQUIRE(py::hasattr(module, "DerivedWidget")); + + auto locals = py::dict("hello"_a="Hello, World!", "x"_a=5, **module.attr("__dict__")); + py::exec(R"( + widget = DerivedWidget("{} - {}".format(hello, x)) + message = widget.the_message + )", py::globals(), locals); + REQUIRE(locals["message"].cast() == "Hello, World! - 5"); + + auto py_widget = module.attr("DerivedWidget")("The question"); + auto message = py_widget.attr("the_message"); + REQUIRE(message.cast() == "The question"); + + const auto &cpp_widget = py_widget.cast(); + REQUIRE(cpp_widget.the_answer() == 42); +} + +TEST_CASE("Import error handling") { + REQUIRE_NOTHROW(py::module::import("widget_module")); + REQUIRE_THROWS_WITH(py::module::import("throw_exception"), + "ImportError: C++ Error"); + REQUIRE_THROWS_WITH(py::module::import("throw_error_already_set"), + Catch::Contains("ImportError: KeyError")); +} + +TEST_CASE("There can be only one interpreter") { + static_assert(std::is_move_constructible::value, ""); + static_assert(!std::is_move_assignable::value, ""); + static_assert(!std::is_copy_constructible::value, ""); + static_assert(!std::is_copy_assignable::value, ""); + + REQUIRE_THROWS_WITH(py::initialize_interpreter(), "The interpreter is already running"); + REQUIRE_THROWS_WITH(py::scoped_interpreter(), "The interpreter is already running"); + + py::finalize_interpreter(); + REQUIRE_NOTHROW(py::scoped_interpreter()); + { + auto pyi1 = py::scoped_interpreter(); + auto pyi2 = std::move(pyi1); + } + py::initialize_interpreter(); +} + +bool has_pybind11_internals_builtin() { + auto builtins = py::handle(PyEval_GetBuiltins()); + return builtins.contains(PYBIND11_INTERNALS_ID); +}; + +bool has_pybind11_internals_static() { + auto **&ipp = py::detail::get_internals_pp(); + return ipp && *ipp; +} + +TEST_CASE("Restart the interpreter") { + // Verify pre-restart state. + REQUIRE(py::module::import("widget_module").attr("add")(1, 2).cast() == 3); + REQUIRE(has_pybind11_internals_builtin()); + REQUIRE(has_pybind11_internals_static()); + REQUIRE(py::module::import("external_module").attr("A")(123).attr("value").cast() == 123); + + // local and foreign module internals should point to the same internals: + REQUIRE(reinterpret_cast(*py::detail::get_internals_pp()) == + py::module::import("external_module").attr("internals_at")().cast()); + + // Restart the interpreter. + py::finalize_interpreter(); + REQUIRE(Py_IsInitialized() == 0); + + py::initialize_interpreter(); + REQUIRE(Py_IsInitialized() == 1); + + // Internals are deleted after a restart. + REQUIRE_FALSE(has_pybind11_internals_builtin()); + REQUIRE_FALSE(has_pybind11_internals_static()); + pybind11::detail::get_internals(); + REQUIRE(has_pybind11_internals_builtin()); + REQUIRE(has_pybind11_internals_static()); + REQUIRE(reinterpret_cast(*py::detail::get_internals_pp()) == + py::module::import("external_module").attr("internals_at")().cast()); + + // Make sure that an interpreter with no get_internals() created until finalize still gets the + // internals destroyed + py::finalize_interpreter(); + py::initialize_interpreter(); + bool ran = false; + py::module::import("__main__").attr("internals_destroy_test") = + py::capsule(&ran, [](void *ran) { py::detail::get_internals(); *static_cast(ran) = true; }); + REQUIRE_FALSE(has_pybind11_internals_builtin()); + REQUIRE_FALSE(has_pybind11_internals_static()); + REQUIRE_FALSE(ran); + py::finalize_interpreter(); + REQUIRE(ran); + py::initialize_interpreter(); + REQUIRE_FALSE(has_pybind11_internals_builtin()); + REQUIRE_FALSE(has_pybind11_internals_static()); + + // C++ modules can be reloaded. + auto cpp_module = py::module::import("widget_module"); + REQUIRE(cpp_module.attr("add")(1, 2).cast() == 3); + + // C++ type information is reloaded and can be used in python modules. + auto py_module = py::module::import("test_interpreter"); + auto py_widget = py_module.attr("DerivedWidget")("Hello after restart"); + REQUIRE(py_widget.attr("the_message").cast() == "Hello after restart"); +} + +TEST_CASE("Subinterpreter") { + // Add tags to the modules in the main interpreter and test the basics. + py::module::import("__main__").attr("main_tag") = "main interpreter"; + { + auto m = py::module::import("widget_module"); + m.attr("extension_module_tag") = "added to module in main interpreter"; + + REQUIRE(m.attr("add")(1, 2).cast() == 3); + } + REQUIRE(has_pybind11_internals_builtin()); + REQUIRE(has_pybind11_internals_static()); + + /// Create and switch to a subinterpreter. + auto main_tstate = PyThreadState_Get(); + auto sub_tstate = Py_NewInterpreter(); + + // Subinterpreters get their own copy of builtins. detail::get_internals() still + // works by returning from the static variable, i.e. all interpreters share a single + // global pybind11::internals; + REQUIRE_FALSE(has_pybind11_internals_builtin()); + REQUIRE(has_pybind11_internals_static()); + + // Modules tags should be gone. + REQUIRE_FALSE(py::hasattr(py::module::import("__main__"), "tag")); + { + auto m = py::module::import("widget_module"); + REQUIRE_FALSE(py::hasattr(m, "extension_module_tag")); + + // Function bindings should still work. + REQUIRE(m.attr("add")(1, 2).cast() == 3); + } + + // Restore main interpreter. + Py_EndInterpreter(sub_tstate); + PyThreadState_Swap(main_tstate); + + REQUIRE(py::hasattr(py::module::import("__main__"), "main_tag")); + REQUIRE(py::hasattr(py::module::import("widget_module"), "extension_module_tag")); +} + +TEST_CASE("Execution frame") { + // When the interpreter is embedded, there is no execution frame, but `py::exec` + // should still function by using reasonable globals: `__main__.__dict__`. + py::exec("var = dict(number=42)"); + REQUIRE(py::globals()["var"]["number"].cast() == 42); +} + +TEST_CASE("Threads") { + // Restart interpreter to ensure threads are not initialized + py::finalize_interpreter(); + py::initialize_interpreter(); + REQUIRE_FALSE(has_pybind11_internals_static()); + + constexpr auto num_threads = 10; + auto locals = py::dict("count"_a=0); + + { + py::gil_scoped_release gil_release{}; + REQUIRE(has_pybind11_internals_static()); + + auto threads = std::vector(); + for (auto i = 0; i < num_threads; ++i) { + threads.emplace_back([&]() { + py::gil_scoped_acquire gil{}; + locals["count"] = locals["count"].cast() + 1; + }); + } + + for (auto &thread : threads) { + thread.join(); + } + } + + REQUIRE(locals["count"].cast() == num_threads); +} + +// Scope exit utility https://stackoverflow.com/a/36644501/7255855 +struct scope_exit { + std::function f_; + explicit scope_exit(std::function f) noexcept : f_(std::move(f)) {} + ~scope_exit() { if (f_) f_(); } +}; + +TEST_CASE("Reload module from file") { + // Disable generation of cached bytecode (.pyc files) for this test, otherwise + // Python might pick up an old version from the cache instead of the new versions + // of the .py files generated below + auto sys = py::module::import("sys"); + bool dont_write_bytecode = sys.attr("dont_write_bytecode").cast(); + sys.attr("dont_write_bytecode") = true; + // Reset the value at scope exit + scope_exit reset_dont_write_bytecode([&]() { + sys.attr("dont_write_bytecode") = dont_write_bytecode; + }); + + std::string module_name = "test_module_reload"; + std::string module_file = module_name + ".py"; + + // Create the module .py file + std::ofstream test_module(module_file); + test_module << "def test():\n"; + test_module << " return 1\n"; + test_module.close(); + // Delete the file at scope exit + scope_exit delete_module_file([&]() { + std::remove(module_file.c_str()); + }); + + // Import the module from file + auto module = py::module::import(module_name.c_str()); + int result = module.attr("test")().cast(); + REQUIRE(result == 1); + + // Update the module .py file with a small change + test_module.open(module_file); + test_module << "def test():\n"; + test_module << " return 2\n"; + test_module.close(); + + // Reload the module + module.reload(); + result = module.attr("test")().cast(); + REQUIRE(result == 2); +} diff --git a/pybind11/tests/test_embed/test_interpreter.py b/pybind11/tests/test_embed/test_interpreter.py new file mode 100644 index 0000000..26a0479 --- /dev/null +++ b/pybind11/tests/test_embed/test_interpreter.py @@ -0,0 +1,9 @@ +from widget_module import Widget + + +class DerivedWidget(Widget): + def __init__(self, message): + super(DerivedWidget, self).__init__(message) + + def the_answer(self): + return 42 diff --git a/pybind11/tests/test_enum.cpp b/pybind11/tests/test_enum.cpp new file mode 100644 index 0000000..498a00e --- /dev/null +++ b/pybind11/tests/test_enum.cpp @@ -0,0 +1,85 @@ +/* + 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" + +TEST_SUBMODULE(enums, m) { + // test_unscoped_enum + enum UnscopedEnum { + EOne = 1, + ETwo + }; + py::enum_(m, "UnscopedEnum", py::arithmetic(), "An unscoped enumeration") + .value("EOne", EOne, "Docstring for EOne") + .value("ETwo", ETwo, "Docstring for ETwo") + .export_values(); + + // test_scoped_enum + enum class ScopedEnum { + Two = 2, + Three + }; + py::enum_(m, "ScopedEnum", py::arithmetic()) + .value("Two", ScopedEnum::Two) + .value("Three", ScopedEnum::Three); + + m.def("test_scoped_enum", [](ScopedEnum z) { + return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three"); + }); + + // test_binary_operators + enum Flags { + Read = 4, + Write = 2, + Execute = 1 + }; + py::enum_(m, "Flags", py::arithmetic()) + .value("Read", Flags::Read) + .value("Write", Flags::Write) + .value("Execute", Flags::Execute) + .export_values(); + + // test_implicit_conversion + class ClassWithUnscopedEnum { + public: + enum EMode { + EFirstMode = 1, + ESecondMode + }; + + static EMode test_function(EMode mode) { + return mode; + } + }; + 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(); + + // test_enum_to_int + m.def("test_enum_to_int", [](int) { }); + m.def("test_enum_to_uint", [](uint32_t) { }); + m.def("test_enum_to_long_long", [](long long) { }); + + // test_duplicate_enum_name + enum SimpleEnum + { + ONE, TWO, THREE + }; + + m.def("register_bad_enum", [m]() { + py::enum_(m, "SimpleEnum") + .value("ONE", SimpleEnum::ONE) //NOTE: all value function calls are called with the same first parameter value + .value("ONE", SimpleEnum::TWO) + .value("ONE", SimpleEnum::THREE) + .export_values(); + }); +} diff --git a/pybind11/tests/test_enum.py b/pybind11/tests/test_enum.py new file mode 100644 index 0000000..d0989ad --- /dev/null +++ b/pybind11/tests/test_enum.py @@ -0,0 +1,167 @@ +import pytest +from pybind11_tests import enums as m + + +def test_unscoped_enum(): + assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne" + assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo" + assert str(m.EOne) == "UnscopedEnum.EOne" + + # name property + assert m.UnscopedEnum.EOne.name == "EOne" + assert m.UnscopedEnum.ETwo.name == "ETwo" + assert m.EOne.name == "EOne" + # name readonly + with pytest.raises(AttributeError): + m.UnscopedEnum.EOne.name = "" + # name returns a copy + foo = m.UnscopedEnum.EOne.name + foo = "bar" + assert m.UnscopedEnum.EOne.name == "EOne" + + # __members__ property + assert m.UnscopedEnum.__members__ == \ + {"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo} + # __members__ readonly + with pytest.raises(AttributeError): + m.UnscopedEnum.__members__ = {} + # __members__ returns a copy + foo = m.UnscopedEnum.__members__ + foo["bar"] = "baz" + assert m.UnscopedEnum.__members__ == \ + {"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo} + + assert m.UnscopedEnum.__doc__ == \ + '''An unscoped enumeration + +Members: + + EOne : Docstring for EOne + + ETwo : Docstring for ETwo''' or m.UnscopedEnum.__doc__ == \ + '''An unscoped enumeration + +Members: + + ETwo : Docstring for ETwo + + EOne : Docstring for EOne''' + + # Unscoped enums will accept ==/!= int comparisons + y = m.UnscopedEnum.ETwo + assert y == 2 + assert 2 == y + assert y != 3 + assert 3 != y + + assert int(m.UnscopedEnum.ETwo) == 2 + assert str(m.UnscopedEnum(2)) == "UnscopedEnum.ETwo" + + # order + assert m.UnscopedEnum.EOne < m.UnscopedEnum.ETwo + assert m.UnscopedEnum.EOne < 2 + assert m.UnscopedEnum.ETwo > m.UnscopedEnum.EOne + assert m.UnscopedEnum.ETwo > 1 + assert m.UnscopedEnum.ETwo <= 2 + assert m.UnscopedEnum.ETwo >= 2 + assert m.UnscopedEnum.EOne <= m.UnscopedEnum.ETwo + assert m.UnscopedEnum.EOne <= 2 + assert m.UnscopedEnum.ETwo >= m.UnscopedEnum.EOne + assert m.UnscopedEnum.ETwo >= 1 + assert not (m.UnscopedEnum.ETwo < m.UnscopedEnum.EOne) + assert not (2 < m.UnscopedEnum.EOne) + + +def test_scoped_enum(): + assert m.test_scoped_enum(m.ScopedEnum.Three) == "ScopedEnum::Three" + z = m.ScopedEnum.Two + assert m.test_scoped_enum(z) == "ScopedEnum::Two" + + # Scoped enums will *NOT* accept ==/!= int comparisons (Will always return False) + assert not z == 3 + assert not 3 == z + assert z != 3 + assert 3 != z + # Scoped enums will *NOT* accept >, <, >= and <= int comparisons (Will throw exceptions) + with pytest.raises(TypeError): + z > 3 + with pytest.raises(TypeError): + z < 3 + with pytest.raises(TypeError): + z >= 3 + with pytest.raises(TypeError): + z <= 3 + + # order + assert m.ScopedEnum.Two < m.ScopedEnum.Three + assert m.ScopedEnum.Three > m.ScopedEnum.Two + assert m.ScopedEnum.Two <= m.ScopedEnum.Three + assert m.ScopedEnum.Two <= m.ScopedEnum.Two + assert m.ScopedEnum.Two >= m.ScopedEnum.Two + assert m.ScopedEnum.Three >= m.ScopedEnum.Two + + +def test_implicit_conversion(): + assert str(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode" + assert str(m.ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode" + + f = m.ClassWithUnscopedEnum.test_function + first = m.ClassWithUnscopedEnum.EFirstMode + second = m.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(): + assert int(m.Flags.Read) == 4 + assert int(m.Flags.Write) == 2 + assert int(m.Flags.Execute) == 1 + assert int(m.Flags.Read | m.Flags.Write | m.Flags.Execute) == 7 + assert int(m.Flags.Read | m.Flags.Write) == 6 + assert int(m.Flags.Read | m.Flags.Execute) == 5 + assert int(m.Flags.Write | m.Flags.Execute) == 3 + assert int(m.Flags.Write | 1) == 3 + + state = m.Flags.Read | m.Flags.Write + assert (state & m.Flags.Read) != 0 + assert (state & m.Flags.Write) != 0 + assert (state & m.Flags.Execute) == 0 + assert (state & 1) == 0 + + state2 = ~state + assert state2 == -7 + assert int(state ^ state2) == -1 + + +def test_enum_to_int(): + m.test_enum_to_int(m.Flags.Read) + m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode) + m.test_enum_to_uint(m.Flags.Read) + m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode) + m.test_enum_to_long_long(m.Flags.Read) + m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode) + + +def test_duplicate_enum_name(): + with pytest.raises(ValueError) as excinfo: + m.register_bad_enum() + assert str(excinfo.value) == 'SimpleEnum: element "ONE" already exists!' diff --git a/pybind11/tests/test_eval.cpp b/pybind11/tests/test_eval.cpp new file mode 100644 index 0000000..e094821 --- /dev/null +++ b/pybind11/tests/test_eval.cpp @@ -0,0 +1,91 @@ +/* + 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_SUBMODULE(eval_, m) { + // test_evals + + 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; + }); + + // Regular string literal + py::exec( + "message = 'Hello World!'\n" + "x = call_test()", + global, local + ); + + // Multi-line raw string literal + py::exec(R"( + if x == 42: + print(message) + else: + raise RuntimeError + )", global, local + ); + auto x = local["x"].cast(); + + return 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.is_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.is_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/pybind11/tests/test_eval.py b/pybind11/tests/test_eval.py new file mode 100644 index 0000000..bda4ef6 --- /dev/null +++ b/pybind11/tests/test_eval.py @@ -0,0 +1,17 @@ +import os +from pybind11_tests import eval_ as m + + +def test_evals(capture): + with capture: + assert m.test_eval_statements() + assert capture == "Hello World!" + + assert m.test_eval() + assert m.test_eval_single_statement() + + filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py") + assert m.test_eval_file(filename) + + assert m.test_eval_failure() + assert m.test_eval_file_failure() diff --git a/pybind11/tests/test_eval_call.py b/pybind11/tests/test_eval_call.py new file mode 100644 index 0000000..53c7e72 --- /dev/null +++ b/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/pybind11/tests/test_exceptions.cpp b/pybind11/tests/test_exceptions.cpp new file mode 100644 index 0000000..cf20214 --- /dev/null +++ b/pybind11/tests/test_exceptions.cpp @@ -0,0 +1,168 @@ +/* + 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 exception 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; +}; + +struct PythonCallInDestructor { + PythonCallInDestructor(const py::dict &d) : d(d) {} + ~PythonCallInDestructor() { d["good"] = true; } + + py::dict d; +}; + +TEST_SUBMODULE(exceptions, m) { + m.def("throw_std_exception", []() { + throw std::runtime_error("This exception was intentionally thrown."); + }); + + // 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", []() { throw MyException("this error should go to a custom type"); }); + m.def("throws2", []() { throw MyException2("this error should go to a standard Python exception"); }); + m.def("throws3", []() { throw MyException3("this error cannot be translated"); }); + m.def("throws4", []() { throw MyException4("this error is rethrown"); }); + m.def("throws5", []() { throw MyException5("this is a helper-defined translated exception"); }); + m.def("throws5_1", []() { throw MyException5_1("MyException5 subclass"); }); + m.def("throws_logic_error", []() { throw std::logic_error("this error should fall through to the standard handler"); }); + m.def("exception_matches", []() { + py::dict foo; + try { foo["bar"]; } + catch (py::error_already_set& ex) { + if (!ex.matches(PyExc_KeyError)) throw; + } + }); + + 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; + }); + + // test_nested_throws + m.def("try_catch", [m](py::object exc_type, py::function f, py::args args) { + try { f(*args); } + catch (py::error_already_set &ex) { + if (ex.matches(exc_type)) + py::print(ex.what()); + else + throw; + } + }); + +} diff --git a/pybind11/tests/test_exceptions.py b/pybind11/tests/test_exceptions.py new file mode 100644 index 0000000..8d37c09 --- /dev/null +++ b/pybind11/tests/test_exceptions.py @@ -0,0 +1,144 @@ +import pytest + +from pybind11_tests import exceptions as m +import pybind11_cross_module_tests as cm + + +def test_std_exception(msg): + with pytest.raises(RuntimeError) as excinfo: + m.throw_std_exception() + assert msg(excinfo.value) == "This exception was intentionally thrown." + + +def test_error_already_set(msg): + with pytest.raises(RuntimeError) as excinfo: + m.throw_already_set(False) + assert msg(excinfo.value) == "Unknown internal error occurred" + + with pytest.raises(ValueError) as excinfo: + m.throw_already_set(True) + assert msg(excinfo.value) == "foo" + + +def test_cross_module_exceptions(): + with pytest.raises(RuntimeError) as excinfo: + cm.raise_runtime_error() + assert str(excinfo.value) == "My runtime error" + + with pytest.raises(ValueError) as excinfo: + cm.raise_value_error() + assert str(excinfo.value) == "My value error" + + with pytest.raises(ValueError) as excinfo: + cm.throw_pybind_value_error() + assert str(excinfo.value) == "pybind11 value error" + + with pytest.raises(TypeError) as excinfo: + cm.throw_pybind_type_error() + assert str(excinfo.value) == "pybind11 type error" + + with pytest.raises(StopIteration) as excinfo: + cm.throw_stop_iteration() + + +def test_python_call_in_catch(): + d = {} + assert m.python_call_in_destructor(d) is True + assert d["good"] is True + + +def test_exception_matches(): + m.exception_matches() + + +def test_custom(msg): + # Can we catch a MyException? + with pytest.raises(m.MyException) as excinfo: + m.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: + m.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: + m.throws3() + assert msg(excinfo.value) == "Caught an unknown exception!" + + # Can we delegate to another handler by rethrowing? + with pytest.raises(m.MyException) as excinfo: + m.throws4() + assert msg(excinfo.value) == "this error is rethrown" + + # Can we fall-through to the default handler? + with pytest.raises(RuntimeError) as excinfo: + m.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(m.MyException5) as excinfo: + m.throws5() + assert msg(excinfo.value) == "this is a helper-defined translated exception" + + # Exception subclassing: + with pytest.raises(m.MyException5) as excinfo: + m.throws5_1() + assert msg(excinfo.value) == "MyException5 subclass" + assert isinstance(excinfo.value, m.MyException5_1) + + with pytest.raises(m.MyException5_1) as excinfo: + m.throws5_1() + assert msg(excinfo.value) == "MyException5 subclass" + + with pytest.raises(m.MyException5) as excinfo: + try: + m.throws5() + except m.MyException5_1: + raise RuntimeError("Exception error: caught child from parent") + assert msg(excinfo.value) == "this is a helper-defined translated exception" + + +def test_nested_throws(capture): + """Tests nested (e.g. C++ -> Python -> C++) exception handling""" + + def throw_myex(): + raise m.MyException("nested error") + + def throw_myex5(): + raise m.MyException5("nested error 5") + + # In the comments below, the exception is caught in the first step, thrown in the last step + + # C++ -> Python + with capture: + m.try_catch(m.MyException5, throw_myex5) + assert str(capture).startswith("MyException5: nested error 5") + + # Python -> C++ -> Python + with pytest.raises(m.MyException) as excinfo: + m.try_catch(m.MyException5, throw_myex) + assert str(excinfo.value) == "nested error" + + def pycatch(exctype, f, *args): + try: + f(*args) + except m.MyException as e: + print(e) + + # C++ -> Python -> C++ -> Python + with capture: + m.try_catch( + m.MyException5, pycatch, m.MyException, m.try_catch, m.MyException, throw_myex5) + assert str(capture).startswith("MyException5: nested error 5") + + # C++ -> Python -> C++ + with capture: + m.try_catch(m.MyException, pycatch, m.MyException5, m.throws4) + assert capture == "this error is rethrown" + + # Python -> C++ -> Python -> C++ + with pytest.raises(m.MyException5) as excinfo: + m.try_catch(m.MyException, pycatch, m.MyException, m.throws5) + assert str(excinfo.value) == "this is a helper-defined translated exception" diff --git a/pybind11/tests/test_factory_constructors.cpp b/pybind11/tests/test_factory_constructors.cpp new file mode 100644 index 0000000..5cfbfdc --- /dev/null +++ b/pybind11/tests/test_factory_constructors.cpp @@ -0,0 +1,338 @@ +/* + tests/test_factory_constructors.cpp -- tests construction from a factory function + via py::init_factory() + + Copyright (c) 2017 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" +#include "constructor_stats.h" +#include + +// Classes for testing python construction via C++ factory function: +// Not publicly constructible, copyable, or movable: +class TestFactory1 { + friend class TestFactoryHelper; + TestFactory1() : value("(empty)") { print_default_created(this); } + TestFactory1(int v) : value(std::to_string(v)) { print_created(this, value); } + TestFactory1(std::string v) : value(std::move(v)) { print_created(this, value); } + TestFactory1(TestFactory1 &&) = delete; + TestFactory1(const TestFactory1 &) = delete; + TestFactory1 &operator=(TestFactory1 &&) = delete; + TestFactory1 &operator=(const TestFactory1 &) = delete; +public: + std::string value; + ~TestFactory1() { print_destroyed(this); } +}; +// Non-public construction, but moveable: +class TestFactory2 { + friend class TestFactoryHelper; + TestFactory2() : value("(empty2)") { print_default_created(this); } + TestFactory2(int v) : value(std::to_string(v)) { print_created(this, value); } + TestFactory2(std::string v) : value(std::move(v)) { print_created(this, value); } +public: + TestFactory2(TestFactory2 &&m) { value = std::move(m.value); print_move_created(this); } + TestFactory2 &operator=(TestFactory2 &&m) { value = std::move(m.value); print_move_assigned(this); return *this; } + std::string value; + ~TestFactory2() { print_destroyed(this); } +}; +// Mixed direct/factory construction: +class TestFactory3 { +protected: + friend class TestFactoryHelper; + TestFactory3() : value("(empty3)") { print_default_created(this); } + TestFactory3(int v) : value(std::to_string(v)) { print_created(this, value); } +public: + TestFactory3(std::string v) : value(std::move(v)) { print_created(this, value); } + TestFactory3(TestFactory3 &&m) { value = std::move(m.value); print_move_created(this); } + TestFactory3 &operator=(TestFactory3 &&m) { value = std::move(m.value); print_move_assigned(this); return *this; } + std::string value; + virtual ~TestFactory3() { print_destroyed(this); } +}; +// Inheritance test +class TestFactory4 : public TestFactory3 { +public: + TestFactory4() : TestFactory3() { print_default_created(this); } + TestFactory4(int v) : TestFactory3(v) { print_created(this, v); } + virtual ~TestFactory4() { print_destroyed(this); } +}; +// Another class for an invalid downcast test +class TestFactory5 : public TestFactory3 { +public: + TestFactory5(int i) : TestFactory3(i) { print_created(this, i); } + virtual ~TestFactory5() { print_destroyed(this); } +}; + +class TestFactory6 { +protected: + int value; + bool alias = false; +public: + TestFactory6(int i) : value{i} { print_created(this, i); } + TestFactory6(TestFactory6 &&f) { print_move_created(this); value = f.value; alias = f.alias; } + TestFactory6(const TestFactory6 &f) { print_copy_created(this); value = f.value; alias = f.alias; } + virtual ~TestFactory6() { print_destroyed(this); } + virtual int get() { return value; } + bool has_alias() { return alias; } +}; +class PyTF6 : public TestFactory6 { +public: + // Special constructor that allows the factory to construct a PyTF6 from a TestFactory6 only + // when an alias is needed: + PyTF6(TestFactory6 &&base) : TestFactory6(std::move(base)) { alias = true; print_created(this, "move", value); } + PyTF6(int i) : TestFactory6(i) { alias = true; print_created(this, i); } + PyTF6(PyTF6 &&f) : TestFactory6(std::move(f)) { print_move_created(this); } + PyTF6(const PyTF6 &f) : TestFactory6(f) { print_copy_created(this); } + PyTF6(std::string s) : TestFactory6((int) s.size()) { alias = true; print_created(this, s); } + virtual ~PyTF6() { print_destroyed(this); } + int get() override { PYBIND11_OVERLOAD(int, TestFactory6, get, /*no args*/); } +}; + +class TestFactory7 { +protected: + int value; + bool alias = false; +public: + TestFactory7(int i) : value{i} { print_created(this, i); } + TestFactory7(TestFactory7 &&f) { print_move_created(this); value = f.value; alias = f.alias; } + TestFactory7(const TestFactory7 &f) { print_copy_created(this); value = f.value; alias = f.alias; } + virtual ~TestFactory7() { print_destroyed(this); } + virtual int get() { return value; } + bool has_alias() { return alias; } +}; +class PyTF7 : public TestFactory7 { +public: + PyTF7(int i) : TestFactory7(i) { alias = true; print_created(this, i); } + PyTF7(PyTF7 &&f) : TestFactory7(std::move(f)) { print_move_created(this); } + PyTF7(const PyTF7 &f) : TestFactory7(f) { print_copy_created(this); } + virtual ~PyTF7() { print_destroyed(this); } + int get() override { PYBIND11_OVERLOAD(int, TestFactory7, get, /*no args*/); } +}; + + +class TestFactoryHelper { +public: + // Non-movable, non-copyable type: + // Return via pointer: + static TestFactory1 *construct1() { return new TestFactory1(); } + // Holder: + static std::unique_ptr construct1(int a) { return std::unique_ptr(new TestFactory1(a)); } + // pointer again + static TestFactory1 *construct1_string(std::string a) { return new TestFactory1(a); } + + // Moveable type: + // pointer: + static TestFactory2 *construct2() { return new TestFactory2(); } + // holder: + static std::unique_ptr construct2(int a) { return std::unique_ptr(new TestFactory2(a)); } + // by value moving: + static TestFactory2 construct2(std::string a) { return TestFactory2(a); } + + // shared_ptr holder type: + // pointer: + static TestFactory3 *construct3() { return new TestFactory3(); } + // holder: + static std::shared_ptr construct3(int a) { return std::shared_ptr(new TestFactory3(a)); } +}; + +TEST_SUBMODULE(factory_constructors, m) { + + // Define various trivial types to allow simpler overload resolution: + py::module m_tag = m.def_submodule("tag"); +#define MAKE_TAG_TYPE(Name) \ + struct Name##_tag {}; \ + py::class_(m_tag, #Name "_tag").def(py::init<>()); \ + m_tag.attr(#Name) = py::cast(Name##_tag{}) + MAKE_TAG_TYPE(pointer); + MAKE_TAG_TYPE(unique_ptr); + MAKE_TAG_TYPE(move); + MAKE_TAG_TYPE(shared_ptr); + MAKE_TAG_TYPE(derived); + MAKE_TAG_TYPE(TF4); + MAKE_TAG_TYPE(TF5); + MAKE_TAG_TYPE(null_ptr); + MAKE_TAG_TYPE(base); + MAKE_TAG_TYPE(invalid_base); + MAKE_TAG_TYPE(alias); + MAKE_TAG_TYPE(unaliasable); + MAKE_TAG_TYPE(mixed); + + // test_init_factory_basic, test_bad_type + py::class_(m, "TestFactory1") + .def(py::init([](unique_ptr_tag, int v) { return TestFactoryHelper::construct1(v); })) + .def(py::init(&TestFactoryHelper::construct1_string)) // raw function pointer + .def(py::init([](pointer_tag) { return TestFactoryHelper::construct1(); })) + .def(py::init([](py::handle, int v, py::handle) { return TestFactoryHelper::construct1(v); })) + .def_readwrite("value", &TestFactory1::value) + ; + py::class_(m, "TestFactory2") + .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); })) + .def(py::init([](unique_ptr_tag, std::string v) { return TestFactoryHelper::construct2(v); })) + .def(py::init([](move_tag) { return TestFactoryHelper::construct2(); })) + .def_readwrite("value", &TestFactory2::value) + ; + + // Stateful & reused: + int c = 1; + auto c4a = [c](pointer_tag, TF4_tag, int a) { (void) c; return new TestFactory4(a);}; + + // test_init_factory_basic, test_init_factory_casting + py::class_>(m, "TestFactory3") + .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct3(v); })) + .def(py::init([](shared_ptr_tag) { return TestFactoryHelper::construct3(); })) + .def("__init__", [](TestFactory3 &self, std::string v) { new (&self) TestFactory3(v); }) // placement-new ctor + + // factories returning a derived type: + .def(py::init(c4a)) // derived ptr + .def(py::init([](pointer_tag, TF5_tag, int a) { return new TestFactory5(a); })) + // derived shared ptr: + .def(py::init([](shared_ptr_tag, TF4_tag, int a) { return std::make_shared(a); })) + .def(py::init([](shared_ptr_tag, TF5_tag, int a) { return std::make_shared(a); })) + + // Returns nullptr: + .def(py::init([](null_ptr_tag) { return (TestFactory3 *) nullptr; })) + + .def_readwrite("value", &TestFactory3::value) + ; + + // test_init_factory_casting + py::class_>(m, "TestFactory4") + .def(py::init(c4a)) // pointer + ; + + // Doesn't need to be registered, but registering makes getting ConstructorStats easier: + py::class_>(m, "TestFactory5"); + + // test_init_factory_alias + // Alias testing + py::class_(m, "TestFactory6") + .def(py::init([](base_tag, int i) { return TestFactory6(i); })) + .def(py::init([](alias_tag, int i) { return PyTF6(i); })) + .def(py::init([](alias_tag, std::string s) { return PyTF6(s); })) + .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF6(i); })) + .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory6(i); })) + .def(py::init([](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); })) + + .def("get", &TestFactory6::get) + .def("has_alias", &TestFactory6::has_alias) + + .def_static("get_cstats", &ConstructorStats::get, py::return_value_policy::reference) + .def_static("get_alias_cstats", &ConstructorStats::get, py::return_value_policy::reference) + ; + + // test_init_factory_dual + // Separate alias constructor testing + py::class_>(m, "TestFactory7") + .def(py::init( + [](int i) { return TestFactory7(i); }, + [](int i) { return PyTF7(i); })) + .def(py::init( + [](pointer_tag, int i) { return new TestFactory7(i); }, + [](pointer_tag, int i) { return new PyTF7(i); })) + .def(py::init( + [](mixed_tag, int i) { return new TestFactory7(i); }, + [](mixed_tag, int i) { return PyTF7(i); })) + .def(py::init( + [](mixed_tag, std::string s) { return TestFactory7((int) s.size()); }, + [](mixed_tag, std::string s) { return new PyTF7((int) s.size()); })) + .def(py::init( + [](base_tag, pointer_tag, int i) { return new TestFactory7(i); }, + [](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); })) + .def(py::init( + [](alias_tag, pointer_tag, int i) { return new PyTF7(i); }, + [](alias_tag, pointer_tag, int i) { return new PyTF7(10*i); })) + .def(py::init( + [](shared_ptr_tag, base_tag, int i) { return std::make_shared(i); }, + [](shared_ptr_tag, base_tag, int i) { auto *p = new PyTF7(i); return std::shared_ptr(p); })) + .def(py::init( + [](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared(i); }, + [](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared(i); })) // <-- invalid alias factory + + .def("get", &TestFactory7::get) + .def("has_alias", &TestFactory7::has_alias) + + .def_static("get_cstats", &ConstructorStats::get, py::return_value_policy::reference) + .def_static("get_alias_cstats", &ConstructorStats::get, py::return_value_policy::reference) + ; + + // test_placement_new_alternative + // Class with a custom new operator but *without* a placement new operator (issue #948) + class NoPlacementNew { + public: + NoPlacementNew(int i) : i(i) { } + static void *operator new(std::size_t s) { + auto *p = ::operator new(s); + py::print("operator new called, returning", reinterpret_cast(p)); + return p; + } + static void operator delete(void *p) { + py::print("operator delete called on", reinterpret_cast(p)); + ::operator delete(p); + } + int i; + }; + // As of 2.2, `py::init` no longer requires placement new + py::class_(m, "NoPlacementNew") + .def(py::init()) + .def(py::init([]() { return new NoPlacementNew(100); })) + .def_readwrite("i", &NoPlacementNew::i) + ; + + + // test_reallocations + // Class that has verbose operator_new/operator_delete calls + struct NoisyAlloc { + NoisyAlloc(const NoisyAlloc &) = default; + NoisyAlloc(int i) { py::print(py::str("NoisyAlloc(int {})").format(i)); } + NoisyAlloc(double d) { py::print(py::str("NoisyAlloc(double {})").format(d)); } + ~NoisyAlloc() { py::print("~NoisyAlloc()"); } + + static void *operator new(size_t s) { py::print("noisy new"); return ::operator new(s); } + static void *operator new(size_t, void *p) { py::print("noisy placement new"); return p; } + static void operator delete(void *p, size_t) { py::print("noisy delete"); ::operator delete(p); } + static void operator delete(void *, void *) { py::print("noisy placement delete"); } +#if defined(_MSC_VER) && _MSC_VER < 1910 + // MSVC 2015 bug: the above "noisy delete" isn't invoked (fixed in MSVC 2017) + static void operator delete(void *p) { py::print("noisy delete"); ::operator delete(p); } +#endif + }; + py::class_(m, "NoisyAlloc") + // Since these overloads have the same number of arguments, the dispatcher will try each of + // them until the arguments convert. Thus we can get a pre-allocation here when passing a + // single non-integer: + .def("__init__", [](NoisyAlloc *a, int i) { new (a) NoisyAlloc(i); }) // Regular constructor, runs first, requires preallocation + .def(py::init([](double d) { return new NoisyAlloc(d); })) + + // The two-argument version: first the factory pointer overload. + .def(py::init([](int i, int) { return new NoisyAlloc(i); })) + // Return-by-value: + .def(py::init([](double d, int) { return NoisyAlloc(d); })) + // Old-style placement new init; requires preallocation + .def("__init__", [](NoisyAlloc &a, double d, double) { new (&a) NoisyAlloc(d); }) + // Requires deallocation of previous overload preallocated value: + .def(py::init([](int i, double) { return new NoisyAlloc(i); })) + // Regular again: requires yet another preallocation + .def("__init__", [](NoisyAlloc &a, int i, std::string) { new (&a) NoisyAlloc(i); }) + ; + + + + + // static_assert testing (the following def's should all fail with appropriate compilation errors): +#if 0 + struct BadF1Base {}; + struct BadF1 : BadF1Base {}; + struct PyBadF1 : BadF1 {}; + py::class_> bf1(m, "BadF1"); + // wrapped factory function must return a compatible pointer, holder, or value + bf1.def(py::init([]() { return 3; })); + // incompatible factory function pointer return type + bf1.def(py::init([]() { static int three = 3; return &three; })); + // incompatible factory function std::shared_ptr return type: cannot convert shared_ptr to holder + // (non-polymorphic base) + bf1.def(py::init([]() { return std::shared_ptr(new BadF1()); })); +#endif +} diff --git a/pybind11/tests/test_factory_constructors.py b/pybind11/tests/test_factory_constructors.py new file mode 100644 index 0000000..78a3910 --- /dev/null +++ b/pybind11/tests/test_factory_constructors.py @@ -0,0 +1,459 @@ +import pytest +import re + +from pybind11_tests import factory_constructors as m +from pybind11_tests.factory_constructors import tag +from pybind11_tests import ConstructorStats + + +def test_init_factory_basic(): + """Tests py::init_factory() wrapper around various ways of returning the object""" + + cstats = [ConstructorStats.get(c) for c in [m.TestFactory1, m.TestFactory2, m.TestFactory3]] + cstats[0].alive() # force gc + n_inst = ConstructorStats.detail_reg_inst() + + x1 = m.TestFactory1(tag.unique_ptr, 3) + assert x1.value == "3" + y1 = m.TestFactory1(tag.pointer) + assert y1.value == "(empty)" + z1 = m.TestFactory1("hi!") + assert z1.value == "hi!" + + assert ConstructorStats.detail_reg_inst() == n_inst + 3 + + x2 = m.TestFactory2(tag.move) + assert x2.value == "(empty2)" + y2 = m.TestFactory2(tag.pointer, 7) + assert y2.value == "7" + z2 = m.TestFactory2(tag.unique_ptr, "hi again") + assert z2.value == "hi again" + + assert ConstructorStats.detail_reg_inst() == n_inst + 6 + + x3 = m.TestFactory3(tag.shared_ptr) + assert x3.value == "(empty3)" + y3 = m.TestFactory3(tag.pointer, 42) + assert y3.value == "42" + z3 = m.TestFactory3("bye") + assert z3.value == "bye" + + with pytest.raises(TypeError) as excinfo: + m.TestFactory3(tag.null_ptr) + assert str(excinfo.value) == "pybind11::init(): factory function returned nullptr" + + assert [i.alive() for i in cstats] == [3, 3, 3] + assert ConstructorStats.detail_reg_inst() == n_inst + 9 + + del x1, y2, y3, z3 + assert [i.alive() for i in cstats] == [2, 2, 1] + assert ConstructorStats.detail_reg_inst() == n_inst + 5 + del x2, x3, y1, z1, z2 + assert [i.alive() for i in cstats] == [0, 0, 0] + assert ConstructorStats.detail_reg_inst() == n_inst + + assert [i.values() for i in cstats] == [ + ["3", "hi!"], + ["7", "hi again"], + ["42", "bye"] + ] + assert [i.default_constructions for i in cstats] == [1, 1, 1] + + +def test_init_factory_signature(msg): + with pytest.raises(TypeError) as excinfo: + m.TestFactory1("invalid", "constructor", "arguments") + assert msg(excinfo.value) == """ + __init__(): incompatible constructor arguments. The following argument types are supported: + 1. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int) + 2. m.factory_constructors.TestFactory1(arg0: str) + 3. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.pointer_tag) + 4. m.factory_constructors.TestFactory1(arg0: handle, arg1: int, arg2: handle) + + Invoked with: 'invalid', 'constructor', 'arguments' + """ # noqa: E501 line too long + + assert msg(m.TestFactory1.__init__.__doc__) == """ + __init__(*args, **kwargs) + Overloaded function. + + 1. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int) -> None + + 2. __init__(self: m.factory_constructors.TestFactory1, arg0: str) -> None + + 3. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.pointer_tag) -> None + + 4. __init__(self: m.factory_constructors.TestFactory1, arg0: handle, arg1: int, arg2: handle) -> None + """ # noqa: E501 line too long + + +def test_init_factory_casting(): + """Tests py::init_factory() wrapper with various upcasting and downcasting returns""" + + cstats = [ConstructorStats.get(c) for c in [m.TestFactory3, m.TestFactory4, m.TestFactory5]] + cstats[0].alive() # force gc + n_inst = ConstructorStats.detail_reg_inst() + + # Construction from derived references: + a = m.TestFactory3(tag.pointer, tag.TF4, 4) + assert a.value == "4" + b = m.TestFactory3(tag.shared_ptr, tag.TF4, 5) + assert b.value == "5" + c = m.TestFactory3(tag.pointer, tag.TF5, 6) + assert c.value == "6" + d = m.TestFactory3(tag.shared_ptr, tag.TF5, 7) + assert d.value == "7" + + assert ConstructorStats.detail_reg_inst() == n_inst + 4 + + # Shared a lambda with TF3: + e = m.TestFactory4(tag.pointer, tag.TF4, 8) + assert e.value == "8" + + assert ConstructorStats.detail_reg_inst() == n_inst + 5 + assert [i.alive() for i in cstats] == [5, 3, 2] + + del a + assert [i.alive() for i in cstats] == [4, 2, 2] + assert ConstructorStats.detail_reg_inst() == n_inst + 4 + + del b, c, e + assert [i.alive() for i in cstats] == [1, 0, 1] + assert ConstructorStats.detail_reg_inst() == n_inst + 1 + + del d + assert [i.alive() for i in cstats] == [0, 0, 0] + assert ConstructorStats.detail_reg_inst() == n_inst + + assert [i.values() for i in cstats] == [ + ["4", "5", "6", "7", "8"], + ["4", "5", "8"], + ["6", "7"] + ] + + +def test_init_factory_alias(): + """Tests py::init_factory() wrapper with value conversions and alias types""" + + cstats = [m.TestFactory6.get_cstats(), m.TestFactory6.get_alias_cstats()] + cstats[0].alive() # force gc + n_inst = ConstructorStats.detail_reg_inst() + + a = m.TestFactory6(tag.base, 1) + assert a.get() == 1 + assert not a.has_alias() + b = m.TestFactory6(tag.alias, "hi there") + assert b.get() == 8 + assert b.has_alias() + c = m.TestFactory6(tag.alias, 3) + assert c.get() == 3 + assert c.has_alias() + d = m.TestFactory6(tag.alias, tag.pointer, 4) + assert d.get() == 4 + assert d.has_alias() + e = m.TestFactory6(tag.base, tag.pointer, 5) + assert e.get() == 5 + assert not e.has_alias() + f = m.TestFactory6(tag.base, tag.alias, tag.pointer, 6) + assert f.get() == 6 + assert f.has_alias() + + assert ConstructorStats.detail_reg_inst() == n_inst + 6 + assert [i.alive() for i in cstats] == [6, 4] + + del a, b, e + assert [i.alive() for i in cstats] == [3, 3] + assert ConstructorStats.detail_reg_inst() == n_inst + 3 + del f, c, d + assert [i.alive() for i in cstats] == [0, 0] + assert ConstructorStats.detail_reg_inst() == n_inst + + class MyTest(m.TestFactory6): + def __init__(self, *args): + m.TestFactory6.__init__(self, *args) + + def get(self): + return -5 + m.TestFactory6.get(self) + + # Return Class by value, moved into new alias: + z = MyTest(tag.base, 123) + assert z.get() == 118 + assert z.has_alias() + + # Return alias by value, moved into new alias: + y = MyTest(tag.alias, "why hello!") + assert y.get() == 5 + assert y.has_alias() + + # Return Class by pointer, moved into new alias then original destroyed: + x = MyTest(tag.base, tag.pointer, 47) + assert x.get() == 42 + assert x.has_alias() + + assert ConstructorStats.detail_reg_inst() == n_inst + 3 + assert [i.alive() for i in cstats] == [3, 3] + del x, y, z + assert [i.alive() for i in cstats] == [0, 0] + assert ConstructorStats.detail_reg_inst() == n_inst + + assert [i.values() for i in cstats] == [ + ["1", "8", "3", "4", "5", "6", "123", "10", "47"], + ["hi there", "3", "4", "6", "move", "123", "why hello!", "move", "47"] + ] + + +def test_init_factory_dual(): + """Tests init factory functions with dual main/alias factory functions""" + from pybind11_tests.factory_constructors import TestFactory7 + + cstats = [TestFactory7.get_cstats(), TestFactory7.get_alias_cstats()] + cstats[0].alive() # force gc + n_inst = ConstructorStats.detail_reg_inst() + + class PythFactory7(TestFactory7): + def get(self): + return 100 + TestFactory7.get(self) + + a1 = TestFactory7(1) + a2 = PythFactory7(2) + assert a1.get() == 1 + assert a2.get() == 102 + assert not a1.has_alias() + assert a2.has_alias() + + b1 = TestFactory7(tag.pointer, 3) + b2 = PythFactory7(tag.pointer, 4) + assert b1.get() == 3 + assert b2.get() == 104 + assert not b1.has_alias() + assert b2.has_alias() + + c1 = TestFactory7(tag.mixed, 5) + c2 = PythFactory7(tag.mixed, 6) + assert c1.get() == 5 + assert c2.get() == 106 + assert not c1.has_alias() + assert c2.has_alias() + + d1 = TestFactory7(tag.base, tag.pointer, 7) + d2 = PythFactory7(tag.base, tag.pointer, 8) + assert d1.get() == 7 + assert d2.get() == 108 + assert not d1.has_alias() + assert d2.has_alias() + + # Both return an alias; the second multiplies the value by 10: + e1 = TestFactory7(tag.alias, tag.pointer, 9) + e2 = PythFactory7(tag.alias, tag.pointer, 10) + assert e1.get() == 9 + assert e2.get() == 200 + assert e1.has_alias() + assert e2.has_alias() + + f1 = TestFactory7(tag.shared_ptr, tag.base, 11) + f2 = PythFactory7(tag.shared_ptr, tag.base, 12) + assert f1.get() == 11 + assert f2.get() == 112 + assert not f1.has_alias() + assert f2.has_alias() + + g1 = TestFactory7(tag.shared_ptr, tag.invalid_base, 13) + assert g1.get() == 13 + assert not g1.has_alias() + with pytest.raises(TypeError) as excinfo: + PythFactory7(tag.shared_ptr, tag.invalid_base, 14) + assert (str(excinfo.value) == + "pybind11::init(): construction failed: returned holder-wrapped instance is not an " + "alias instance") + + assert [i.alive() for i in cstats] == [13, 7] + assert ConstructorStats.detail_reg_inst() == n_inst + 13 + + del a1, a2, b1, d1, e1, e2 + assert [i.alive() for i in cstats] == [7, 4] + assert ConstructorStats.detail_reg_inst() == n_inst + 7 + del b2, c1, c2, d2, f1, f2, g1 + assert [i.alive() for i in cstats] == [0, 0] + assert ConstructorStats.detail_reg_inst() == n_inst + + assert [i.values() for i in cstats] == [ + ["1", "2", "3", "4", "5", "6", "7", "8", "9", "100", "11", "12", "13", "14"], + ["2", "4", "6", "8", "9", "100", "12"] + ] + + +def test_no_placement_new(capture): + """Prior to 2.2, `py::init<...>` relied on the type supporting placement + new; this tests a class without placement new support.""" + with capture: + a = m.NoPlacementNew(123) + + found = re.search(r'^operator new called, returning (\d+)\n$', str(capture)) + assert found + assert a.i == 123 + with capture: + del a + pytest.gc_collect() + assert capture == "operator delete called on " + found.group(1) + + with capture: + b = m.NoPlacementNew() + + found = re.search(r'^operator new called, returning (\d+)\n$', str(capture)) + assert found + assert b.i == 100 + with capture: + del b + pytest.gc_collect() + assert capture == "operator delete called on " + found.group(1) + + +def test_multiple_inheritance(): + class MITest(m.TestFactory1, m.TestFactory2): + def __init__(self): + m.TestFactory1.__init__(self, tag.unique_ptr, 33) + m.TestFactory2.__init__(self, tag.move) + + a = MITest() + assert m.TestFactory1.value.fget(a) == "33" + assert m.TestFactory2.value.fget(a) == "(empty2)" + + +def create_and_destroy(*args): + a = m.NoisyAlloc(*args) + print("---") + del a + pytest.gc_collect() + + +def strip_comments(s): + return re.sub(r'\s+#.*', '', s) + + +def test_reallocations(capture, msg): + """When the constructor is overloaded, previous overloads can require a preallocated value. + This test makes sure that such preallocated values only happen when they might be necessary, + and that they are deallocated properly""" + + pytest.gc_collect() + + with capture: + create_and_destroy(1) + assert msg(capture) == """ + noisy new + noisy placement new + NoisyAlloc(int 1) + --- + ~NoisyAlloc() + noisy delete + """ + with capture: + create_and_destroy(1.5) + assert msg(capture) == strip_comments(""" + noisy new # allocation required to attempt first overload + noisy delete # have to dealloc before considering factory init overload + noisy new # pointer factory calling "new", part 1: allocation + NoisyAlloc(double 1.5) # ... part two, invoking constructor + --- + ~NoisyAlloc() # Destructor + noisy delete # operator delete + """) + + with capture: + create_and_destroy(2, 3) + assert msg(capture) == strip_comments(""" + noisy new # pointer factory calling "new", allocation + NoisyAlloc(int 2) # constructor + --- + ~NoisyAlloc() # Destructor + noisy delete # operator delete + """) + + with capture: + create_and_destroy(2.5, 3) + assert msg(capture) == strip_comments(""" + NoisyAlloc(double 2.5) # construction (local func variable: operator_new not called) + noisy new # return-by-value "new" part 1: allocation + ~NoisyAlloc() # moved-away local func variable destruction + --- + ~NoisyAlloc() # Destructor + noisy delete # operator delete + """) + + with capture: + create_and_destroy(3.5, 4.5) + assert msg(capture) == strip_comments(""" + noisy new # preallocation needed before invoking placement-new overload + noisy placement new # Placement new + NoisyAlloc(double 3.5) # construction + --- + ~NoisyAlloc() # Destructor + noisy delete # operator delete + """) + + with capture: + create_and_destroy(4, 0.5) + assert msg(capture) == strip_comments(""" + noisy new # preallocation needed before invoking placement-new overload + noisy delete # deallocation of preallocated storage + noisy new # Factory pointer allocation + NoisyAlloc(int 4) # factory pointer construction + --- + ~NoisyAlloc() # Destructor + noisy delete # operator delete + """) + + with capture: + create_and_destroy(5, "hi") + assert msg(capture) == strip_comments(""" + noisy new # preallocation needed before invoking first placement new + noisy delete # delete before considering new-style constructor + noisy new # preallocation for second placement new + noisy placement new # Placement new in the second placement new overload + NoisyAlloc(int 5) # construction + --- + ~NoisyAlloc() # Destructor + noisy delete # operator delete + """) + + +@pytest.unsupported_on_py2 +def test_invalid_self(): + """Tests invocation of the pybind-registered base class with an invalid `self` argument. You + can only actually do this on Python 3: Python 2 raises an exception itself if you try.""" + class NotPybindDerived(object): + pass + + # Attempts to initialize with an invalid type passed as `self`: + class BrokenTF1(m.TestFactory1): + def __init__(self, bad): + if bad == 1: + a = m.TestFactory2(tag.pointer, 1) + m.TestFactory1.__init__(a, tag.pointer) + elif bad == 2: + a = NotPybindDerived() + m.TestFactory1.__init__(a, tag.pointer) + + # Same as above, but for a class with an alias: + class BrokenTF6(m.TestFactory6): + def __init__(self, bad): + if bad == 1: + a = m.TestFactory2(tag.pointer, 1) + m.TestFactory6.__init__(a, tag.base, 1) + elif bad == 2: + a = m.TestFactory2(tag.pointer, 1) + m.TestFactory6.__init__(a, tag.alias, 1) + elif bad == 3: + m.TestFactory6.__init__(NotPybindDerived.__new__(NotPybindDerived), tag.base, 1) + elif bad == 4: + m.TestFactory6.__init__(NotPybindDerived.__new__(NotPybindDerived), tag.alias, 1) + + for arg in (1, 2): + with pytest.raises(TypeError) as excinfo: + BrokenTF1(arg) + assert str(excinfo.value) == "__init__(self, ...) called with invalid `self` argument" + + for arg in (1, 2, 3, 4): + with pytest.raises(TypeError) as excinfo: + BrokenTF6(arg) + assert str(excinfo.value) == "__init__(self, ...) called with invalid `self` argument" diff --git a/pybind11/tests/test_gil_scoped.cpp b/pybind11/tests/test_gil_scoped.cpp new file mode 100644 index 0000000..a94b7a2 --- /dev/null +++ b/pybind11/tests/test_gil_scoped.cpp @@ -0,0 +1,43 @@ +/* + tests/test_gil_scoped.cpp -- acquire and release gil + + Copyright (c) 2017 Borja Zarco (Google LLC) + + 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 + + +class VirtClass { +public: + virtual void virtual_func() {} + virtual void pure_virtual_func() = 0; +}; + +class PyVirtClass : public VirtClass { + void virtual_func() override { + PYBIND11_OVERLOAD(void, VirtClass, virtual_func,); + } + void pure_virtual_func() override { + PYBIND11_OVERLOAD_PURE(void, VirtClass, pure_virtual_func,); + } +}; + +TEST_SUBMODULE(gil_scoped, m) { + py::class_(m, "VirtClass") + .def(py::init<>()) + .def("virtual_func", &VirtClass::virtual_func) + .def("pure_virtual_func", &VirtClass::pure_virtual_func); + + m.def("test_callback_py_obj", + [](py::object func) { func(); }); + m.def("test_callback_std_func", + [](const std::function &func) { func(); }); + m.def("test_callback_virtual_func", + [](VirtClass &virt) { virt.virtual_func(); }); + m.def("test_callback_pure_virtual_func", + [](VirtClass &virt) { virt.pure_virtual_func(); }); +} diff --git a/pybind11/tests/test_gil_scoped.py b/pybind11/tests/test_gil_scoped.py new file mode 100644 index 0000000..5e70243 --- /dev/null +++ b/pybind11/tests/test_gil_scoped.py @@ -0,0 +1,80 @@ +import multiprocessing +import threading +from pybind11_tests import gil_scoped as m + + +def _run_in_process(target, *args, **kwargs): + """Runs target in process and returns its exitcode after 1s (None if still alive).""" + process = multiprocessing.Process(target=target, args=args, kwargs=kwargs) + process.daemon = True + try: + process.start() + # Do not need to wait much, 1s should be more than enough. + process.join(timeout=1) + return process.exitcode + finally: + if process.is_alive(): + process.terminate() + + +def _python_to_cpp_to_python(): + """Calls different C++ functions that come back to Python.""" + class ExtendedVirtClass(m.VirtClass): + def virtual_func(self): + pass + + def pure_virtual_func(self): + pass + + extended = ExtendedVirtClass() + m.test_callback_py_obj(lambda: None) + m.test_callback_std_func(lambda: None) + m.test_callback_virtual_func(extended) + m.test_callback_pure_virtual_func(extended) + + +def _python_to_cpp_to_python_from_threads(num_threads, parallel=False): + """Calls different C++ functions that come back to Python, from Python threads.""" + threads = [] + for _ in range(num_threads): + thread = threading.Thread(target=_python_to_cpp_to_python) + thread.daemon = True + thread.start() + if parallel: + threads.append(thread) + else: + thread.join() + for thread in threads: + thread.join() + + +def test_python_to_cpp_to_python_from_thread(): + """Makes sure there is no GIL deadlock when running in a thread. + + It runs in a separate process to be able to stop and assert if it deadlocks. + """ + assert _run_in_process(_python_to_cpp_to_python_from_threads, 1) == 0 + + +def test_python_to_cpp_to_python_from_thread_multiple_parallel(): + """Makes sure there is no GIL deadlock when running in a thread multiple times in parallel. + + It runs in a separate process to be able to stop and assert if it deadlocks. + """ + assert _run_in_process(_python_to_cpp_to_python_from_threads, 8, parallel=True) == 0 + + +def test_python_to_cpp_to_python_from_thread_multiple_sequential(): + """Makes sure there is no GIL deadlock when running in a thread multiple times sequentially. + + It runs in a separate process to be able to stop and assert if it deadlocks. + """ + assert _run_in_process(_python_to_cpp_to_python_from_threads, 8, parallel=False) == 0 + + +def test_python_to_cpp_to_python_from_process(): + """Makes sure there is no GIL deadlock when using processes. + + This test is for completion, but it was never an issue. + """ + assert _run_in_process(_python_to_cpp_to_python) == 0 diff --git a/pybind11/tests/test_iostream.cpp b/pybind11/tests/test_iostream.cpp new file mode 100644 index 0000000..e67f88a --- /dev/null +++ b/pybind11/tests/test_iostream.cpp @@ -0,0 +1,73 @@ +/* + tests/test_iostream.cpp -- Usage of scoped_output_redirect + + Copyright (c) 2017 Henry F. Schreiner + + 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" +#include + + +void noisy_function(std::string msg, bool flush) { + + std::cout << msg; + if (flush) + std::cout << std::flush; +} + +void noisy_funct_dual(std::string msg, std::string emsg) { + std::cout << msg; + std::cerr << emsg; +} + +TEST_SUBMODULE(iostream, m) { + + add_ostream_redirect(m); + + // test_evals + + m.def("captured_output_default", [](std::string msg) { + py::scoped_ostream_redirect redir; + std::cout << msg << std::flush; + }); + + m.def("captured_output", [](std::string msg) { + py::scoped_ostream_redirect redir(std::cout, py::module::import("sys").attr("stdout")); + std::cout << msg << std::flush; + }); + + m.def("guard_output", &noisy_function, + py::call_guard(), + py::arg("msg"), py::arg("flush")=true); + + m.def("captured_err", [](std::string msg) { + py::scoped_ostream_redirect redir(std::cerr, py::module::import("sys").attr("stderr")); + std::cerr << msg << std::flush; + }); + + m.def("noisy_function", &noisy_function, py::arg("msg"), py::arg("flush") = true); + + m.def("dual_guard", &noisy_funct_dual, + py::call_guard(), + py::arg("msg"), py::arg("emsg")); + + m.def("raw_output", [](std::string msg) { + std::cout << msg << std::flush; + }); + + m.def("raw_err", [](std::string msg) { + std::cerr << msg << std::flush; + }); + + m.def("captured_dual", [](std::string msg, std::string emsg) { + py::scoped_ostream_redirect redirout(std::cout, py::module::import("sys").attr("stdout")); + py::scoped_ostream_redirect redirerr(std::cerr, py::module::import("sys").attr("stderr")); + std::cout << msg << std::flush; + std::cerr << emsg << std::flush; + }); +} diff --git a/pybind11/tests/test_iostream.py b/pybind11/tests/test_iostream.py new file mode 100644 index 0000000..27095b2 --- /dev/null +++ b/pybind11/tests/test_iostream.py @@ -0,0 +1,214 @@ +from pybind11_tests import iostream as m +import sys + +from contextlib import contextmanager + +try: + # Python 3 + from io import StringIO +except ImportError: + # Python 2 + try: + from cStringIO import StringIO + except ImportError: + from StringIO import StringIO + +try: + # Python 3.4 + from contextlib import redirect_stdout +except ImportError: + @contextmanager + def redirect_stdout(target): + original = sys.stdout + sys.stdout = target + yield + sys.stdout = original + +try: + # Python 3.5 + from contextlib import redirect_stderr +except ImportError: + @contextmanager + def redirect_stderr(target): + original = sys.stderr + sys.stderr = target + yield + sys.stderr = original + + +def test_captured(capsys): + msg = "I've been redirected to Python, I hope!" + m.captured_output(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == '' + + m.captured_output_default(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == '' + + m.captured_err(msg) + stdout, stderr = capsys.readouterr() + assert stdout == '' + assert stderr == msg + + +def test_captured_large_string(capsys): + # Make this bigger than the buffer used on the C++ side: 1024 chars + msg = "I've been redirected to Python, I hope!" + msg = msg * (1024 // len(msg) + 1) + + m.captured_output_default(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == '' + + +def test_guard_capture(capsys): + msg = "I've been redirected to Python, I hope!" + m.guard_output(msg) + stdout, stderr = capsys.readouterr() + assert stdout == msg + assert stderr == '' + + +def test_series_captured(capture): + with capture: + m.captured_output("a") + m.captured_output("b") + assert capture == "ab" + + +def test_flush(capfd): + msg = "(not flushed)" + msg2 = "(flushed)" + + with m.ostream_redirect(): + m.noisy_function(msg, flush=False) + stdout, stderr = capfd.readouterr() + assert stdout == '' + + m.noisy_function(msg2, flush=True) + stdout, stderr = capfd.readouterr() + assert stdout == msg + msg2 + + m.noisy_function(msg, flush=False) + + stdout, stderr = capfd.readouterr() + assert stdout == msg + + +def test_not_captured(capfd): + msg = "Something that should not show up in log" + stream = StringIO() + with redirect_stdout(stream): + m.raw_output(msg) + stdout, stderr = capfd.readouterr() + assert stdout == msg + assert stderr == '' + assert stream.getvalue() == '' + + stream = StringIO() + with redirect_stdout(stream): + m.captured_output(msg) + stdout, stderr = capfd.readouterr() + assert stdout == '' + assert stderr == '' + assert stream.getvalue() == msg + + +def test_err(capfd): + msg = "Something that should not show up in log" + stream = StringIO() + with redirect_stderr(stream): + m.raw_err(msg) + stdout, stderr = capfd.readouterr() + assert stdout == '' + assert stderr == msg + assert stream.getvalue() == '' + + stream = StringIO() + with redirect_stderr(stream): + m.captured_err(msg) + stdout, stderr = capfd.readouterr() + assert stdout == '' + assert stderr == '' + assert stream.getvalue() == msg + + +def test_multi_captured(capfd): + stream = StringIO() + with redirect_stdout(stream): + m.captured_output("a") + m.raw_output("b") + m.captured_output("c") + m.raw_output("d") + stdout, stderr = capfd.readouterr() + assert stdout == 'bd' + assert stream.getvalue() == 'ac' + + +def test_dual(capsys): + m.captured_dual("a", "b") + stdout, stderr = capsys.readouterr() + assert stdout == "a" + assert stderr == "b" + + +def test_redirect(capfd): + msg = "Should not be in log!" + stream = StringIO() + with redirect_stdout(stream): + m.raw_output(msg) + stdout, stderr = capfd.readouterr() + assert stdout == msg + assert stream.getvalue() == '' + + stream = StringIO() + with redirect_stdout(stream): + with m.ostream_redirect(): + m.raw_output(msg) + stdout, stderr = capfd.readouterr() + assert stdout == '' + assert stream.getvalue() == msg + + stream = StringIO() + with redirect_stdout(stream): + m.raw_output(msg) + stdout, stderr = capfd.readouterr() + assert stdout == msg + assert stream.getvalue() == '' + + +def test_redirect_err(capfd): + msg = "StdOut" + msg2 = "StdErr" + + stream = StringIO() + with redirect_stderr(stream): + with m.ostream_redirect(stdout=False): + m.raw_output(msg) + m.raw_err(msg2) + stdout, stderr = capfd.readouterr() + assert stdout == msg + assert stderr == '' + assert stream.getvalue() == msg2 + + +def test_redirect_both(capfd): + msg = "StdOut" + msg2 = "StdErr" + + stream = StringIO() + stream2 = StringIO() + with redirect_stdout(stream): + with redirect_stderr(stream2): + with m.ostream_redirect(): + m.raw_output(msg) + m.raw_err(msg2) + stdout, stderr = capfd.readouterr() + assert stdout == '' + assert stderr == '' + assert stream.getvalue() == msg + assert stream2.getvalue() == msg2 diff --git a/pybind11/tests/test_kwargs_and_defaults.cpp b/pybind11/tests/test_kwargs_and_defaults.cpp new file mode 100644 index 0000000..2263b6b --- /dev/null +++ b/pybind11/tests/test_kwargs_and_defaults.cpp @@ -0,0 +1,100 @@ +/* + 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 "constructor_stats.h" +#include + +TEST_SUBMODULE(kwargs_and_defaults, m) { + auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); }; + + // test_named_arguments + 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{{13, 17}}; + m.def("kw_func4", [](const std::vector &entries) { + std::string ret = "{"; + for (int i : entries) + ret += std::to_string(i) + " "; + ret.back() = '}'; + return ret; + }, py::arg("myList") = list); + + 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); + + // test_args_and_kwargs + m.def("args_function", [](py::args args) -> py::tuple { return args; }); + m.def("args_kwargs_function", [](py::args args, py::kwargs kwargs) { + return py::make_tuple(args, kwargs); + }); + + // test_mixed_args_and_kwargs + m.def("mixed_plus_args", [](int i, double j, py::args args) { + return py::make_tuple(i, j, args); + }); + m.def("mixed_plus_kwargs", [](int i, double j, py::kwargs kwargs) { + return py::make_tuple(i, j, kwargs); + }); + auto mixed_plus_both = [](int i, double j, py::args args, py::kwargs kwargs) { + return py::make_tuple(i, j, args, kwargs); + }; + m.def("mixed_plus_args_kwargs", mixed_plus_both); + + m.def("mixed_plus_args_kwargs_defaults", mixed_plus_both, + py::arg("i") = 1, py::arg("j") = 3.14159); + + // test_args_refcount + // PyPy needs a garbage collection to get the reference count values to match CPython's behaviour + #ifdef PYPY_VERSION + #define GC_IF_NEEDED ConstructorStats::gc() + #else + #define GC_IF_NEEDED + #endif + m.def("arg_refcount_h", [](py::handle h) { GC_IF_NEEDED; return h.ref_count(); }); + m.def("arg_refcount_h", [](py::handle h, py::handle, py::handle) { GC_IF_NEEDED; return h.ref_count(); }); + m.def("arg_refcount_o", [](py::object o) { GC_IF_NEEDED; return o.ref_count(); }); + m.def("args_refcount", [](py::args a) { + GC_IF_NEEDED; + py::tuple t(a.size()); + for (size_t i = 0; i < a.size(); i++) + // Use raw Python API here to avoid an extra, intermediate incref on the tuple item: + t[i] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast(i))); + return t; + }); + m.def("mixed_args_refcount", [](py::object o, py::args a) { + GC_IF_NEEDED; + py::tuple t(a.size() + 1); + t[0] = o.ref_count(); + for (size_t i = 0; i < a.size(); i++) + // Use raw Python API here to avoid an extra, intermediate incref on the tuple item: + t[i + 1] = (int) Py_REFCNT(PyTuple_GET_ITEM(a.ptr(), static_cast(i))); + return t; + }); + + // pybind11 won't allow these to be bound: args and kwargs, if present, must be at the end. + // Uncomment these to test that the static_assert is indeed working: +// m.def("bad_args1", [](py::args, int) {}); +// m.def("bad_args2", [](py::kwargs, int) {}); +// m.def("bad_args3", [](py::kwargs, py::args) {}); +// m.def("bad_args4", [](py::args, int, py::kwargs) {}); +// m.def("bad_args5", [](py::args, py::kwargs, int) {}); +// m.def("bad_args6", [](py::args, py::args) {}); +// m.def("bad_args7", [](py::kwargs, py::kwargs) {}); + + // test_function_signatures (along with most of the above) + struct KWClass { void foo(int, float) {} }; + py::class_(m, "KWClass") + .def("foo0", &KWClass::foo) + .def("foo1", &KWClass::foo, "x"_a, "y"_a); +} diff --git a/pybind11/tests/test_kwargs_and_defaults.py b/pybind11/tests/test_kwargs_and_defaults.py new file mode 100644 index 0000000..27a05a0 --- /dev/null +++ b/pybind11/tests/test_kwargs_and_defaults.py @@ -0,0 +1,147 @@ +import pytest +from pybind11_tests import kwargs_and_defaults as m + + +def test_function_signatures(doc): + assert doc(m.kw_func0) == "kw_func0(arg0: int, arg1: int) -> str" + assert doc(m.kw_func1) == "kw_func1(x: int, y: int) -> str" + assert doc(m.kw_func2) == "kw_func2(x: int = 100, y: int = 200) -> str" + assert doc(m.kw_func3) == "kw_func3(data: str = 'Hello world!') -> None" + assert doc(m.kw_func4) == "kw_func4(myList: List[int] = [13, 17]) -> str" + assert doc(m.kw_func_udl) == "kw_func_udl(x: int, y: int = 300) -> str" + assert doc(m.kw_func_udl_z) == "kw_func_udl_z(x: int, y: int = 0) -> str" + assert doc(m.args_function) == "args_function(*args) -> tuple" + assert doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple" + assert doc(m.KWClass.foo0) == \ + "foo0(self: m.kwargs_and_defaults.KWClass, arg0: int, arg1: float) -> None" + assert doc(m.KWClass.foo1) == \ + "foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None" + + +def test_named_arguments(msg): + assert m.kw_func0(5, 10) == "x=5, y=10" + + assert m.kw_func1(5, 10) == "x=5, y=10" + assert m.kw_func1(5, y=10) == "x=5, y=10" + assert m.kw_func1(y=10, x=5) == "x=5, y=10" + + assert m.kw_func2() == "x=100, y=200" + assert m.kw_func2(5) == "x=5, y=200" + assert m.kw_func2(x=5) == "x=5, y=200" + assert m.kw_func2(y=10) == "x=100, y=10" + assert m.kw_func2(5, 10) == "x=5, y=10" + assert m.kw_func2(x=5, y=10) == "x=5, y=10" + + with pytest.raises(TypeError) as excinfo: + # noinspection PyArgumentList + m.kw_func2(x=5, y=10, z=12) + assert excinfo.match( + r'(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$))' + '{3}$') + + assert m.kw_func4() == "{13 17}" + assert m.kw_func4(myList=[1, 2, 3]) == "{1 2 3}" + + assert m.kw_func_udl(x=5, y=10) == "x=5, y=10" + assert m.kw_func_udl_z(x=5) == "x=5, y=0" + + +def test_arg_and_kwargs(): + args = 'arg1_value', 'arg2_value', 3 + assert m.args_function(*args) == args + + args = 'a1', 'a2' + kwargs = dict(arg3='a3', arg4=4) + assert m.args_kwargs_function(*args, **kwargs) == (args, kwargs) + + +def test_mixed_args_and_kwargs(msg): + mpa = m.mixed_plus_args + mpk = m.mixed_plus_kwargs + mpak = m.mixed_plus_args_kwargs + mpakd = m.mixed_plus_args_kwargs_defaults + + assert mpa(1, 2.5, 4, 99.5, None) == (1, 2.5, (4, 99.5, None)) + assert mpa(1, 2.5) == (1, 2.5, ()) + with pytest.raises(TypeError) as excinfo: + assert mpa(1) + assert msg(excinfo.value) == """ + mixed_plus_args(): incompatible function arguments. The following argument types are supported: + 1. (arg0: int, arg1: float, *args) -> tuple + + Invoked with: 1 + """ # noqa: E501 line too long + with pytest.raises(TypeError) as excinfo: + assert mpa() + assert msg(excinfo.value) == """ + mixed_plus_args(): incompatible function arguments. The following argument types are supported: + 1. (arg0: int, arg1: float, *args) -> tuple + + Invoked with: + """ # noqa: E501 line too long + + assert mpk(-2, 3.5, pi=3.14159, e=2.71828) == (-2, 3.5, {'e': 2.71828, 'pi': 3.14159}) + assert mpak(7, 7.7, 7.77, 7.777, 7.7777, minusseven=-7) == ( + 7, 7.7, (7.77, 7.777, 7.7777), {'minusseven': -7}) + assert mpakd() == (1, 3.14159, (), {}) + assert mpakd(3) == (3, 3.14159, (), {}) + assert mpakd(j=2.71828) == (1, 2.71828, (), {}) + assert mpakd(k=42) == (1, 3.14159, (), {'k': 42}) + assert mpakd(1, 1, 2, 3, 5, 8, then=13, followedby=21) == ( + 1, 1, (2, 3, 5, 8), {'then': 13, 'followedby': 21}) + # Arguments specified both positionally and via kwargs should fail: + with pytest.raises(TypeError) as excinfo: + assert mpakd(1, i=1) + assert msg(excinfo.value) == """ + mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported: + 1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple + + Invoked with: 1; kwargs: i=1 + """ # noqa: E501 line too long + with pytest.raises(TypeError) as excinfo: + assert mpakd(1, 2, j=1) + assert msg(excinfo.value) == """ + mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported: + 1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple + + Invoked with: 1, 2; kwargs: j=1 + """ # noqa: E501 line too long + + +def test_args_refcount(): + """Issue/PR #1216 - py::args elements get double-inc_ref()ed when combined with regular + arguments""" + refcount = m.arg_refcount_h + + myval = 54321 + expected = refcount(myval) + assert m.arg_refcount_h(myval) == expected + assert m.arg_refcount_o(myval) == expected + 1 + assert m.arg_refcount_h(myval) == expected + assert refcount(myval) == expected + + assert m.mixed_plus_args(1, 2.0, "a", myval) == (1, 2.0, ("a", myval)) + assert refcount(myval) == expected + + assert m.mixed_plus_kwargs(3, 4.0, a=1, b=myval) == (3, 4.0, {"a": 1, "b": myval}) + assert refcount(myval) == expected + + assert m.args_function(-1, myval) == (-1, myval) + assert refcount(myval) == expected + + assert m.mixed_plus_args_kwargs(5, 6.0, myval, a=myval) == (5, 6.0, (myval,), {"a": myval}) + assert refcount(myval) == expected + + assert m.args_kwargs_function(7, 8, myval, a=1, b=myval) == \ + ((7, 8, myval), {"a": 1, "b": myval}) + assert refcount(myval) == expected + + exp3 = refcount(myval, myval, myval) + assert m.args_refcount(myval, myval, myval) == (exp3, exp3, exp3) + assert refcount(myval) == expected + + # This function takes the first arg as a `py::object` and the rest as a `py::args`. Unlike the + # previous case, when we have both positional and `py::args` we need to construct a new tuple + # for the `py::args`; in the previous case, we could simply inc_ref and pass on Python's input + # tuple without having to inc_ref the individual elements, but here we can't, hence the extra + # refs. + assert m.mixed_args_refcount(myval, myval, myval) == (exp3 + 3, exp3 + 3, exp3 + 3) diff --git a/pybind11/tests/test_local_bindings.cpp b/pybind11/tests/test_local_bindings.cpp new file mode 100644 index 0000000..97c02db --- /dev/null +++ b/pybind11/tests/test_local_bindings.cpp @@ -0,0 +1,101 @@ +/* + tests/test_local_bindings.cpp -- tests the py::module_local class feature which makes a class + binding local to the module in which it is defined. + + Copyright (c) 2017 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" +#include "local_bindings.h" +#include +#include +#include + +TEST_SUBMODULE(local_bindings, m) { + // test_load_external + m.def("load_external1", [](ExternalType1 &e) { return e.i; }); + m.def("load_external2", [](ExternalType2 &e) { return e.i; }); + + // test_local_bindings + // Register a class with py::module_local: + bind_local(m, "LocalType", py::module_local()) + .def("get3", [](LocalType &t) { return t.i + 3; }) + ; + + m.def("local_value", [](LocalType &l) { return l.i; }); + + // test_nonlocal_failure + // The main pybind11 test module is loaded first, so this registration will succeed (the second + // one, in pybind11_cross_module_tests.cpp, is designed to fail): + bind_local(m, "NonLocalType") + .def(py::init()) + .def("get", [](LocalType &i) { return i.i; }) + ; + + // test_duplicate_local + // py::module_local declarations should be visible across compilation units that get linked together; + // this tries to register a duplicate local. It depends on a definition in test_class.cpp and + // should raise a runtime error from the duplicate definition attempt. If test_class isn't + // available it *also* throws a runtime error (with "test_class not enabled" as value). + m.def("register_local_external", [m]() { + auto main = py::module::import("pybind11_tests"); + if (py::hasattr(main, "class_")) { + bind_local(m, "LocalExternal", py::module_local()); + } + else throw std::runtime_error("test_class not enabled"); + }); + + // test_stl_bind_local + // stl_bind.h binders defaults to py::module_local if the types are local or converting: + py::bind_vector(m, "LocalVec"); + py::bind_map(m, "LocalMap"); + // and global if the type (or one of the types, for the map) is global: + py::bind_vector(m, "NonLocalVec"); + py::bind_map(m, "NonLocalMap"); + + // test_stl_bind_global + // They can, however, be overridden to global using `py::module_local(false)`: + bind_local(m, "NonLocal2"); + py::bind_vector(m, "LocalVec2", py::module_local()); + py::bind_map(m, "NonLocalMap2", py::module_local(false)); + + // test_mixed_local_global + // We try this both with the global type registered first and vice versa (the order shouldn't + // matter). + m.def("register_mixed_global", [m]() { + bind_local(m, "MixedGlobalLocal", py::module_local(false)); + }); + m.def("register_mixed_local", [m]() { + bind_local(m, "MixedLocalGlobal", py::module_local()); + }); + m.def("get_mixed_gl", [](int i) { return MixedGlobalLocal(i); }); + m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); }); + + // test_internal_locals_differ + m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::registered_local_types_cpp(); }); + + // test_stl_caster_vs_stl_bind + m.def("load_vector_via_caster", [](std::vector v) { + return std::accumulate(v.begin(), v.end(), 0); + }); + + // test_cross_module_calls + m.def("return_self", [](LocalVec *v) { return v; }); + m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); }); + + class Cat : public pets::Pet { public: Cat(std::string name) : Pet(name) {}; }; + py::class_(m, "Pet", py::module_local()) + .def("get_name", &pets::Pet::name); + // Binding for local extending class: + py::class_(m, "Cat") + .def(py::init()); + m.def("pet_name", [](pets::Pet &p) { return p.name(); }); + + py::class_(m, "MixGL").def(py::init()); + m.def("get_gl_value", [](MixGL &o) { return o.i + 10; }); + + py::class_(m, "MixGL2").def(py::init()); +} diff --git a/pybind11/tests/test_local_bindings.py b/pybind11/tests/test_local_bindings.py new file mode 100644 index 0000000..b3dc361 --- /dev/null +++ b/pybind11/tests/test_local_bindings.py @@ -0,0 +1,226 @@ +import pytest + +from pybind11_tests import local_bindings as m + + +def test_load_external(): + """Load a `py::module_local` type that's only registered in an external module""" + import pybind11_cross_module_tests as cm + + assert m.load_external1(cm.ExternalType1(11)) == 11 + assert m.load_external2(cm.ExternalType2(22)) == 22 + + with pytest.raises(TypeError) as excinfo: + assert m.load_external2(cm.ExternalType1(21)) == 21 + assert "incompatible function arguments" in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + assert m.load_external1(cm.ExternalType2(12)) == 12 + assert "incompatible function arguments" in str(excinfo.value) + + +def test_local_bindings(): + """Tests that duplicate `py::module_local` class bindings work across modules""" + + # Make sure we can load the second module with the conflicting (but local) definition: + import pybind11_cross_module_tests as cm + + i1 = m.LocalType(5) + assert i1.get() == 4 + assert i1.get3() == 8 + + i2 = cm.LocalType(10) + assert i2.get() == 11 + assert i2.get2() == 12 + + assert not hasattr(i1, 'get2') + assert not hasattr(i2, 'get3') + + # Loading within the local module + assert m.local_value(i1) == 5 + assert cm.local_value(i2) == 10 + + # Cross-module loading works as well (on failure, the type loader looks for + # external module-local converters): + assert m.local_value(i2) == 10 + assert cm.local_value(i1) == 5 + + +def test_nonlocal_failure(): + """Tests that attempting to register a non-local type in multiple modules fails""" + import pybind11_cross_module_tests as cm + + with pytest.raises(RuntimeError) as excinfo: + cm.register_nonlocal() + assert str(excinfo.value) == 'generic_type: type "NonLocalType" is already registered!' + + +def test_duplicate_local(): + """Tests expected failure when registering a class twice with py::local in the same module""" + with pytest.raises(RuntimeError) as excinfo: + m.register_local_external() + import pybind11_tests + assert str(excinfo.value) == ( + 'generic_type: type "LocalExternal" is already registered!' + if hasattr(pybind11_tests, 'class_') else 'test_class not enabled') + + +def test_stl_bind_local(): + import pybind11_cross_module_tests as cm + + v1, v2 = m.LocalVec(), cm.LocalVec() + v1.append(m.LocalType(1)) + v1.append(m.LocalType(2)) + v2.append(cm.LocalType(1)) + v2.append(cm.LocalType(2)) + + # Cross module value loading: + v1.append(cm.LocalType(3)) + v2.append(m.LocalType(3)) + + assert [i.get() for i in v1] == [0, 1, 2] + assert [i.get() for i in v2] == [2, 3, 4] + + v3, v4 = m.NonLocalVec(), cm.NonLocalVec2() + v3.append(m.NonLocalType(1)) + v3.append(m.NonLocalType(2)) + v4.append(m.NonLocal2(3)) + v4.append(m.NonLocal2(4)) + + assert [i.get() for i in v3] == [1, 2] + assert [i.get() for i in v4] == [13, 14] + + d1, d2 = m.LocalMap(), cm.LocalMap() + d1["a"] = v1[0] + d1["b"] = v1[1] + d2["c"] = v2[0] + d2["d"] = v2[1] + assert {i: d1[i].get() for i in d1} == {'a': 0, 'b': 1} + assert {i: d2[i].get() for i in d2} == {'c': 2, 'd': 3} + + +def test_stl_bind_global(): + import pybind11_cross_module_tests as cm + + with pytest.raises(RuntimeError) as excinfo: + cm.register_nonlocal_map() + assert str(excinfo.value) == 'generic_type: type "NonLocalMap" is already registered!' + + with pytest.raises(RuntimeError) as excinfo: + cm.register_nonlocal_vec() + assert str(excinfo.value) == 'generic_type: type "NonLocalVec" is already registered!' + + with pytest.raises(RuntimeError) as excinfo: + cm.register_nonlocal_map2() + assert str(excinfo.value) == 'generic_type: type "NonLocalMap2" is already registered!' + + +def test_mixed_local_global(): + """Local types take precedence over globally registered types: a module with a `module_local` + type can be registered even if the type is already registered globally. With the module, + casting will go to the local type; outside the module casting goes to the global type.""" + import pybind11_cross_module_tests as cm + m.register_mixed_global() + m.register_mixed_local() + + a = [] + a.append(m.MixedGlobalLocal(1)) + a.append(m.MixedLocalGlobal(2)) + a.append(m.get_mixed_gl(3)) + a.append(m.get_mixed_lg(4)) + + assert [x.get() for x in a] == [101, 1002, 103, 1004] + + cm.register_mixed_global_local() + cm.register_mixed_local_global() + a.append(m.MixedGlobalLocal(5)) + a.append(m.MixedLocalGlobal(6)) + a.append(cm.MixedGlobalLocal(7)) + a.append(cm.MixedLocalGlobal(8)) + a.append(m.get_mixed_gl(9)) + a.append(m.get_mixed_lg(10)) + a.append(cm.get_mixed_gl(11)) + a.append(cm.get_mixed_lg(12)) + + assert [x.get() for x in a] == \ + [101, 1002, 103, 1004, 105, 1006, 207, 2008, 109, 1010, 211, 2012] + + +def test_internal_locals_differ(): + """Makes sure the internal local type map differs across the two modules""" + import pybind11_cross_module_tests as cm + assert m.local_cpp_types_addr() != cm.local_cpp_types_addr() + + +def test_stl_caster_vs_stl_bind(msg): + """One module uses a generic vector caster from `` while the other + exports `std::vector` via `py:bind_vector` and `py::module_local`""" + import pybind11_cross_module_tests as cm + + v1 = cm.VectorInt([1, 2, 3]) + assert m.load_vector_via_caster(v1) == 6 + assert cm.load_vector_via_binding(v1) == 6 + + v2 = [1, 2, 3] + assert m.load_vector_via_caster(v2) == 6 + with pytest.raises(TypeError) as excinfo: + cm.load_vector_via_binding(v2) == 6 + assert msg(excinfo.value) == """ + load_vector_via_binding(): incompatible function arguments. The following argument types are supported: + 1. (arg0: pybind11_cross_module_tests.VectorInt) -> int + + Invoked with: [1, 2, 3] + """ # noqa: E501 line too long + + +def test_cross_module_calls(): + import pybind11_cross_module_tests as cm + + v1 = m.LocalVec() + v1.append(m.LocalType(1)) + v2 = cm.LocalVec() + v2.append(cm.LocalType(2)) + + # Returning the self pointer should get picked up as returning an existing + # instance (even when that instance is of a foreign, non-local type). + assert m.return_self(v1) is v1 + assert cm.return_self(v2) is v2 + assert m.return_self(v2) is v2 + assert cm.return_self(v1) is v1 + + assert m.LocalVec is not cm.LocalVec + # Returning a copy, on the other hand, always goes to the local type, + # regardless of where the source type came from. + assert type(m.return_copy(v1)) is m.LocalVec + assert type(m.return_copy(v2)) is m.LocalVec + assert type(cm.return_copy(v1)) is cm.LocalVec + assert type(cm.return_copy(v2)) is cm.LocalVec + + # Test the example given in the documentation (which also tests inheritance casting): + mycat = m.Cat("Fluffy") + mydog = cm.Dog("Rover") + assert mycat.get_name() == "Fluffy" + assert mydog.name() == "Rover" + assert m.Cat.__base__.__name__ == "Pet" + assert cm.Dog.__base__.__name__ == "Pet" + assert m.Cat.__base__ is not cm.Dog.__base__ + assert m.pet_name(mycat) == "Fluffy" + assert m.pet_name(mydog) == "Rover" + assert cm.pet_name(mycat) == "Fluffy" + assert cm.pet_name(mydog) == "Rover" + + assert m.MixGL is not cm.MixGL + a = m.MixGL(1) + b = cm.MixGL(2) + assert m.get_gl_value(a) == 11 + assert m.get_gl_value(b) == 12 + assert cm.get_gl_value(a) == 101 + assert cm.get_gl_value(b) == 102 + + c, d = m.MixGL2(3), cm.MixGL2(4) + with pytest.raises(TypeError) as excinfo: + m.get_gl_value(c) + assert "incompatible function arguments" in str(excinfo) + with pytest.raises(TypeError) as excinfo: + m.get_gl_value(d) + assert "incompatible function arguments" in str(excinfo) diff --git a/pybind11/tests/test_methods_and_attributes.cpp b/pybind11/tests/test_methods_and_attributes.cpp new file mode 100644 index 0000000..fde152b --- /dev/null +++ b/pybind11/tests/test_methods_and_attributes.cpp @@ -0,0 +1,454 @@ +/* + 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 + + py::str overloaded() { return "()"; } + py::str overloaded(int) { return "(int)"; } + py::str overloaded(int, float) { return "(int, float)"; } + py::str overloaded(float, int) { return "(float, int)"; } + py::str overloaded(int, int) { return "(int, int)"; } + py::str overloaded(float, float) { return "(float, float)"; } + py::str overloaded(int) const { return "(int) const"; } + py::str overloaded(int, float) const { return "(int, float) const"; } + py::str overloaded(float, int) const { return "(float, int) const"; } + py::str overloaded(int, int) const { return "(int, int) const"; } + py::str overloaded(float, float) const { return "(float, float) const"; } + + static py::str overloaded(float) { return "static float"; } + + 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 TestPropertiesOverride : TestProperties { + int value = 99; + static int static_value; +}; +int TestPropertiesOverride::static_value = 99; + +struct TestPropRVP { + UserType v1{1}; + UserType v2{1}; + static UserType sv1; + static UserType sv2; + + const UserType &get1() const { return v1; } + const UserType &get2() const { return v2; } + UserType get_rvalue() const { return v2; } + void set1(int v) { v1.set(v); } + void set2(int v) { v2.set(v); } +}; +UserType TestPropRVP::sv1(1); +UserType TestPropRVP::sv2(1); + +// py::arg/py::arg_v testing: these arguments just record their argument when invoked +class ArgInspector1 { public: std::string arg = "(default arg inspector 1)"; }; +class ArgInspector2 { public: std::string arg = "(default arg inspector 2)"; }; +class ArgAlwaysConverts { }; +namespace pybind11 { namespace detail { +template <> struct type_caster { +public: + PYBIND11_TYPE_CASTER(ArgInspector1, _("ArgInspector1")); + + bool load(handle src, bool convert) { + value.arg = "loading ArgInspector1 argument " + + std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed. " + "Argument value = " + (std::string) str(src); + return true; + } + + static handle cast(const ArgInspector1 &src, return_value_policy, handle) { + return str(src.arg).release(); + } +}; +template <> struct type_caster { +public: + PYBIND11_TYPE_CASTER(ArgInspector2, _("ArgInspector2")); + + bool load(handle src, bool convert) { + value.arg = "loading ArgInspector2 argument " + + std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed. " + "Argument value = " + (std::string) str(src); + return true; + } + + static handle cast(const ArgInspector2 &src, return_value_policy, handle) { + return str(src.arg).release(); + } +}; +template <> struct type_caster { +public: + PYBIND11_TYPE_CASTER(ArgAlwaysConverts, _("ArgAlwaysConverts")); + + bool load(handle, bool convert) { + return convert; + } + + static handle cast(const ArgAlwaysConverts &, return_value_policy, handle) { + return py::none().release(); + } +}; +}} + +// test_custom_caster_destruction +class DestructionTester { +public: + DestructionTester() { print_default_created(this); } + ~DestructionTester() { print_destroyed(this); } + DestructionTester(const DestructionTester &) { print_copy_created(this); } + DestructionTester(DestructionTester &&) { print_move_created(this); } + DestructionTester &operator=(const DestructionTester &) { print_copy_assigned(this); return *this; } + DestructionTester &operator=(DestructionTester &&) { print_move_assigned(this); return *this; } +}; +namespace pybind11 { namespace detail { +template <> struct type_caster { + PYBIND11_TYPE_CASTER(DestructionTester, _("DestructionTester")); + bool load(handle, bool) { return true; } + + static handle cast(const DestructionTester &, return_value_policy, handle) { + return py::bool_(true).release(); + } +}; +}} + +// Test None-allowed py::arg argument policy +class NoneTester { public: int answer = 42; }; +int none1(const NoneTester &obj) { return obj.answer; } +int none2(NoneTester *obj) { return obj ? obj->answer : -1; } +int none3(std::shared_ptr &obj) { return obj ? obj->answer : -1; } +int none4(std::shared_ptr *obj) { return obj && *obj ? (*obj)->answer : -1; } +int none5(std::shared_ptr obj) { return obj ? obj->answer : -1; } + +struct StrIssue { + int val = -1; + + StrIssue() = default; + StrIssue(int i) : val{i} {} +}; + +// Issues #854, #910: incompatible function args when member function/pointer is in unregistered base class +class UnregisteredBase { +public: + void do_nothing() const {} + void increase_value() { rw_value++; ro_value += 0.25; } + void set_int(int v) { rw_value = v; } + int get_int() const { return rw_value; } + double get_double() const { return ro_value; } + int rw_value = 42; + double ro_value = 1.25; +}; +class RegisteredDerived : public UnregisteredBase { +public: + using UnregisteredBase::UnregisteredBase; + double sum() const { return rw_value + ro_value; } +}; + +TEST_SUBMODULE(methods_and_attributes, m) { + // test_methods_and_attributes + py::class_ emna(m, "ExampleMandA"); + emna.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) +#if defined(PYBIND11_OVERLOAD_CAST) + .def("overloaded", py::overload_cast<>(&ExampleMandA::overloaded)) + .def("overloaded", py::overload_cast(&ExampleMandA::overloaded)) + .def("overloaded", py::overload_cast(&ExampleMandA::overloaded)) + .def("overloaded", py::overload_cast(&ExampleMandA::overloaded)) + .def("overloaded", py::overload_cast(&ExampleMandA::overloaded)) + .def("overloaded", py::overload_cast(&ExampleMandA::overloaded)) + .def("overloaded_float", py::overload_cast(&ExampleMandA::overloaded)) + .def("overloaded_const", py::overload_cast(&ExampleMandA::overloaded, py::const_)) + .def("overloaded_const", py::overload_cast(&ExampleMandA::overloaded, py::const_)) + .def("overloaded_const", py::overload_cast(&ExampleMandA::overloaded, py::const_)) + .def("overloaded_const", py::overload_cast(&ExampleMandA::overloaded, py::const_)) + .def("overloaded_const", py::overload_cast(&ExampleMandA::overloaded, py::const_)) +#else + .def("overloaded", static_cast(&ExampleMandA::overloaded)) + .def("overloaded", static_cast(&ExampleMandA::overloaded)) + .def("overloaded", static_cast(&ExampleMandA::overloaded)) + .def("overloaded", static_cast(&ExampleMandA::overloaded)) + .def("overloaded", static_cast(&ExampleMandA::overloaded)) + .def("overloaded", static_cast(&ExampleMandA::overloaded)) + .def("overloaded_float", static_cast(&ExampleMandA::overloaded)) + .def("overloaded_const", static_cast(&ExampleMandA::overloaded)) + .def("overloaded_const", static_cast(&ExampleMandA::overloaded)) + .def("overloaded_const", static_cast(&ExampleMandA::overloaded)) + .def("overloaded_const", static_cast(&ExampleMandA::overloaded)) + .def("overloaded_const", static_cast(&ExampleMandA::overloaded)) +#endif + // test_no_mixed_overloads + // Raise error if trying to mix static/non-static overloads on the same name: + .def_static("add_mixed_overloads1", []() { + auto emna = py::reinterpret_borrow>(py::module::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA")); + emna.def ("overload_mixed1", static_cast(&ExampleMandA::overloaded)) + .def_static("overload_mixed1", static_cast(&ExampleMandA::overloaded)); + }) + .def_static("add_mixed_overloads2", []() { + auto emna = py::reinterpret_borrow>(py::module::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA")); + emna.def_static("overload_mixed2", static_cast(&ExampleMandA::overloaded)) + .def ("overload_mixed2", static_cast(&ExampleMandA::overloaded)); + }) + .def("__str__", &ExampleMandA::toString) + .def_readwrite("value", &ExampleMandA::value); + + // test_copy_method + // Issue #443: can't call copied methods in Python 3 + emna.attr("add2b") = emna.attr("add2"); + + // test_properties, test_static_properties, test_static_cls + py::class_(m, "TestProperties") + .def(py::init<>()) + .def_readonly("def_readonly", &TestProperties::value) + .def_readwrite("def_readwrite", &TestProperties::value) + .def_property("def_writeonly", nullptr, + [](TestProperties& s,int v) { s.value = v; } ) + .def_property("def_property_writeonly", nullptr, &TestProperties::set) + .def_property_readonly("def_property_readonly", &TestProperties::get) + .def_property("def_property", &TestProperties::get, &TestProperties::set) + .def_property("def_property_impossible", nullptr, nullptr) + .def_readonly_static("def_readonly_static", &TestProperties::static_value) + .def_readwrite_static("def_readwrite_static", &TestProperties::static_value) + .def_property_static("def_writeonly_static", nullptr, + [](py::object, int v) { TestProperties::static_value = v; }) + .def_property_readonly_static("def_property_readonly_static", + [](py::object) { return TestProperties::static_get(); }) + .def_property_static("def_property_writeonly_static", nullptr, + [](py::object, int v) { return TestProperties::static_set(v); }) + .def_property_static("def_property_static", + [](py::object) { return TestProperties::static_get(); }, + [](py::object, int v) { TestProperties::static_set(v); }) + .def_property_static("static_cls", + [](py::object cls) { return cls; }, + [](py::object cls, py::function f) { f(cls); }); + + py::class_(m, "TestPropertiesOverride") + .def(py::init<>()) + .def_readonly("def_readonly", &TestPropertiesOverride::value) + .def_readonly_static("def_readonly_static", &TestPropertiesOverride::static_value); + + auto static_get1 = [](py::object) -> const UserType & { return TestPropRVP::sv1; }; + auto static_get2 = [](py::object) -> const UserType & { return TestPropRVP::sv2; }; + auto static_set1 = [](py::object, int v) { TestPropRVP::sv1.set(v); }; + auto static_set2 = [](py::object, int v) { TestPropRVP::sv2.set(v); }; + auto rvp_copy = py::return_value_policy::copy; + + // test_property_return_value_policies + 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) + // test_property_rvalue_policy + .def_property_readonly("rvalue", &TestPropRVP::get_rvalue) + .def_property_readonly_static("static_rvalue", [](py::object) { return UserType(1); }); + + // test_metaclass_override + struct MetaclassOverride { }; + py::class_(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type)) + .def_property_readonly_static("readonly", [](py::object) { return 1; }); + +#if !defined(PYPY_VERSION) + // test_dynamic_attributes + class DynamicClass { + public: + DynamicClass() { print_default_created(this); } + ~DynamicClass() { print_destroyed(this); } + }; + py::class_(m, "DynamicClass", py::dynamic_attr()) + .def(py::init()); + + class CppDerivedDynamicClass : public DynamicClass { }; + py::class_(m, "CppDerivedDynamicClass") + .def(py::init()); +#endif + + // test_noconvert_args + // + // Test converting. The ArgAlwaysConverts is just there to make the first no-conversion pass + // fail so that our call always ends up happening via the second dispatch (the one that allows + // some conversion). + class ArgInspector { + public: + ArgInspector1 f(ArgInspector1 a, ArgAlwaysConverts) { return a; } + std::string g(ArgInspector1 a, const ArgInspector1 &b, int c, ArgInspector2 *d, ArgAlwaysConverts) { + return a.arg + "\n" + b.arg + "\n" + std::to_string(c) + "\n" + d->arg; + } + static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; } + }; + py::class_(m, "ArgInspector") + .def(py::init<>()) + .def("f", &ArgInspector::f, py::arg(), py::arg() = ArgAlwaysConverts()) + .def("g", &ArgInspector::g, "a"_a.noconvert(), "b"_a, "c"_a.noconvert()=13, "d"_a=ArgInspector2(), py::arg() = ArgAlwaysConverts()) + .def_static("h", &ArgInspector::h, py::arg().noconvert(), py::arg() = ArgAlwaysConverts()) + ; + m.def("arg_inspect_func", [](ArgInspector2 a, ArgInspector1 b, ArgAlwaysConverts) { return a.arg + "\n" + b.arg; }, + py::arg().noconvert(false), py::arg_v(nullptr, ArgInspector1()).noconvert(true), py::arg() = ArgAlwaysConverts()); + + m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f")); + m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert()); + m.def("ints_preferred", [](int i) { return i / 2; }, py::arg("i")); + m.def("ints_only", [](int i) { return i / 2; }, py::arg("i").noconvert()); + + // test_bad_arg_default + // Issue/PR #648: bad arg default debugging output +#if !defined(NDEBUG) + m.attr("debug_enabled") = true; +#else + m.attr("debug_enabled") = false; +#endif + m.def("bad_arg_def_named", []{ + auto m = py::module::import("pybind11_tests"); + m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg("a") = UnregisteredType()); + }); + m.def("bad_arg_def_unnamed", []{ + auto m = py::module::import("pybind11_tests"); + m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg() = UnregisteredType()); + }); + + // test_accepts_none + py::class_>(m, "NoneTester") + .def(py::init<>()); + m.def("no_none1", &none1, py::arg().none(false)); + m.def("no_none2", &none2, py::arg().none(false)); + m.def("no_none3", &none3, py::arg().none(false)); + m.def("no_none4", &none4, py::arg().none(false)); + m.def("no_none5", &none5, py::arg().none(false)); + m.def("ok_none1", &none1); + m.def("ok_none2", &none2, py::arg().none(true)); + m.def("ok_none3", &none3); + m.def("ok_none4", &none4, py::arg().none(true)); + m.def("ok_none5", &none5); + + // test_str_issue + // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid + py::class_(m, "StrIssue") + .def(py::init()) + .def(py::init<>()) + .def("__str__", [](const StrIssue &si) { + return "StrIssue[" + std::to_string(si.val) + "]"; } + ); + + // test_unregistered_base_implementations + // + // Issues #854/910: incompatible function args when member function/pointer is in unregistered + // base class The methods and member pointers below actually resolve to members/pointers in + // UnregisteredBase; before this test/fix they would be registered via lambda with a first + // argument of an unregistered type, and thus uncallable. + py::class_(m, "RegisteredDerived") + .def(py::init<>()) + .def("do_nothing", &RegisteredDerived::do_nothing) + .def("increase_value", &RegisteredDerived::increase_value) + .def_readwrite("rw_value", &RegisteredDerived::rw_value) + .def_readonly("ro_value", &RegisteredDerived::ro_value) + // These should trigger a static_assert if uncommented + //.def_readwrite("fails", &UserType::value) // should trigger a static_assert if uncommented + //.def_readonly("fails", &UserType::value) // should trigger a static_assert if uncommented + .def_property("rw_value_prop", &RegisteredDerived::get_int, &RegisteredDerived::set_int) + .def_property_readonly("ro_value_prop", &RegisteredDerived::get_double) + // This one is in the registered class: + .def("sum", &RegisteredDerived::sum) + ; + + using Adapted = decltype(py::method_adaptor(&RegisteredDerived::do_nothing)); + static_assert(std::is_same::value, ""); + + // test_custom_caster_destruction + // Test that `take_ownership` works on types with a custom type caster when given a pointer + + // default policy: don't take ownership: + m.def("custom_caster_no_destroy", []() { static auto *dt = new DestructionTester(); return dt; }); + + m.def("custom_caster_destroy", []() { return new DestructionTester(); }, + py::return_value_policy::take_ownership); // Takes ownership: destroy when finished + m.def("custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); }, + py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction) + m.def("destruction_tester_cstats", &ConstructorStats::get, py::return_value_policy::reference); +} diff --git a/pybind11/tests/test_methods_and_attributes.py b/pybind11/tests/test_methods_and_attributes.py new file mode 100644 index 0000000..86b2c3b --- /dev/null +++ b/pybind11/tests/test_methods_and_attributes.py @@ -0,0 +1,512 @@ +import pytest +from pybind11_tests import methods_and_attributes as m +from pybind11_tests import ConstructorStats + + +def test_methods_and_attributes(): + instance1 = m.ExampleMandA() + instance2 = m.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.overloaded() == "()" + assert instance1.overloaded(0) == "(int)" + assert instance1.overloaded(1, 1.0) == "(int, float)" + assert instance1.overloaded(2.0, 2) == "(float, int)" + assert instance1.overloaded(3, 3) == "(int, int)" + assert instance1.overloaded(4., 4.) == "(float, float)" + assert instance1.overloaded_const(-3) == "(int) const" + assert instance1.overloaded_const(5, 5.0) == "(int, float) const" + assert instance1.overloaded_const(6.0, 6) == "(float, int) const" + assert instance1.overloaded_const(7, 7) == "(int, int) const" + assert instance1.overloaded_const(8., 8.) == "(float, float) const" + assert instance1.overloaded_float(1, 1) == "(float, float)" + assert instance1.overloaded_float(1, 1.) == "(float, float)" + assert instance1.overloaded_float(1., 1) == "(float, float)" + assert instance1.overloaded_float(1., 1.) == "(float, float)" + + assert instance1.value == 320 + instance1.value = 100 + assert str(instance1) == "ExampleMandA[value=100]" + + cstats = ConstructorStats.get(m.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_copy_method(): + """Issue #443: calling copied methods fails in Python 3""" + + m.ExampleMandA.add2c = m.ExampleMandA.add2 + m.ExampleMandA.add2d = m.ExampleMandA.add2b + a = m.ExampleMandA(123) + assert a.value == 123 + a.add2(m.ExampleMandA(-100)) + assert a.value == 23 + a.add2b(m.ExampleMandA(20)) + assert a.value == 43 + a.add2c(m.ExampleMandA(6)) + assert a.value == 49 + a.add2d(m.ExampleMandA(-7)) + assert a.value == 42 + + +def test_properties(): + instance = m.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 + + with pytest.raises(AttributeError) as excinfo: + dummy = instance.def_property_writeonly # noqa: F841 unused var + assert "unreadable attribute" in str(excinfo) + + instance.def_property_writeonly = 4 + assert instance.def_property_readonly == 4 + + with pytest.raises(AttributeError) as excinfo: + dummy = instance.def_property_impossible # noqa: F841 unused var + assert "unreadable attribute" in str(excinfo) + + with pytest.raises(AttributeError) as excinfo: + instance.def_property_impossible = 5 + assert "can't set attribute" in str(excinfo) + + +def test_static_properties(): + assert m.TestProperties.def_readonly_static == 1 + with pytest.raises(AttributeError) as excinfo: + m.TestProperties.def_readonly_static = 2 + assert "can't set attribute" in str(excinfo) + + m.TestProperties.def_readwrite_static = 2 + assert m.TestProperties.def_readwrite_static == 2 + + with pytest.raises(AttributeError) as excinfo: + dummy = m.TestProperties.def_writeonly_static # noqa: F841 unused var + assert "unreadable attribute" in str(excinfo) + + m.TestProperties.def_writeonly_static = 3 + assert m.TestProperties.def_readonly_static == 3 + + assert m.TestProperties.def_property_readonly_static == 3 + with pytest.raises(AttributeError) as excinfo: + m.TestProperties.def_property_readonly_static = 99 + assert "can't set attribute" in str(excinfo) + + m.TestProperties.def_property_static = 4 + assert m.TestProperties.def_property_static == 4 + + with pytest.raises(AttributeError) as excinfo: + dummy = m.TestProperties.def_property_writeonly_static + assert "unreadable attribute" in str(excinfo) + + m.TestProperties.def_property_writeonly_static = 5 + assert m.TestProperties.def_property_static == 5 + + # Static property read and write via instance + instance = m.TestProperties() + + m.TestProperties.def_readwrite_static = 0 + assert m.TestProperties.def_readwrite_static == 0 + assert instance.def_readwrite_static == 0 + + instance.def_readwrite_static = 2 + assert m.TestProperties.def_readwrite_static == 2 + assert instance.def_readwrite_static == 2 + + with pytest.raises(AttributeError) as excinfo: + dummy = instance.def_property_writeonly_static # noqa: F841 unused var + assert "unreadable attribute" in str(excinfo) + + instance.def_property_writeonly_static = 4 + assert instance.def_property_static == 4 + + # It should be possible to override properties in derived classes + assert m.TestPropertiesOverride().def_readonly == 99 + assert m.TestPropertiesOverride.def_readonly_static == 99 + + +def test_static_cls(): + """Static property getter and setters expect the type object as the their only argument""" + + instance = m.TestProperties() + assert m.TestProperties.static_cls is m.TestProperties + assert instance.static_cls is m.TestProperties + + def check_self(self): + assert self is m.TestProperties + + m.TestProperties.static_cls = check_self + instance.static_cls = check_self + + +def test_metaclass_override(): + """Overriding pybind11's default metaclass changes the behavior of `static_property`""" + + assert type(m.ExampleMandA).__name__ == "pybind11_type" + assert type(m.MetaclassOverride).__name__ == "type" + + assert m.MetaclassOverride.readonly == 1 + assert type(m.MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property" + + # Regular `type` replaces the property instead of calling `__set__()` + m.MetaclassOverride.readonly = 2 + assert m.MetaclassOverride.readonly == 2 + assert isinstance(m.MetaclassOverride.__dict__["readonly"], int) + + +def test_no_mixed_overloads(): + from pybind11_tests import debug_enabled + + with pytest.raises(RuntimeError) as excinfo: + m.ExampleMandA.add_mixed_overloads1() + assert (str(excinfo.value) == + "overloading a method with both static and instance methods is not supported; " + + ("compile in debug mode for more details" if not debug_enabled else + "error while attempting to bind static method ExampleMandA.overload_mixed1" + "(arg0: float) -> str") + ) + + with pytest.raises(RuntimeError) as excinfo: + m.ExampleMandA.add_mixed_overloads2() + assert (str(excinfo.value) == + "overloading a method with both static and instance methods is not supported; " + + ("compile in debug mode for more details" if not debug_enabled else + "error while attempting to bind instance method ExampleMandA.overload_mixed2" + "(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)" + " -> str") + ) + + +@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"]) +def test_property_return_value_policies(access): + if not access.startswith("static"): + obj = m.TestPropRVP() + else: + obj = m.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.""" + + instance = m.TestPropRVP() + o = instance.rvalue + assert o.value == 1 + + os = m.TestPropRVP.static_rvalue + assert os.value == 1 + + +# https://bitbucket.org/pypy/pypy/issues/2447 +@pytest.unsupported_on_pypy +def test_dynamic_attributes(): + instance = m.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(m.DynamicClass) + assert cstats.alive() == 1 + del instance + assert cstats.alive() == 0 + + # Derived classes should work as well + class PythonDerivedDynamicClass(m.DynamicClass): + pass + + for cls in m.CppDerivedDynamicClass, PythonDerivedDynamicClass: + derived = cls() + derived.foobar = 100 + assert derived.foobar == 100 + + assert cstats.alive() == 1 + del derived + assert cstats.alive() == 0 + + +# https://bitbucket.org/pypy/pypy/issues/2447 +@pytest.unsupported_on_pypy +def test_cyclic_gc(): + # One object references itself + instance = m.DynamicClass() + instance.circular_reference = instance + + cstats = ConstructorStats.get(m.DynamicClass) + assert cstats.alive() == 1 + del instance + assert cstats.alive() == 0 + + # Two object reference each other + i1 = m.DynamicClass() + i2 = m.DynamicClass() + i1.cycle = i2 + i2.cycle = i1 + + assert cstats.alive() == 2 + del i1, i2 + assert cstats.alive() == 0 + + +def test_noconvert_args(msg): + a = m.ArgInspector() + assert msg(a.f("hi")) == """ + loading ArgInspector1 argument WITH conversion allowed. Argument value = hi + """ + assert msg(a.g("this is a", "this is b")) == """ + loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a + loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b + 13 + loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2) + """ # noqa: E501 line too long + assert msg(a.g("this is a", "this is b", 42)) == """ + loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a + loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b + 42 + loading ArgInspector2 argument WITH conversion allowed. Argument value = (default arg inspector 2) + """ # noqa: E501 line too long + assert msg(a.g("this is a", "this is b", 42, "this is d")) == """ + loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = this is a + loading ArgInspector1 argument WITH conversion allowed. Argument value = this is b + 42 + loading ArgInspector2 argument WITH conversion allowed. Argument value = this is d + """ + assert (a.h("arg 1") == + "loading ArgInspector2 argument WITHOUT conversion allowed. Argument value = arg 1") + assert msg(m.arg_inspect_func("A1", "A2")) == """ + loading ArgInspector2 argument WITH conversion allowed. Argument value = A1 + loading ArgInspector1 argument WITHOUT conversion allowed. Argument value = A2 + """ + + assert m.floats_preferred(4) == 2.0 + assert m.floats_only(4.0) == 2.0 + with pytest.raises(TypeError) as excinfo: + m.floats_only(4) + assert msg(excinfo.value) == """ + floats_only(): incompatible function arguments. The following argument types are supported: + 1. (f: float) -> float + + Invoked with: 4 + """ + + assert m.ints_preferred(4) == 2 + assert m.ints_preferred(True) == 0 + with pytest.raises(TypeError) as excinfo: + m.ints_preferred(4.0) + assert msg(excinfo.value) == """ + ints_preferred(): incompatible function arguments. The following argument types are supported: + 1. (i: int) -> int + + Invoked with: 4.0 + """ # noqa: E501 line too long + + assert m.ints_only(4) == 2 + with pytest.raises(TypeError) as excinfo: + m.ints_only(4.0) + assert msg(excinfo.value) == """ + ints_only(): incompatible function arguments. The following argument types are supported: + 1. (i: int) -> int + + Invoked with: 4.0 + """ + + +def test_bad_arg_default(msg): + from pybind11_tests import debug_enabled + + with pytest.raises(RuntimeError) as excinfo: + m.bad_arg_def_named() + assert msg(excinfo.value) == ( + "arg(): could not convert default argument 'a: UnregisteredType' in function " + "'should_fail' into a Python object (type not registered yet?)" + if debug_enabled else + "arg(): could not convert default argument into a Python object (type not registered " + "yet?). Compile in debug mode for more information." + ) + + with pytest.raises(RuntimeError) as excinfo: + m.bad_arg_def_unnamed() + assert msg(excinfo.value) == ( + "arg(): could not convert default argument 'UnregisteredType' in function " + "'should_fail' into a Python object (type not registered yet?)" + if debug_enabled else + "arg(): could not convert default argument into a Python object (type not registered " + "yet?). Compile in debug mode for more information." + ) + + +def test_accepts_none(msg): + a = m.NoneTester() + assert m.no_none1(a) == 42 + assert m.no_none2(a) == 42 + assert m.no_none3(a) == 42 + assert m.no_none4(a) == 42 + assert m.no_none5(a) == 42 + assert m.ok_none1(a) == 42 + assert m.ok_none2(a) == 42 + assert m.ok_none3(a) == 42 + assert m.ok_none4(a) == 42 + assert m.ok_none5(a) == 42 + + with pytest.raises(TypeError) as excinfo: + m.no_none1(None) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.no_none2(None) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.no_none3(None) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.no_none4(None) + assert "incompatible function arguments" in str(excinfo.value) + with pytest.raises(TypeError) as excinfo: + m.no_none5(None) + assert "incompatible function arguments" in str(excinfo.value) + + # The first one still raises because you can't pass None as a lvalue reference arg: + with pytest.raises(TypeError) as excinfo: + assert m.ok_none1(None) == -1 + assert msg(excinfo.value) == """ + ok_none1(): incompatible function arguments. The following argument types are supported: + 1. (arg0: m.methods_and_attributes.NoneTester) -> int + + Invoked with: None + """ + + # The rest take the argument as pointer or holder, and accept None: + assert m.ok_none2(None) == -1 + assert m.ok_none3(None) == -1 + assert m.ok_none4(None) == -1 + assert m.ok_none5(None) == -1 + + +def test_str_issue(msg): + """#283: __str__ called on uninitialized instance when constructor arguments invalid""" + + assert str(m.StrIssue(3)) == "StrIssue[3]" + + with pytest.raises(TypeError) as excinfo: + str(m.StrIssue("no", "such", "constructor")) + assert msg(excinfo.value) == """ + __init__(): incompatible constructor arguments. The following argument types are supported: + 1. m.methods_and_attributes.StrIssue(arg0: int) + 2. m.methods_and_attributes.StrIssue() + + Invoked with: 'no', 'such', 'constructor' + """ + + +def test_unregistered_base_implementations(): + a = m.RegisteredDerived() + a.do_nothing() + assert a.rw_value == 42 + assert a.ro_value == 1.25 + a.rw_value += 5 + assert a.sum() == 48.25 + a.increase_value() + assert a.rw_value == 48 + assert a.ro_value == 1.5 + assert a.sum() == 49.5 + assert a.rw_value_prop == 48 + a.rw_value_prop += 1 + assert a.rw_value_prop == 49 + a.increase_value() + assert a.ro_value_prop == 1.75 + + +def test_custom_caster_destruction(): + """Tests that returning a pointer to a type that gets converted with a custom type caster gets + destroyed when the function has py::return_value_policy::take_ownership policy applied.""" + + cstats = m.destruction_tester_cstats() + # This one *doesn't* have take_ownership: the pointer should be used but not destroyed: + z = m.custom_caster_no_destroy() + assert cstats.alive() == 1 and cstats.default_constructions == 1 + assert z + + # take_ownership applied: this constructs a new object, casts it, then destroys it: + z = m.custom_caster_destroy() + assert z + assert cstats.default_constructions == 2 + + # Same, but with a const pointer return (which should *not* inhibit destruction): + z = m.custom_caster_destroy_const() + assert z + assert cstats.default_constructions == 3 + + # Make sure we still only have the original object (from ..._no_destroy()) alive: + assert cstats.alive() == 1 diff --git a/pybind11/tests/test_modules.cpp b/pybind11/tests/test_modules.cpp new file mode 100644 index 0000000..c1475fa --- /dev/null +++ b/pybind11/tests/test_modules.cpp @@ -0,0 +1,98 @@ +/* + 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" + +TEST_SUBMODULE(modules, m) { + // test_nested_modules + py::module m_sub = m.def_submodule("subsubmodule"); + m_sub.def("submodule_func", []() { return "submodule_func()"; }); + + // test_reference_internal + 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; + }; + py::class_(m_sub, "A") + .def(py::init()) + .def("__repr__", &A::toString); + + 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}; + }; + 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"); + + // test_duplicate_registration + // Registering two things with the same name + m.def("duplicate_registration", []() { + class Dupe1 { }; + class Dupe2 { }; + class Dupe3 { }; + class DupeException { }; + + auto dm = py::module("dummy"); + auto failures = py::list(); + + py::class_(dm, "Dupe1"); + py::class_(dm, "Dupe2"); + dm.def("dupe1_factory", []() { return Dupe1(); }); + py::exception(dm, "DupeException"); + + try { + py::class_(dm, "Dupe1"); + failures.append("Dupe1 class"); + } catch (std::runtime_error &) {} + try { + dm.def("Dupe1", []() { return Dupe1(); }); + failures.append("Dupe1 function"); + } catch (std::runtime_error &) {} + try { + py::class_(dm, "dupe1_factory"); + failures.append("dupe1_factory"); + } catch (std::runtime_error &) {} + try { + py::exception(dm, "Dupe2"); + failures.append("Dupe2"); + } catch (std::runtime_error &) {} + try { + dm.def("DupeException", []() { return 30; }); + failures.append("DupeException1"); + } catch (std::runtime_error &) {} + try { + py::class_(dm, "DupeException"); + failures.append("DupeException2"); + } catch (std::runtime_error &) {} + + return failures; + }); +} diff --git a/pybind11/tests/test_modules.py b/pybind11/tests/test_modules.py new file mode 100644 index 0000000..2552838 --- /dev/null +++ b/pybind11/tests/test_modules.py @@ -0,0 +1,72 @@ +from pybind11_tests import modules as m +from pybind11_tests.modules import subsubmodule as ms +from pybind11_tests import ConstructorStats + + +def test_nested_modules(): + import pybind11_tests + assert pybind11_tests.__name__ == "pybind11_tests" + assert pybind11_tests.modules.__name__ == "pybind11_tests.modules" + assert pybind11_tests.modules.subsubmodule.__name__ == "pybind11_tests.modules.subsubmodule" + assert m.__name__ == "pybind11_tests.modules" + assert ms.__name__ == "pybind11_tests.modules.subsubmodule" + + assert ms.submodule_func() == "submodule_func()" + + +def test_reference_internal(): + b = ms.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 = ms.A(42) + b.a2 = ms.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(ms.A), ConstructorStats.get(ms.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.modules import OD + from collections import OrderedDict + + assert OD is OrderedDict + assert str(OD([(1, 'a'), (2, 'b')])) == "OrderedDict([(1, 'a'), (2, 'b')])" + + +def test_pydoc(): + """Pydoc needs to be able to provide help() for everything inside a pybind11 module""" + import pybind11_tests + import pydoc + + assert pybind11_tests.__name__ == "pybind11_tests" + assert pybind11_tests.__doc__ == "pybind11 test module" + assert pydoc.text.docmodule(pybind11_tests) + + +def test_duplicate_registration(): + """Registering two things with the same name""" + + assert m.duplicate_registration() == [] diff --git a/pybind11/tests/test_multiple_inheritance.cpp b/pybind11/tests/test_multiple_inheritance.cpp new file mode 100644 index 0000000..ba1674f --- /dev/null +++ b/pybind11/tests/test_multiple_inheritance.cpp @@ -0,0 +1,220 @@ +/* + 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" +#include "constructor_stats.h" + +// Many bases for testing that multiple inheritance from many classes (i.e. requiring extra +// space for holder constructed flags) works. +template struct BaseN { + BaseN(int i) : i(i) { } + int i; +}; + +// test_mi_static_properties +struct Vanilla { + std::string vanilla() { return "Vanilla"; }; +}; +struct WithStatic1 { + static std::string static_func1() { return "WithStatic1"; }; + static int static_value1; +}; +struct WithStatic2 { + static std::string static_func2() { return "WithStatic2"; }; + static int static_value2; +}; +struct VanillaStaticMix1 : Vanilla, WithStatic1, WithStatic2 { + static std::string static_func() { return "VanillaStaticMix1"; } + static int static_value; +}; +struct VanillaStaticMix2 : WithStatic1, Vanilla, WithStatic2 { + static std::string static_func() { return "VanillaStaticMix2"; } + static int static_value; +}; +int WithStatic1::static_value1 = 1; +int WithStatic2::static_value2 = 2; +int VanillaStaticMix1::static_value = 12; +int VanillaStaticMix2::static_value = 12; + +TEST_SUBMODULE(multiple_inheritance, m) { + + // test_multiple_inheritance_mix1 + // test_multiple_inheritance_mix2 + struct Base1 { + Base1(int i) : i(i) { } + int foo() { return i; } + int i; + }; + py::class_ b1(m, "Base1"); + b1.def(py::init()) + .def("foo", &Base1::foo); + + struct Base2 { + Base2(int i) : i(i) { } + int bar() { return i; } + int i; + }; + py::class_ b2(m, "Base2"); + b2.def(py::init()) + .def("bar", &Base2::bar); + + + // test_multiple_inheritance_cpp + struct Base12 : Base1, Base2 { + Base12(int i, int j) : Base1(i), Base2(j) { } + }; + struct MIType : Base12 { + MIType(int i, int j) : Base12(i, j) { } + }; + py::class_(m, "Base12"); + py::class_(m, "MIType") + .def(py::init()); + + + // test_multiple_inheritance_python_many_bases + #define PYBIND11_BASEN(N) py::class_>(m, "BaseN" #N).def(py::init()).def("f" #N, [](BaseN &b) { return b.i + N; }) + PYBIND11_BASEN( 1); PYBIND11_BASEN( 2); PYBIND11_BASEN( 3); PYBIND11_BASEN( 4); + PYBIND11_BASEN( 5); PYBIND11_BASEN( 6); PYBIND11_BASEN( 7); PYBIND11_BASEN( 8); + PYBIND11_BASEN( 9); PYBIND11_BASEN(10); PYBIND11_BASEN(11); PYBIND11_BASEN(12); + PYBIND11_BASEN(13); PYBIND11_BASEN(14); PYBIND11_BASEN(15); PYBIND11_BASEN(16); + PYBIND11_BASEN(17); + + // Uncommenting this should result in a compile time failure (MI can only be specified via + // template parameters because pybind has to know the types involved; see discussion in #742 for + // details). +// struct Base12v2 : Base1, Base2 { +// Base12v2(int i, int j) : Base1(i), Base2(j) { } +// }; +// py::class_(m, "Base12v2", b1, b2) +// .def(py::init()); + + + // test_multiple_inheritance_virtbase + // 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; + }; + py::class_>(m, "Base1a") + .def(py::init()) + .def("foo", &Base1a::foo); + + struct Base2a { + Base2a(int i) : i(i) { } + int bar() { return i; } + int i; + }; + py::class_>(m, "Base2a") + .def(py::init()) + .def("bar", &Base2a::bar); + + struct Base12a : Base1a, Base2a { + Base12a(int i, int j) : Base1a(i), Base2a(j) { } + }; + 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(); }); + + // test_mi_unaligned_base + // test_mi_base_return + // Issue #801: invalid casting to derived type with MI bases + struct I801B1 { int a = 1; I801B1() = default; I801B1(const I801B1 &) = default; virtual ~I801B1() = default; }; + struct I801B2 { int b = 2; I801B2() = default; I801B2(const I801B2 &) = default; virtual ~I801B2() = default; }; + struct I801C : I801B1, I801B2 {}; + struct I801D : I801C {}; // Indirect MI + // Unregistered classes: + struct I801B3 { int c = 3; virtual ~I801B3() = default; }; + struct I801E : I801B3, I801D {}; + + py::class_>(m, "I801B1").def(py::init<>()).def_readonly("a", &I801B1::a); + py::class_>(m, "I801B2").def(py::init<>()).def_readonly("b", &I801B2::b); + py::class_>(m, "I801C").def(py::init<>()); + py::class_>(m, "I801D").def(py::init<>()); + + // Two separate issues here: first, we want to recognize a pointer to a base type as being a + // known instance even when the pointer value is unequal (i.e. due to a non-first + // multiple-inheritance base class): + m.def("i801b1_c", [](I801C *c) { return static_cast(c); }); + m.def("i801b2_c", [](I801C *c) { return static_cast(c); }); + m.def("i801b1_d", [](I801D *d) { return static_cast(d); }); + m.def("i801b2_d", [](I801D *d) { return static_cast(d); }); + + // Second, when returned a base class pointer to a derived instance, we cannot assume that the + // pointer is `reinterpret_cast`able to the derived pointer because, like above, the base class + // pointer could be offset. + m.def("i801c_b1", []() -> I801B1 * { return new I801C(); }); + m.def("i801c_b2", []() -> I801B2 * { return new I801C(); }); + m.def("i801d_b1", []() -> I801B1 * { return new I801D(); }); + m.def("i801d_b2", []() -> I801B2 * { return new I801D(); }); + + // Return a base class pointer to a pybind-registered type when the actual derived type + // isn't pybind-registered (and uses multiple-inheritance to offset the pybind base) + m.def("i801e_c", []() -> I801C * { return new I801E(); }); + m.def("i801e_b2", []() -> I801B2 * { return new I801E(); }); + + + // test_mi_static_properties + py::class_(m, "Vanilla") + .def(py::init<>()) + .def("vanilla", &Vanilla::vanilla); + + py::class_(m, "WithStatic1") + .def(py::init<>()) + .def_static("static_func1", &WithStatic1::static_func1) + .def_readwrite_static("static_value1", &WithStatic1::static_value1); + + py::class_(m, "WithStatic2") + .def(py::init<>()) + .def_static("static_func2", &WithStatic2::static_func2) + .def_readwrite_static("static_value2", &WithStatic2::static_value2); + + py::class_( + m, "VanillaStaticMix1") + .def(py::init<>()) + .def_static("static_func", &VanillaStaticMix1::static_func) + .def_readwrite_static("static_value", &VanillaStaticMix1::static_value); + + py::class_( + m, "VanillaStaticMix2") + .def(py::init<>()) + .def_static("static_func", &VanillaStaticMix2::static_func) + .def_readwrite_static("static_value", &VanillaStaticMix2::static_value); + + +#if !defined(PYPY_VERSION) + struct WithDict { }; + struct VanillaDictMix1 : Vanilla, WithDict { }; + struct VanillaDictMix2 : WithDict, Vanilla { }; + py::class_(m, "WithDict", py::dynamic_attr()).def(py::init<>()); + py::class_(m, "VanillaDictMix1").def(py::init<>()); + py::class_(m, "VanillaDictMix2").def(py::init<>()); +#endif + + // test_diamond_inheritance + // Issue #959: segfault when constructing diamond inheritance instance + // All of these have int members so that there will be various unequal pointers involved. + struct B { int b; B() = default; B(const B&) = default; virtual ~B() = default; }; + struct C0 : public virtual B { int c0; }; + struct C1 : public virtual B { int c1; }; + struct D : public C0, public C1 { int d; }; + py::class_(m, "B") + .def("b", [](B *self) { return self; }); + py::class_(m, "C0") + .def("c0", [](C0 *self) { return self; }); + py::class_(m, "C1") + .def("c1", [](C1 *self) { return self; }); + py::class_(m, "D") + .def(py::init<>()); +} diff --git a/pybind11/tests/test_multiple_inheritance.py b/pybind11/tests/test_multiple_inheritance.py new file mode 100644 index 0000000..475dd3b --- /dev/null +++ b/pybind11/tests/test_multiple_inheritance.py @@ -0,0 +1,349 @@ +import pytest +from pybind11_tests import ConstructorStats +from pybind11_tests import multiple_inheritance as m + + +def test_multiple_inheritance_cpp(): + mt = m.MIType(3, 4) + + assert mt.foo() == 3 + assert mt.bar() == 4 + + +def test_multiple_inheritance_mix1(): + class Base1: + def __init__(self, i): + self.i = i + + def foo(self): + return self.i + + class MITypePy(Base1, m.Base2): + def __init__(self, i, j): + Base1.__init__(self, i) + m.Base2.__init__(self, j) + + mt = MITypePy(3, 4) + + assert mt.foo() == 3 + assert mt.bar() == 4 + + +def test_multiple_inheritance_mix2(): + + class Base2: + def __init__(self, i): + self.i = i + + def bar(self): + return self.i + + class MITypePy(m.Base1, Base2): + def __init__(self, i, j): + m.Base1.__init__(self, i) + Base2.__init__(self, j) + + mt = MITypePy(3, 4) + + assert mt.foo() == 3 + assert mt.bar() == 4 + + +def test_multiple_inheritance_python(): + + class MI1(m.Base1, m.Base2): + def __init__(self, i, j): + m.Base1.__init__(self, i) + m.Base2.__init__(self, j) + + class B1(object): + def v(self): + return 1 + + class MI2(B1, m.Base1, m.Base2): + def __init__(self, i, j): + B1.__init__(self) + m.Base1.__init__(self, i) + m.Base2.__init__(self, j) + + class MI3(MI2): + def __init__(self, i, j): + MI2.__init__(self, i, j) + + class MI4(MI3, m.Base2): + def __init__(self, i, j): + MI3.__init__(self, i, j) + # This should be ignored (Base2 is already initialized via MI2): + m.Base2.__init__(self, i + 100) + + class MI5(m.Base2, B1, m.Base1): + def __init__(self, i, j): + B1.__init__(self) + m.Base1.__init__(self, i) + m.Base2.__init__(self, j) + + class MI6(m.Base2, B1): + def __init__(self, i): + m.Base2.__init__(self, i) + B1.__init__(self) + + class B2(B1): + def v(self): + return 2 + + class B3(object): + def v(self): + return 3 + + class B4(B3, B2): + def v(self): + return 4 + + class MI7(B4, MI6): + def __init__(self, i): + B4.__init__(self) + MI6.__init__(self, i) + + class MI8(MI6, B3): + def __init__(self, i): + MI6.__init__(self, i) + B3.__init__(self) + + class MI8b(B3, MI6): + def __init__(self, i): + B3.__init__(self) + MI6.__init__(self, i) + + mi1 = MI1(1, 2) + assert mi1.foo() == 1 + assert mi1.bar() == 2 + + mi2 = MI2(3, 4) + assert mi2.v() == 1 + assert mi2.foo() == 3 + assert mi2.bar() == 4 + + mi3 = MI3(5, 6) + assert mi3.v() == 1 + assert mi3.foo() == 5 + assert mi3.bar() == 6 + + mi4 = MI4(7, 8) + assert mi4.v() == 1 + assert mi4.foo() == 7 + assert mi4.bar() == 8 + + mi5 = MI5(10, 11) + assert mi5.v() == 1 + assert mi5.foo() == 10 + assert mi5.bar() == 11 + + mi6 = MI6(12) + assert mi6.v() == 1 + assert mi6.bar() == 12 + + mi7 = MI7(13) + assert mi7.v() == 4 + assert mi7.bar() == 13 + + mi8 = MI8(14) + assert mi8.v() == 1 + assert mi8.bar() == 14 + + mi8b = MI8b(15) + assert mi8b.v() == 3 + assert mi8b.bar() == 15 + + +def test_multiple_inheritance_python_many_bases(): + + class MIMany14(m.BaseN1, m.BaseN2, m.BaseN3, m.BaseN4): + def __init__(self): + m.BaseN1.__init__(self, 1) + m.BaseN2.__init__(self, 2) + m.BaseN3.__init__(self, 3) + m.BaseN4.__init__(self, 4) + + class MIMany58(m.BaseN5, m.BaseN6, m.BaseN7, m.BaseN8): + def __init__(self): + m.BaseN5.__init__(self, 5) + m.BaseN6.__init__(self, 6) + m.BaseN7.__init__(self, 7) + m.BaseN8.__init__(self, 8) + + class MIMany916(m.BaseN9, m.BaseN10, m.BaseN11, m.BaseN12, m.BaseN13, m.BaseN14, m.BaseN15, + m.BaseN16): + def __init__(self): + m.BaseN9.__init__(self, 9) + m.BaseN10.__init__(self, 10) + m.BaseN11.__init__(self, 11) + m.BaseN12.__init__(self, 12) + m.BaseN13.__init__(self, 13) + m.BaseN14.__init__(self, 14) + m.BaseN15.__init__(self, 15) + m.BaseN16.__init__(self, 16) + + class MIMany19(MIMany14, MIMany58, m.BaseN9): + def __init__(self): + MIMany14.__init__(self) + MIMany58.__init__(self) + m.BaseN9.__init__(self, 9) + + class MIMany117(MIMany14, MIMany58, MIMany916, m.BaseN17): + def __init__(self): + MIMany14.__init__(self) + MIMany58.__init__(self) + MIMany916.__init__(self) + m.BaseN17.__init__(self, 17) + + # Inherits from 4 registered C++ classes: can fit in one pointer on any modern arch: + a = MIMany14() + for i in range(1, 4): + assert getattr(a, "f" + str(i))() == 2 * i + + # Inherits from 8: requires 1/2 pointers worth of holder flags on 32/64-bit arch: + b = MIMany916() + for i in range(9, 16): + assert getattr(b, "f" + str(i))() == 2 * i + + # Inherits from 9: requires >= 2 pointers worth of holder flags + c = MIMany19() + for i in range(1, 9): + assert getattr(c, "f" + str(i))() == 2 * i + + # Inherits from 17: requires >= 3 pointers worth of holder flags + d = MIMany117() + for i in range(1, 17): + assert getattr(d, "f" + str(i))() == 2 * i + + +def test_multiple_inheritance_virtbase(): + + class MITypePy(m.Base12a): + def __init__(self, i, j): + m.Base12a.__init__(self, i, j) + + mt = MITypePy(3, 4) + assert mt.bar() == 4 + assert m.bar_base2a(mt) == 4 + assert m.bar_base2a_sharedptr(mt) == 4 + + +def test_mi_static_properties(): + """Mixing bases with and without static properties should be possible + and the result should be independent of base definition order""" + + for d in (m.VanillaStaticMix1(), m.VanillaStaticMix2()): + assert d.vanilla() == "Vanilla" + assert d.static_func1() == "WithStatic1" + assert d.static_func2() == "WithStatic2" + assert d.static_func() == d.__class__.__name__ + + m.WithStatic1.static_value1 = 1 + m.WithStatic2.static_value2 = 2 + assert d.static_value1 == 1 + assert d.static_value2 == 2 + assert d.static_value == 12 + + d.static_value1 = 0 + assert d.static_value1 == 0 + d.static_value2 = 0 + assert d.static_value2 == 0 + d.static_value = 0 + assert d.static_value == 0 + + +@pytest.unsupported_on_pypy +def test_mi_dynamic_attributes(): + """Mixing bases with and without dynamic attribute support""" + + for d in (m.VanillaDictMix1(), m.VanillaDictMix2()): + d.dynamic = 1 + assert d.dynamic == 1 + + +def test_mi_unaligned_base(): + """Returning an offset (non-first MI) base class pointer should recognize the instance""" + + n_inst = ConstructorStats.detail_reg_inst() + + c = m.I801C() + d = m.I801D() + # + 4 below because we have the two instances, and each instance has offset base I801B2 + assert ConstructorStats.detail_reg_inst() == n_inst + 4 + b1c = m.i801b1_c(c) + assert b1c is c + b2c = m.i801b2_c(c) + assert b2c is c + b1d = m.i801b1_d(d) + assert b1d is d + b2d = m.i801b2_d(d) + assert b2d is d + + assert ConstructorStats.detail_reg_inst() == n_inst + 4 # no extra instances + del c, b1c, b2c + assert ConstructorStats.detail_reg_inst() == n_inst + 2 + del d, b1d, b2d + assert ConstructorStats.detail_reg_inst() == n_inst + + +def test_mi_base_return(): + """Tests returning an offset (non-first MI) base class pointer to a derived instance""" + + n_inst = ConstructorStats.detail_reg_inst() + + c1 = m.i801c_b1() + assert type(c1) is m.I801C + assert c1.a == 1 + assert c1.b == 2 + + d1 = m.i801d_b1() + assert type(d1) is m.I801D + assert d1.a == 1 + assert d1.b == 2 + + assert ConstructorStats.detail_reg_inst() == n_inst + 4 + + c2 = m.i801c_b2() + assert type(c2) is m.I801C + assert c2.a == 1 + assert c2.b == 2 + + d2 = m.i801d_b2() + assert type(d2) is m.I801D + assert d2.a == 1 + assert d2.b == 2 + + assert ConstructorStats.detail_reg_inst() == n_inst + 8 + + del c2 + assert ConstructorStats.detail_reg_inst() == n_inst + 6 + del c1, d1, d2 + assert ConstructorStats.detail_reg_inst() == n_inst + + # Returning an unregistered derived type with a registered base; we won't + # pick up the derived type, obviously, but should still work (as an object + # of whatever type was returned). + e1 = m.i801e_c() + assert type(e1) is m.I801C + assert e1.a == 1 + assert e1.b == 2 + + e2 = m.i801e_b2() + assert type(e2) is m.I801B2 + assert e2.b == 2 + + +def test_diamond_inheritance(): + """Tests that diamond inheritance works as expected (issue #959)""" + + # Issue #959: this shouldn't segfault: + d = m.D() + + # Make sure all the various distinct pointers are all recognized as registered instances: + assert d is d.c0() + assert d is d.c1() + assert d is d.b() + assert d is d.c0().b() + assert d is d.c1().b() + assert d is d.c0().c1().b().c0().b() diff --git a/pybind11/tests/test_numpy_array.cpp b/pybind11/tests/test_numpy_array.cpp new file mode 100644 index 0000000..5702594 --- /dev/null +++ b/pybind11/tests/test_numpy_array.cpp @@ -0,0 +1,304 @@ +/* + 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 + +using arr = py::array; +using arr_t = py::array_t; +static_assert(std::is_same::value, ""); + +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...)); +} + +template arr& mutate_data(arr& a, Ix... index) { + auto ptr = (uint8_t *) a.mutable_data(index...); + for (ssize_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 (ssize_t i = 0; i < a.size() - a.index_at(index...); i++) + ptr[i]++; + return a; +} + +template ssize_t index_at(const arr& a, Ix... idx) { return a.index_at(idx...); } +template ssize_t index_at_t(const arr_t& a, Ix... idx) { return a.index_at(idx...); } +template ssize_t offset_at(const arr& a, Ix... idx) { return a.offset_at(idx...); } +template ssize_t offset_at_t(const arr_t& a, Ix... idx) { return a.offset_at(idx...); } +template ssize_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); }); + +template py::handle auxiliaries(T &&r, T2 &&r2) { + if (r.ndim() != 2) throw std::domain_error("error: ndim != 2"); + py::list l; + l.append(*r.data(0, 0)); + l.append(*r2.mutable_data(0, 0)); + l.append(r.data(0, 1) == r2.mutable_data(0, 1)); + l.append(r.ndim()); + l.append(r.itemsize()); + l.append(r.shape(0)); + l.append(r.shape(1)); + l.append(r.size()); + l.append(r.nbytes()); + return l.release(); +} + +TEST_SUBMODULE(numpy_array, sm) { + try { py::module::import("numpy"); } + catch (...) { return; } + + // test_array_attributes + 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, ssize_t dim) { return a.shape(dim); }); + sm.def("strides", [](const arr& a) { return arr(a.ndim(), a.strides()); }); + sm.def("strides", [](const arr& a, ssize_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(); }); + + // test_index_offset + 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&); + // test_data + def_index_fn(data, const arr&); + def_index_fn(data_t, const arr_t&); + // test_mutate_data, test_mutate_readonly + 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&); + + // test_make_c_f_array + 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 }); }); + + // test_empty_shaped_array + sm.def("make_empty_shaped_array", [] { return py::array(py::dtype("f"), {}, {}); }); + + // test_wrap + sm.def("wrap", [](py::array a) { + return py::array( + a.dtype(), + {a.shape(), a.shape() + a.ndim()}, + {a.strides(), a.strides() + a.ndim()}, + a.data(), + a + ); + }); + + // test_numpy_view + 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); + } + ); + + // test_cast_numpy_int64_to_uint64 + sm.def("function_taking_uint64", [](uint64_t) { }); + + // test_isinstance + 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); + }); + + // test_constructors + 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) + ); + }); + + // test_overload_resolution + sm.def("overloaded", [](py::array_t) { return "double"; }); + sm.def("overloaded", [](py::array_t) { return "float"; }); + sm.def("overloaded", [](py::array_t) { return "int"; }); + sm.def("overloaded", [](py::array_t) { return "unsigned short"; }); + sm.def("overloaded", [](py::array_t) { return "long long"; }); + sm.def("overloaded", [](py::array_t>) { return "double complex"; }); + sm.def("overloaded", [](py::array_t>) { return "float complex"; }); + + sm.def("overloaded2", [](py::array_t>) { return "double complex"; }); + sm.def("overloaded2", [](py::array_t) { return "double"; }); + sm.def("overloaded2", [](py::array_t>) { return "float complex"; }); + sm.def("overloaded2", [](py::array_t) { return "float"; }); + + // Only accept the exact types: + sm.def("overloaded3", [](py::array_t) { return "int"; }, py::arg().noconvert()); + sm.def("overloaded3", [](py::array_t) { return "double"; }, py::arg().noconvert()); + + // Make sure we don't do unsafe coercion (e.g. float to int) when not using forcecast, but + // rather that float gets converted via the safe (conversion to double) overload: + sm.def("overloaded4", [](py::array_t) { return "long long"; }); + sm.def("overloaded4", [](py::array_t) { return "double"; }); + + // But we do allow conversion to int if forcecast is enabled (but only if no overload matches + // without conversion) + sm.def("overloaded5", [](py::array_t) { return "unsigned int"; }); + sm.def("overloaded5", [](py::array_t) { return "double"; }); + + // test_greedy_string_overload + // Issue 685: ndarray shouldn't go to std::string overload + sm.def("issue685", [](std::string) { return "string"; }); + sm.def("issue685", [](py::array) { return "array"; }); + sm.def("issue685", [](py::object) { return "other"; }); + + // test_array_unchecked_fixed_dims + sm.def("proxy_add2", [](py::array_t a, double v) { + auto r = a.mutable_unchecked<2>(); + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + r(i, j) += v; + }, py::arg().noconvert(), py::arg()); + + sm.def("proxy_init3", [](double start) { + py::array_t a({ 3, 3, 3 }); + auto r = a.mutable_unchecked<3>(); + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t k = 0; k < r.shape(2); k++) + r(i, j, k) = start++; + return a; + }); + sm.def("proxy_init3F", [](double start) { + py::array_t a({ 3, 3, 3 }); + auto r = a.mutable_unchecked<3>(); + for (ssize_t k = 0; k < r.shape(2); k++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t i = 0; i < r.shape(0); i++) + r(i, j, k) = start++; + return a; + }); + sm.def("proxy_squared_L2_norm", [](py::array_t a) { + auto r = a.unchecked<1>(); + double sumsq = 0; + for (ssize_t i = 0; i < r.shape(0); i++) + sumsq += r[i] * r(i); // Either notation works for a 1D array + return sumsq; + }); + + sm.def("proxy_auxiliaries2", [](py::array_t a) { + auto r = a.unchecked<2>(); + auto r2 = a.mutable_unchecked<2>(); + return auxiliaries(r, r2); + }); + + // test_array_unchecked_dyn_dims + // Same as the above, but without a compile-time dimensions specification: + sm.def("proxy_add2_dyn", [](py::array_t a, double v) { + auto r = a.mutable_unchecked(); + if (r.ndim() != 2) throw std::domain_error("error: ndim != 2"); + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + r(i, j) += v; + }, py::arg().noconvert(), py::arg()); + sm.def("proxy_init3_dyn", [](double start) { + py::array_t a({ 3, 3, 3 }); + auto r = a.mutable_unchecked(); + if (r.ndim() != 3) throw std::domain_error("error: ndim != 3"); + for (ssize_t i = 0; i < r.shape(0); i++) + for (ssize_t j = 0; j < r.shape(1); j++) + for (ssize_t k = 0; k < r.shape(2); k++) + r(i, j, k) = start++; + return a; + }); + sm.def("proxy_auxiliaries2_dyn", [](py::array_t a) { + return auxiliaries(a.unchecked(), a.mutable_unchecked()); + }); + + sm.def("array_auxiliaries2", [](py::array_t a) { + return auxiliaries(a, a); + }); + + // test_array_failures + // Issue #785: Uninformative "Unknown internal error" exception when constructing array from empty object: + sm.def("array_fail_test", []() { return py::array(py::object()); }); + sm.def("array_t_fail_test", []() { return py::array_t(py::object()); }); + // Make sure the error from numpy is being passed through: + sm.def("array_fail_test_negative_size", []() { int c = 0; return py::array(-1, &c); }); + + // test_initializer_list + // Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous + sm.def("array_initializer_list1", []() { return py::array_t(1); }); // { 1 } also works, but clang warns about it + sm.def("array_initializer_list2", []() { return py::array_t({ 1, 2 }); }); + sm.def("array_initializer_list3", []() { return py::array_t({ 1, 2, 3 }); }); + sm.def("array_initializer_list4", []() { return py::array_t({ 1, 2, 3, 4 }); }); + + // test_array_resize + // reshape array to 2D without changing size + sm.def("array_reshape2", [](py::array_t a) { + const ssize_t dim_sz = (ssize_t)std::sqrt(a.size()); + if (dim_sz * dim_sz != a.size()) + throw std::domain_error("array_reshape2: input array total size is not a squared integer"); + a.resize({dim_sz, dim_sz}); + }); + + // resize to 3D array with each dimension = N + sm.def("array_resize3", [](py::array_t a, size_t N, bool refcheck) { + a.resize({N, N, N}, refcheck); + }); + + // test_array_create_and_resize + // return 2D array with Nrows = Ncols = N + sm.def("create_and_resize", [](size_t N) { + py::array_t a; + a.resize({N, N}); + std::fill(a.mutable_data(), a.mutable_data() + a.size(), 42.); + return a; + }); + +#if PY_MAJOR_VERSION >= 3 + sm.def("index_using_ellipsis", [](py::array a) { + return a[py::make_tuple(0, py::ellipsis(), 0)]; + }); +#endif +} diff --git a/pybind11/tests/test_numpy_array.py b/pybind11/tests/test_numpy_array.py new file mode 100644 index 0000000..8ac0e66 --- /dev/null +++ b/pybind11/tests/test_numpy_array.py @@ -0,0 +1,416 @@ +import pytest +from pybind11_tests import numpy_array as m + +pytestmark = pytest.requires_numpy + +with pytest.suppress(ImportError): + import numpy as np + + +@pytest.fixture(scope='function') +def arr(): + return np.array([[1, 2, 3], [4, 5, 6]], '=u2') + + +def test_array_attributes(): + a = np.array(0, 'f8') + assert m.ndim(a) == 0 + assert all(m.shape(a) == []) + assert all(m.strides(a) == []) + with pytest.raises(IndexError) as excinfo: + m.shape(a, 0) + assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)' + with pytest.raises(IndexError) as excinfo: + m.strides(a, 0) + assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)' + assert m.writeable(a) + assert m.size(a) == 1 + assert m.itemsize(a) == 8 + assert m.nbytes(a) == 8 + assert m.owndata(a) + + a = np.array([[1, 2, 3], [4, 5, 6]], 'u2').view() + a.flags.writeable = False + assert m.ndim(a) == 2 + assert all(m.shape(a) == [2, 3]) + assert m.shape(a, 0) == 2 + assert m.shape(a, 1) == 3 + assert all(m.strides(a) == [6, 2]) + assert m.strides(a, 0) == 6 + assert m.strides(a, 1) == 2 + with pytest.raises(IndexError) as excinfo: + m.shape(a, 2) + assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)' + with pytest.raises(IndexError) as excinfo: + m.strides(a, 2) + assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)' + assert not m.writeable(a) + assert m.size(a) == 6 + assert m.itemsize(a) == 2 + assert m.nbytes(a) == 12 + assert not m.owndata(a) + + +@pytest.mark.parametrize('args, ret', [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)]) +def test_index_offset(arr, args, ret): + assert m.index_at(arr, *args) == ret + assert m.index_at_t(arr, *args) == ret + assert m.offset_at(arr, *args) == ret * arr.dtype.itemsize + assert m.offset_at_t(arr, *args) == ret * arr.dtype.itemsize + + +def test_dim_check_fail(arr): + for func in (m.index_at, m.index_at_t, m.offset_at, m.offset_at_t, m.data, m.data_t, + m.mutate_data, m.mutate_data_t): + with pytest.raises(IndexError) as excinfo: + func(arr, 1, 2, 3) + assert str(excinfo.value) == 'too many indices for an array: 3 (ndim = 2)' + + +@pytest.mark.parametrize('args, ret', + [([], [1, 2, 3, 4, 5, 6]), + ([1], [4, 5, 6]), + ([0, 1], [2, 3, 4, 5, 6]), + ([1, 2], [6])]) +def test_data(arr, args, ret): + from sys import byteorder + assert all(m.data_t(arr, *args) == ret) + assert all(m.data(arr, *args)[(0 if byteorder == 'little' else 1)::2] == ret) + assert all(m.data(arr, *args)[(1 if byteorder == 'little' else 0)::2] == 0) + + +@pytest.mark.parametrize('dim', [0, 1, 3]) +def test_at_fail(arr, dim): + for func in m.at_t, m.mutate_at_t: + with pytest.raises(IndexError) as excinfo: + func(arr, *([0] * dim)) + assert str(excinfo.value) == 'index dimension mismatch: {} (ndim = 2)'.format(dim) + + +def test_at(arr): + assert m.at_t(arr, 0, 2) == 3 + assert m.at_t(arr, 1, 0) == 4 + + assert all(m.mutate_at_t(arr, 0, 2).ravel() == [1, 2, 4, 4, 5, 6]) + assert all(m.mutate_at_t(arr, 1, 0).ravel() == [1, 2, 4, 5, 5, 6]) + + +def test_mutate_readonly(arr): + arr.flags.writeable = False + for func, args in (m.mutate_data, ()), (m.mutate_data_t, ()), (m.mutate_at_t, (0, 0)): + with pytest.raises(ValueError) as excinfo: + func(arr, *args) + assert str(excinfo.value) == 'array is not writeable' + + +def test_mutate_data(arr): + assert all(m.mutate_data(arr).ravel() == [2, 4, 6, 8, 10, 12]) + assert all(m.mutate_data(arr).ravel() == [4, 8, 12, 16, 20, 24]) + assert all(m.mutate_data(arr, 1).ravel() == [4, 8, 12, 32, 40, 48]) + assert all(m.mutate_data(arr, 0, 1).ravel() == [4, 16, 24, 64, 80, 96]) + assert all(m.mutate_data(arr, 1, 2).ravel() == [4, 16, 24, 64, 80, 192]) + + assert all(m.mutate_data_t(arr).ravel() == [5, 17, 25, 65, 81, 193]) + assert all(m.mutate_data_t(arr).ravel() == [6, 18, 26, 66, 82, 194]) + assert all(m.mutate_data_t(arr, 1).ravel() == [6, 18, 26, 67, 83, 195]) + assert all(m.mutate_data_t(arr, 0, 1).ravel() == [6, 19, 27, 68, 84, 196]) + assert all(m.mutate_data_t(arr, 1, 2).ravel() == [6, 19, 27, 68, 84, 197]) + + +def test_bounds_check(arr): + for func in (m.index_at, m.index_at_t, m.data, m.data_t, + m.mutate_data, m.mutate_data_t, m.at_t, m.mutate_at_t): + with pytest.raises(IndexError) as excinfo: + func(arr, 2, 0) + assert str(excinfo.value) == 'index 2 is out of bounds for axis 0 with size 2' + with pytest.raises(IndexError) as excinfo: + func(arr, 0, 4) + assert str(excinfo.value) == 'index 4 is out of bounds for axis 1 with size 3' + + +def test_make_c_f_array(): + assert m.make_c_array().flags.c_contiguous + assert not m.make_c_array().flags.f_contiguous + assert m.make_f_array().flags.f_contiguous + assert not m.make_f_array().flags.c_contiguous + + +def test_make_empty_shaped_array(): + m.make_empty_shaped_array() + + +def test_wrap(): + def assert_references(a, b, base=None): + from distutils.version import LooseVersion + if base is None: + base = a + assert a is not b + assert a.__array_interface__['data'][0] == b.__array_interface__['data'][0] + assert a.shape == b.shape + assert a.strides == b.strides + assert a.flags.c_contiguous == b.flags.c_contiguous + assert a.flags.f_contiguous == b.flags.f_contiguous + assert a.flags.writeable == b.flags.writeable + assert a.flags.aligned == b.flags.aligned + if LooseVersion(np.__version__) >= LooseVersion("1.14.0"): + assert a.flags.writebackifcopy == b.flags.writebackifcopy + else: + assert a.flags.updateifcopy == b.flags.updateifcopy + assert np.all(a == b) + assert not b.flags.owndata + assert b.base is base + if a.flags.writeable and a.ndim == 2: + a[0, 0] = 1234 + assert b[0, 0] == 1234 + + a1 = np.array([1, 2], dtype=np.int16) + assert a1.flags.owndata and a1.base is None + a2 = m.wrap(a1) + assert_references(a1, a2) + + a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='F') + assert a1.flags.owndata and a1.base is None + a2 = m.wrap(a1) + assert_references(a1, a2) + + a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='C') + a1.flags.writeable = False + a2 = m.wrap(a1) + assert_references(a1, a2) + + a1 = np.random.random((4, 4, 4)) + a2 = m.wrap(a1) + assert_references(a1, a2) + + a1t = a1.transpose() + a2 = m.wrap(a1t) + assert_references(a1t, a2, a1) + + a1d = a1.diagonal() + a2 = m.wrap(a1d) + assert_references(a1d, a2, a1) + + a1m = a1[::-1, ::-1, ::-1] + a2 = m.wrap(a1m) + assert_references(a1m, a2, a1) + + +def test_numpy_view(capture): + with capture: + ac = m.ArrayClass() + ac_view_1 = ac.numpy_view() + ac_view_2 = ac.numpy_view() + assert np.all(ac_view_1 == np.array([1, 2], dtype=np.int32)) + del ac + pytest.gc_collect() + assert capture == """ + ArrayClass() + ArrayClass::numpy_view() + ArrayClass::numpy_view() + """ + ac_view_1[0] = 4 + ac_view_1[1] = 3 + assert ac_view_2[0] == 4 + assert ac_view_2[1] == 3 + with capture: + del ac_view_1 + del ac_view_2 + pytest.gc_collect() + pytest.gc_collect() + assert capture == """ + ~ArrayClass() + """ + + +@pytest.unsupported_on_pypy +def test_cast_numpy_int64_to_uint64(): + m.function_taking_uint64(123) + m.function_taking_uint64(np.uint64(123)) + + +def test_isinstance(): + assert m.isinstance_untyped(np.array([1, 2, 3]), "not an array") + assert m.isinstance_typed(np.array([1.0, 2.0, 3.0])) + + +def test_constructors(): + defaults = m.default_constructors() + for a in defaults.values(): + assert a.size == 0 + assert defaults["array"].dtype == np.array([]).dtype + assert defaults["array_t"].dtype == np.int32 + assert defaults["array_t"].dtype == np.float64 + + results = m.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 + + +def test_overload_resolution(msg): + # Exact overload matches: + assert m.overloaded(np.array([1], dtype='float64')) == 'double' + assert m.overloaded(np.array([1], dtype='float32')) == 'float' + assert m.overloaded(np.array([1], dtype='ushort')) == 'unsigned short' + assert m.overloaded(np.array([1], dtype='intc')) == 'int' + assert m.overloaded(np.array([1], dtype='longlong')) == 'long long' + assert m.overloaded(np.array([1], dtype='complex')) == 'double complex' + assert m.overloaded(np.array([1], dtype='csingle')) == 'float complex' + + # No exact match, should call first convertible version: + assert m.overloaded(np.array([1], dtype='uint8')) == 'double' + + with pytest.raises(TypeError) as excinfo: + m.overloaded("not an array") + assert msg(excinfo.value) == """ + overloaded(): incompatible function arguments. The following argument types are supported: + 1. (arg0: numpy.ndarray[float64]) -> str + 2. (arg0: numpy.ndarray[float32]) -> str + 3. (arg0: numpy.ndarray[int32]) -> str + 4. (arg0: numpy.ndarray[uint16]) -> str + 5. (arg0: numpy.ndarray[int64]) -> str + 6. (arg0: numpy.ndarray[complex128]) -> str + 7. (arg0: numpy.ndarray[complex64]) -> str + + Invoked with: 'not an array' + """ + + assert m.overloaded2(np.array([1], dtype='float64')) == 'double' + assert m.overloaded2(np.array([1], dtype='float32')) == 'float' + assert m.overloaded2(np.array([1], dtype='complex64')) == 'float complex' + assert m.overloaded2(np.array([1], dtype='complex128')) == 'double complex' + assert m.overloaded2(np.array([1], dtype='float32')) == 'float' + + assert m.overloaded3(np.array([1], dtype='float64')) == 'double' + assert m.overloaded3(np.array([1], dtype='intc')) == 'int' + expected_exc = """ + overloaded3(): incompatible function arguments. The following argument types are supported: + 1. (arg0: numpy.ndarray[int32]) -> str + 2. (arg0: numpy.ndarray[float64]) -> str + + Invoked with: """ + + with pytest.raises(TypeError) as excinfo: + m.overloaded3(np.array([1], dtype='uintc')) + assert msg(excinfo.value) == expected_exc + repr(np.array([1], dtype='uint32')) + with pytest.raises(TypeError) as excinfo: + m.overloaded3(np.array([1], dtype='float32')) + assert msg(excinfo.value) == expected_exc + repr(np.array([1.], dtype='float32')) + with pytest.raises(TypeError) as excinfo: + m.overloaded3(np.array([1], dtype='complex')) + assert msg(excinfo.value) == expected_exc + repr(np.array([1. + 0.j])) + + # Exact matches: + assert m.overloaded4(np.array([1], dtype='double')) == 'double' + assert m.overloaded4(np.array([1], dtype='longlong')) == 'long long' + # Non-exact matches requiring conversion. Since float to integer isn't a + # save conversion, it should go to the double overload, but short can go to + # either (and so should end up on the first-registered, the long long). + assert m.overloaded4(np.array([1], dtype='float32')) == 'double' + assert m.overloaded4(np.array([1], dtype='short')) == 'long long' + + assert m.overloaded5(np.array([1], dtype='double')) == 'double' + assert m.overloaded5(np.array([1], dtype='uintc')) == 'unsigned int' + assert m.overloaded5(np.array([1], dtype='float32')) == 'unsigned int' + + +def test_greedy_string_overload(): + """Tests fix for #685 - ndarray shouldn't go to std::string overload""" + + assert m.issue685("abc") == "string" + assert m.issue685(np.array([97, 98, 99], dtype='b')) == "array" + assert m.issue685(123) == "other" + + +def test_array_unchecked_fixed_dims(msg): + z1 = np.array([[1, 2], [3, 4]], dtype='float64') + m.proxy_add2(z1, 10) + assert np.all(z1 == [[11, 12], [13, 14]]) + + with pytest.raises(ValueError) as excinfo: + m.proxy_add2(np.array([1., 2, 3]), 5.0) + assert msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2" + + expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int') + assert np.all(m.proxy_init3(3.0) == expect_c) + expect_f = np.transpose(expect_c) + assert np.all(m.proxy_init3F(3.0) == expect_f) + + assert m.proxy_squared_L2_norm(np.array(range(6))) == 55 + assert m.proxy_squared_L2_norm(np.array(range(6), dtype="float64")) == 55 + + assert m.proxy_auxiliaries2(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32] + assert m.proxy_auxiliaries2(z1) == m.array_auxiliaries2(z1) + + +def test_array_unchecked_dyn_dims(msg): + z1 = np.array([[1, 2], [3, 4]], dtype='float64') + m.proxy_add2_dyn(z1, 10) + assert np.all(z1 == [[11, 12], [13, 14]]) + + expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int') + assert np.all(m.proxy_init3_dyn(3.0) == expect_c) + + assert m.proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32] + assert m.proxy_auxiliaries2_dyn(z1) == m.array_auxiliaries2(z1) + + +def test_array_failure(): + with pytest.raises(ValueError) as excinfo: + m.array_fail_test() + assert str(excinfo.value) == 'cannot create a pybind11::array from a nullptr' + + with pytest.raises(ValueError) as excinfo: + m.array_t_fail_test() + assert str(excinfo.value) == 'cannot create a pybind11::array_t from a nullptr' + + with pytest.raises(ValueError) as excinfo: + m.array_fail_test_negative_size() + assert str(excinfo.value) == 'negative dimensions are not allowed' + + +def test_initializer_list(): + assert m.array_initializer_list1().shape == (1,) + assert m.array_initializer_list2().shape == (1, 2) + assert m.array_initializer_list3().shape == (1, 2, 3) + assert m.array_initializer_list4().shape == (1, 2, 3, 4) + + +def test_array_resize(msg): + a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype='float64') + m.array_reshape2(a) + assert(a.size == 9) + assert(np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]])) + + # total size change should succced with refcheck off + m.array_resize3(a, 4, False) + assert(a.size == 64) + # ... and fail with refcheck on + try: + m.array_resize3(a, 3, True) + except ValueError as e: + assert(str(e).startswith("cannot resize an array")) + # transposed array doesn't own data + b = a.transpose() + try: + m.array_resize3(b, 3, False) + except ValueError as e: + assert(str(e).startswith("cannot resize this array: it does not own its data")) + # ... but reshape should be fine + m.array_reshape2(b) + assert(b.shape == (8, 8)) + + +@pytest.unsupported_on_pypy +def test_array_create_and_resize(msg): + a = m.create_and_resize(2) + assert(a.size == 4) + assert(np.all(a == 42.)) + + +@pytest.unsupported_on_py2 +def test_index_using_ellipsis(): + a = m.index_using_ellipsis(np.zeros((5, 6, 7))) + assert a.shape == (6,) diff --git a/pybind11/tests/test_numpy_dtypes.cpp b/pybind11/tests/test_numpy_dtypes.cpp new file mode 100644 index 0000000..6e3dc6b --- /dev/null +++ b/pybind11/tests/test_numpy_dtypes.cpp @@ -0,0 +1,466 @@ +/* + 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 bool_; + uint32_t uint_; + float float_; + long double ldbl_; +}; + +std::ostream& operator<<(std::ostream& os, const SimpleStruct& v) { + return os << "s:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_; +} + +PYBIND11_PACKED(struct PackedStruct { + bool bool_; + uint32_t uint_; + float float_; + long double ldbl_; +}); + +std::ostream& operator<<(std::ostream& os, const PackedStruct& v) { + return os << "p:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_; +} + +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 bool_; + uint32_t uint_; + float float_; + uint64_t dummy2; + long double ldbl_; +}; + +struct PartialNestedStruct { + uint64_t dummy1; + PartialStruct a; + uint64_t dummy2; +}; + +struct UnboundStruct { }; + +struct StringStruct { + char a[3]; + std::array b; +}; + +struct ComplexStruct { + std::complex cflt; + std::complex cdbl; +}; + +std::ostream& operator<<(std::ostream& os, const ComplexStruct& v) { + return os << "c:" << v.cflt << "," << v.cdbl; +} + +struct ArrayStruct { + char a[3][4]; + int32_t b[2]; + std::array c; + std::array d[4]; +}; + +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 ArrayStruct& v) { + os << "a={"; + for (int i = 0; i < 3; i++) { + if (i > 0) + os << ','; + os << '{'; + for (int j = 0; j < 3; j++) + os << v.a[i][j] << ','; + os << v.a[i][3] << '}'; + } + os << "},b={" << v.b[0] << ',' << v.b[1]; + os << "},c={" << int(v.c[0]) << ',' << int(v.c[1]) << ',' << int(v.c[2]); + os << "},d={"; + for (int i = 0; i < 4; i++) { + if (i > 0) + os << ','; + os << '{' << v.d[i][0] << ',' << v.d[i][1] << '}'; + } + 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) })); +} + +#define SET_TEST_VALS(s, i) do { \ + s.bool_ = (i) % 2 != 0; \ + s.uint_ = (uint32_t) (i); \ + s.float_ = (float) (i) * 1.5f; \ + s.ldbl_ = (long double) (i) * -2.5L; } while (0) + +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++) { + SET_TEST_VALS(ptr[i], i); + } + 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 (ssize_t i = 0; i < req.size; i++) { + std::stringstream ss; + ss << ptr[i]; + l.append(py::str(ss.str())); + } + 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 A {}; +struct B {}; + +TEST_SUBMODULE(numpy_dtypes, 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, bool_, uint_, float_, ldbl_); + PYBIND11_NUMPY_DTYPE(PackedStruct, bool_, uint_, float_, ldbl_); + PYBIND11_NUMPY_DTYPE(NestedStruct, a, b); + PYBIND11_NUMPY_DTYPE(PartialStruct, bool_, uint_, float_, ldbl_); + PYBIND11_NUMPY_DTYPE(PartialNestedStruct, a); + PYBIND11_NUMPY_DTYPE(StringStruct, a, b); + PYBIND11_NUMPY_DTYPE(ArrayStruct, a, b, c, d); + PYBIND11_NUMPY_DTYPE(EnumStruct, e1, e2); + PYBIND11_NUMPY_DTYPE(ComplexStruct, cflt, cdbl); + + // ... or after + py::class_(m, "PackedStruct"); + + PYBIND11_NUMPY_DTYPE_EX(StructWithUglyNames, __x__, "x", __y__, "y"); + + // If uncommented, this should produce a static_assert failure telling the user that the struct + // is not a POD type +// struct NotPOD { std::string v; NotPOD() : v("hi") {}; }; +// PYBIND11_NUMPY_DTYPE(NotPOD, v); + + // Check that dtypes can be registered programmatically, both from + // initializer lists of field descriptors and from other containers. + py::detail::npy_format_descriptor::register_dtype( + {} + ); + py::detail::npy_format_descriptor::register_dtype( + std::vector{} + ); + + // test_recarray, test_scalar_conversion + m.def("create_rec_simple", &create_recarray); + m.def("create_rec_packed", &create_recarray); + m.def("create_rec_nested", [](size_t n) { // test_signature + py::array_t arr = mkarray_via_buffer(n); + auto req = arr.request(); + auto ptr = static_cast(req.ptr); + for (size_t i = 0; i < n; i++) { + SET_TEST_VALS(ptr[i].a, i); + SET_TEST_VALS(ptr[i].b, i + 1); + } + return arr; + }); + m.def("create_rec_partial", &create_recarray); + m.def("create_rec_partial_nested", [](size_t n) { + py::array_t arr = mkarray_via_buffer(n); + auto req = arr.request(); + auto ptr = static_cast(req.ptr); + for (size_t i = 0; i < n; i++) { + SET_TEST_VALS(ptr[i].a, i); + } + return arr; + }); + m.def("print_rec_simple", &print_recarray); + m.def("print_rec_packed", &print_recarray); + m.def("print_rec_nested", &print_recarray); + + // test_format_descriptors + m.def("get_format_unbound", []() { return py::format_descriptor::format(); }); + m.def("print_format_descriptors", []() { + py::list l; + for (const auto &fmt : { + 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(), + py::format_descriptor::format(), + py::format_descriptor::format() + }) { + l.append(py::cast(fmt)); + } + return l; + }); + + // test_dtype + m.def("print_dtypes", []() { + py::list l; + for (const py::handle &d : { + py::dtype::of(), + py::dtype::of(), + py::dtype::of(), + py::dtype::of(), + py::dtype::of(), + py::dtype::of(), + py::dtype::of(), + py::dtype::of(), + py::dtype::of(), + py::dtype::of() + }) + l.append(py::str(d)); + return l; + }); + m.def("test_dtype_ctors", &test_dtype_ctors); + m.def("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; + }); + struct TrailingPaddingStruct { + int32_t a; + char b; + }; + PYBIND11_NUMPY_DTYPE(TrailingPaddingStruct, a, b); + m.def("trailing_padding_dtype", []() { return py::dtype::of(); }); + + // test_string_array + m.def("create_string_array", [](bool non_empty) { + py::array_t arr = mkarray_via_buffer(non_empty ? 4 : 0); + if (non_empty) { + auto req = arr.request(); + auto ptr = static_cast(req.ptr); + for (ssize_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; + }); + m.def("print_string_array", &print_recarray); + + // test_array_array + m.def("create_array_array", [](size_t n) { + py::array_t arr = mkarray_via_buffer(n); + auto ptr = (ArrayStruct *) arr.mutable_data(); + for (size_t i = 0; i < n; i++) { + for (size_t j = 0; j < 3; j++) + for (size_t k = 0; k < 4; k++) + ptr[i].a[j][k] = char('A' + (i * 100 + j * 10 + k) % 26); + for (size_t j = 0; j < 2; j++) + ptr[i].b[j] = int32_t(i * 1000 + j); + for (size_t j = 0; j < 3; j++) + ptr[i].c[j] = uint8_t(i * 10 + j); + for (size_t j = 0; j < 4; j++) + for (size_t k = 0; k < 2; k++) + ptr[i].d[j][k] = float(i) * 100.0f + float(j) * 10.0f + float(k); + } + return arr; + }); + m.def("print_array_array", &print_recarray); + + // test_enum_array + m.def("create_enum_array", [](size_t n) { + py::array_t 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; + }); + m.def("print_enum_array", &print_recarray); + + // test_complex_array + m.def("create_complex_array", [](size_t n) { + py::array_t arr = mkarray_via_buffer(n); + auto ptr = (ComplexStruct *) arr.mutable_data(); + for (size_t i = 0; i < n; i++) { + ptr[i].cflt.real(float(i)); + ptr[i].cflt.imag(float(i) + 0.25f); + ptr[i].cdbl.real(double(i) + 0.5); + ptr[i].cdbl.imag(double(i) + 0.75); + } + return arr; + }); + m.def("print_complex_array", &print_recarray); + + // test_array_constructors + m.def("test_array_ctors", &test_array_ctors); + + // test_compare_buffer_info + struct CompareStruct { + bool x; + uint32_t y; + float z; + }; + PYBIND11_NUMPY_DTYPE(CompareStruct, x, y, z); + m.def("compare_buffer_info", []() { + py::list list; + list.append(py::bool_(py::detail::compare_buffer_info::compare(py::buffer_info(nullptr, sizeof(float), "f", 1)))); + list.append(py::bool_(py::detail::compare_buffer_info::compare(py::buffer_info(nullptr, sizeof(int), "I", 1)))); + list.append(py::bool_(py::detail::compare_buffer_info::compare(py::buffer_info(nullptr, sizeof(long), "l", 1)))); + list.append(py::bool_(py::detail::compare_buffer_info::compare(py::buffer_info(nullptr, sizeof(long), sizeof(long) == sizeof(int) ? "i" : "q", 1)))); + list.append(py::bool_(py::detail::compare_buffer_info::compare(py::buffer_info(nullptr, sizeof(CompareStruct), "T{?:x:3xI:y:f:z:}", 1)))); + return list; + }); + m.def("buffer_to_dtype", [](py::buffer& buf) { return py::dtype(buf.request()); }); + + // test_scalar_conversion + m.def("f_simple", [](SimpleStruct s) { return s.uint_ * 10; }); + m.def("f_packed", [](PackedStruct s) { return s.uint_ * 10; }); + m.def("f_nested", [](NestedStruct s) { return s.a.uint_ * 10; }); + + // test_register_dtype + m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); }); + + // test_str_leak + m.def("dtype_wrapper", [](py::object d) { return py::dtype::from_args(std::move(d)); }); +} diff --git a/pybind11/tests/test_numpy_dtypes.py b/pybind11/tests/test_numpy_dtypes.py new file mode 100644 index 0000000..2e63885 --- /dev/null +++ b/pybind11/tests/test_numpy_dtypes.py @@ -0,0 +1,310 @@ +import re +import pytest +from pybind11_tests import numpy_dtypes as m + +pytestmark = pytest.requires_numpy + +with pytest.suppress(ImportError): + import numpy as np + + +@pytest.fixture(scope='module') +def simple_dtype(): + ld = np.dtype('longdouble') + return np.dtype({'names': ['bool_', 'uint_', 'float_', 'ldbl_'], + 'formats': ['?', 'u4', 'f4', 'f{}'.format(ld.itemsize)], + 'offsets': [0, 4, 8, (16 if ld.alignment > 4 else 12)]}) + + +@pytest.fixture(scope='module') +def packed_dtype(): + return np.dtype([('bool_', '?'), ('uint_', 'u4'), ('float_', 'f4'), ('ldbl_', 'g')]) + + +def dt_fmt(): + from sys import byteorder + e = '<' if byteorder == 'little' else '>' + return ("{{'names':['bool_','uint_','float_','ldbl_']," + " 'formats':['?','" + e + "u4','" + e + "f4','" + e + "f{}']," + " 'offsets':[0,4,8,{}], 'itemsize':{}}}") + + +def simple_dtype_fmt(): + ld = np.dtype('longdouble') + simple_ld_off = 12 + 4 * (ld.alignment > 4) + return dt_fmt().format(ld.itemsize, simple_ld_off, simple_ld_off + ld.itemsize) + + +def packed_dtype_fmt(): + from sys import byteorder + return "[('bool_', '?'), ('uint_', '{e}u4'), ('float_', '{e}f4'), ('ldbl_', '{e}f{}')]".format( + np.dtype('longdouble').itemsize, e='<' if byteorder == 'little' else '>') + + +def partial_ld_offset(): + return 12 + 4 * (np.dtype('uint64').alignment > 4) + 8 + 8 * ( + np.dtype('longdouble').alignment > 8) + + +def partial_dtype_fmt(): + ld = np.dtype('longdouble') + partial_ld_off = partial_ld_offset() + return dt_fmt().format(ld.itemsize, partial_ld_off, partial_ld_off + ld.itemsize) + + +def partial_nested_fmt(): + ld = np.dtype('longdouble') + partial_nested_off = 8 + 8 * (ld.alignment > 8) + partial_ld_off = partial_ld_offset() + partial_nested_size = partial_nested_off * 2 + partial_ld_off + ld.itemsize + return "{{'names':['a'], 'formats':[{}], 'offsets':[{}], 'itemsize':{}}}".format( + partial_dtype_fmt(), partial_nested_off, partial_nested_size) + + +def assert_equal(actual, expected_data, expected_dtype): + np.testing.assert_equal(actual, np.array(expected_data, dtype=expected_dtype)) + + +def test_format_descriptors(): + with pytest.raises(RuntimeError) as excinfo: + m.get_format_unbound() + assert re.match('^NumPy type info missing for .*UnboundStruct.*$', str(excinfo.value)) + + ld = np.dtype('longdouble') + ldbl_fmt = ('4x' if ld.alignment > 4 else '') + ld.char + ss_fmt = "^T{?:bool_:3xI:uint_:f:float_:" + ldbl_fmt + ":ldbl_:}" + dbl = np.dtype('double') + partial_fmt = ("^T{?:bool_:3xI:uint_:f:float_:" + + str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8)) + + "xg:ldbl_:}") + nested_extra = str(max(8, ld.alignment)) + assert m.print_format_descriptors() == [ + ss_fmt, + "^T{?:bool_:I:uint_:f:float_:g:ldbl_:}", + "^T{" + ss_fmt + ":a:^T{?:bool_:I:uint_:f:float_:g:ldbl_:}:b:}", + partial_fmt, + "^T{" + nested_extra + "x" + partial_fmt + ":a:" + nested_extra + "x}", + "^T{3s:a:3s:b:}", + "^T{(3)4s:a:(2)i:b:(3)B:c:1x(4, 2)f:d:}", + '^T{q:e1:B:e2:}', + '^T{Zf:cflt:Zd:cdbl:}' + ] + + +def test_dtype(simple_dtype): + from sys import byteorder + e = '<' if byteorder == 'little' else '>' + + assert m.print_dtypes() == [ + simple_dtype_fmt(), + packed_dtype_fmt(), + "[('a', {}), ('b', {})]".format(simple_dtype_fmt(), packed_dtype_fmt()), + partial_dtype_fmt(), + partial_nested_fmt(), + "[('a', 'S3'), ('b', 'S3')]", + ("{{'names':['a','b','c','d'], " + + "'formats':[('S4', (3,)),('" + e + "i4', (2,)),('u1', (3,)),('" + e + "f4', (4, 2))], " + + "'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e), + "[('e1', '" + e + "i8'), ('e2', 'u1')]", + "[('x', 'i1'), ('y', '" + e + "u8')]", + "[('cflt', '" + e + "c8'), ('cdbl', '" + e + "c16')]" + ] + + d1 = np.dtype({'names': ['a', 'b'], 'formats': ['int32', 'float64'], + 'offsets': [1, 10], 'itemsize': 20}) + d2 = np.dtype([('a', 'i4'), ('b', 'f4')]) + assert m.test_dtype_ctors() == [np.dtype('int32'), np.dtype('float64'), + np.dtype('bool'), d1, d1, np.dtype('uint32'), d2] + + assert m.test_dtype_methods() == [np.dtype('int32'), simple_dtype, False, True, + np.dtype('int32').itemsize, simple_dtype.itemsize] + + assert m.trailing_padding_dtype() == m.buffer_to_dtype(np.zeros(1, m.trailing_padding_dtype())) + + +def test_recarray(simple_dtype, packed_dtype): + elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)] + + for func, dtype in [(m.create_rec_simple, simple_dtype), (m.create_rec_packed, packed_dtype)]: + arr = func(0) + assert arr.dtype == dtype + assert_equal(arr, [], simple_dtype) + assert_equal(arr, [], packed_dtype) + + arr = func(3) + assert arr.dtype == dtype + assert_equal(arr, elements, simple_dtype) + assert_equal(arr, elements, packed_dtype) + + if dtype == simple_dtype: + assert m.print_rec_simple(arr) == [ + "s:0,0,0,-0", + "s:1,1,1.5,-2.5", + "s:0,2,3,-5" + ] + else: + assert m.print_rec_packed(arr) == [ + "p:0,0,0,-0", + "p:1,1,1.5,-2.5", + "p:0,2,3,-5" + ] + + nested_dtype = np.dtype([('a', simple_dtype), ('b', packed_dtype)]) + + arr = m.create_rec_nested(0) + assert arr.dtype == nested_dtype + assert_equal(arr, [], nested_dtype) + + arr = m.create_rec_nested(3) + assert arr.dtype == nested_dtype + assert_equal(arr, [((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)), + ((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)), + ((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5))], nested_dtype) + assert m.print_rec_nested(arr) == [ + "n:a=s:0,0,0,-0;b=p:1,1,1.5,-2.5", + "n:a=s:1,1,1.5,-2.5;b=p:0,2,3,-5", + "n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5" + ] + + arr = m.create_rec_partial(3) + assert str(arr.dtype) == partial_dtype_fmt() + partial_dtype = arr.dtype + assert '' not in arr.dtype.fields + assert partial_dtype.itemsize > simple_dtype.itemsize + assert_equal(arr, elements, simple_dtype) + assert_equal(arr, elements, packed_dtype) + + arr = m.create_rec_partial_nested(3) + assert str(arr.dtype) == partial_nested_fmt() + assert '' not in arr.dtype.fields + assert '' not in arr.dtype.fields['a'][0].fields + assert arr.dtype.itemsize > partial_dtype.itemsize + np.testing.assert_equal(arr['a'], m.create_rec_partial(3)) + + +def test_array_constructors(): + data = np.arange(1, 7, dtype='int32') + for i in range(8): + np.testing.assert_array_equal(m.test_array_ctors(10 + i), data.reshape((3, 2))) + np.testing.assert_array_equal(m.test_array_ctors(20 + i), data.reshape((3, 2))) + for i in range(5): + np.testing.assert_array_equal(m.test_array_ctors(30 + i), data) + np.testing.assert_array_equal(m.test_array_ctors(40 + i), data) + + +def test_string_array(): + arr = m.create_string_array(True) + assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]" + assert m.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 = m.create_string_array(False) + assert dtype == arr.dtype + + +def test_array_array(): + from sys import byteorder + e = '<' if byteorder == 'little' else '>' + + arr = m.create_array_array(3) + assert str(arr.dtype) == ( + "{{'names':['a','b','c','d'], " + + "'formats':[('S4', (3,)),('" + e + "i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], " + + "'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e) + assert m.print_array_array(arr) == [ + "a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1}," + + "c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}", + "a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001}," + + "c={10,11,12},d={{100,101},{110,111},{120,121},{130,131}}", + "a={{S,T,U,V},{C,D,E,F},{M,N,O,P}},b={2000,2001}," + + "c={20,21,22},d={{200,201},{210,211},{220,221},{230,231}}", + ] + assert arr['a'].tolist() == [[b'ABCD', b'KLMN', b'UVWX'], + [b'WXYZ', b'GHIJ', b'QRST'], + [b'STUV', b'CDEF', b'MNOP']] + assert arr['b'].tolist() == [[0, 1], [1000, 1001], [2000, 2001]] + assert m.create_array_array(0).dtype == arr.dtype + + +def test_enum_array(): + from sys import byteorder + e = '<' if byteorder == 'little' else '>' + + arr = m.create_enum_array(3) + dtype = arr.dtype + assert dtype == np.dtype([('e1', e + 'i8'), ('e2', 'u1')]) + assert m.print_enum_array(arr) == [ + "e1=A,e2=X", + "e1=B,e2=Y", + "e1=A,e2=X" + ] + assert arr['e1'].tolist() == [-1, 1, -1] + assert arr['e2'].tolist() == [1, 2, 1] + assert m.create_enum_array(0).dtype == dtype + + +def test_complex_array(): + from sys import byteorder + e = '<' if byteorder == 'little' else '>' + + arr = m.create_complex_array(3) + dtype = arr.dtype + assert dtype == np.dtype([('cflt', e + 'c8'), ('cdbl', e + 'c16')]) + assert m.print_complex_array(arr) == [ + "c:(0,0.25),(0.5,0.75)", + "c:(1,1.25),(1.5,1.75)", + "c:(2,2.25),(2.5,2.75)" + ] + assert arr['cflt'].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j] + assert arr['cdbl'].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j] + assert m.create_complex_array(0).dtype == dtype + + +def test_signature(doc): + assert doc(m.create_rec_nested) == \ + "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]" + + +def test_scalar_conversion(): + n = 3 + arrays = [m.create_rec_simple(n), m.create_rec_packed(n), + m.create_rec_nested(n), m.create_enum_array(n)] + funcs = [m.f_simple, m.f_packed, m.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) + + +def test_register_dtype(): + with pytest.raises(RuntimeError) as excinfo: + m.register_dtype() + assert 'dtype is already registered' in str(excinfo.value) + + +@pytest.unsupported_on_pypy +def test_str_leak(): + from sys import getrefcount + fmt = "f4" + pytest.gc_collect() + start = getrefcount(fmt) + d = m.dtype_wrapper(fmt) + assert d is np.dtype("f4") + del d + pytest.gc_collect() + assert getrefcount(fmt) == start + + +def test_compare_buffer_info(): + assert all(m.compare_buffer_info()) diff --git a/pybind11/tests/test_numpy_vectorize.cpp b/pybind11/tests/test_numpy_vectorize.cpp new file mode 100644 index 0000000..a875a74 --- /dev/null +++ b/pybind11/tests/test_numpy_vectorize.cpp @@ -0,0 +1,89 @@ +/* + 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; +} + +TEST_SUBMODULE(numpy_vectorize, m) { + try { py::module::import("numpy"); } + catch (...) { return; } + + // test_vectorize, test_docs, test_array_collapse + // 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( + [](std::complex c) { return c * std::complex(2.f); } + )); + + // test_type_selection + // 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."; }); + + + // test_passthrough_arguments + // Passthrough test: references and non-pod types should be automatically passed through (in the + // function definition below, only `b`, `d`, and `g` are vectorized): + struct NonPODClass { + NonPODClass(int v) : value{v} {} + int value; + }; + py::class_(m, "NonPODClass").def(py::init()); + m.def("vec_passthrough", py::vectorize( + [](double *a, double b, py::array_t c, const int &d, int &e, NonPODClass f, const double g) { + return *a + b + c.at(0) + d + e + f.value + g; + } + )); + + // test_method_vectorization + struct VectorizeTestClass { + VectorizeTestClass(int v) : value{v} {}; + float method(int x, float y) { return y + (float) (x + value); } + int value = 0; + }; + py::class_ vtc(m, "VectorizeTestClass"); + vtc .def(py::init()) + .def_readwrite("value", &VectorizeTestClass::value); + + // Automatic vectorizing of methods + vtc.def("method", py::vectorize(&VectorizeTestClass::method)); + + // test_trivial_broadcasting + // Internal optimization test for whether the input is trivially broadcastable: + py::enum_(m, "trivial") + .value("f_trivial", py::detail::broadcast_trivial::f_trivial) + .value("c_trivial", py::detail::broadcast_trivial::c_trivial) + .value("non_trivial", py::detail::broadcast_trivial::non_trivial); + m.def("vectorized_is_trivial", []( + py::array_t arg1, + py::array_t arg2, + py::array_t arg3 + ) { + ssize_t ndim; + std::vector shape; + std::array buffers {{ arg1.request(), arg2.request(), arg3.request() }}; + return py::detail::broadcast(buffers, ndim, shape); + }); +} diff --git a/pybind11/tests/test_numpy_vectorize.py b/pybind11/tests/test_numpy_vectorize.py new file mode 100644 index 0000000..0e9c883 --- /dev/null +++ b/pybind11/tests/test_numpy_vectorize.py @@ -0,0 +1,196 @@ +import pytest +from pybind11_tests import numpy_vectorize as m + +pytestmark = pytest.requires_numpy + +with pytest.suppress(ImportError): + import numpy as np + + +def test_vectorize(capture): + assert np.isclose(m.vectorized_func3(np.array(3 + 7j)), [6 + 14j]) + + for f in [m.vectorized_func, m.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 = np.array([[1, 2], [3, 4]], order='F') + b = np.array([[10, 20], [30, 40]], order='F') + c = 3 + result = f(a, b, c) + assert np.allclose(result, a * b * c) + assert result.flags.f_contiguous + # All inputs are F order and full or singletons, so we the result is in col-major order: + assert capture == """ + my_func(x:int=1, y:float=10, z:float=3) + my_func(x:int=3, y:float=30, z:float=3) + my_func(x:int=2, y:float=20, z:float=3) + my_func(x:int=4, y:float=40, 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) + """ + with capture: + a, b, c = np.array([[1, 2, 3], [4, 5, 6]], order='F'), 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) + """ + with capture: + a, b, c = np.array([[1, 2, 3], [4, 5, 6]])[::, ::2], 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=3, y:float=2, z:float=2) + my_func(x:int=4, y:float=3, z:float=2) + my_func(x:int=6, y:float=3, z:float=2) + """ + with capture: + a, b, c = np.array([[1, 2, 3], [4, 5, 6]], order='F')[::, ::2], 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=3, y:float=2, z:float=2) + my_func(x:int=4, y:float=3, z:float=2) + my_func(x:int=6, y:float=3, z:float=2) + """ + + +def test_type_selection(): + assert m.selective_func(np.array([1], dtype=np.int32)) == "Int branch taken." + assert m.selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken." + assert m.selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken." + + +def test_docs(doc): + assert doc(m.vectorized_func) == """ + vectorized_func(arg0: numpy.ndarray[int32], arg1: numpy.ndarray[float32], arg2: numpy.ndarray[float64]) -> object + """ # noqa: E501 line too long + + +def test_trivial_broadcasting(): + trivial, vectorized_is_trivial = m.trivial, m.vectorized_is_trivial + + assert vectorized_is_trivial(1, 2, 3) == trivial.c_trivial + assert vectorized_is_trivial(np.array(1), np.array(2), 3) == trivial.c_trivial + assert vectorized_is_trivial(np.array([1, 3]), np.array([2, 4]), 3) == trivial.c_trivial + assert trivial.c_trivial == vectorized_is_trivial( + np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3) + assert vectorized_is_trivial( + np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2) == trivial.non_trivial + assert vectorized_is_trivial( + np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2) == trivial.non_trivial + z1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype='int32') + z2 = np.array(z1, dtype='float32') + z3 = np.array(z1, dtype='float64') + assert vectorized_is_trivial(z1, z2, z3) == trivial.c_trivial + assert vectorized_is_trivial(1, z2, z3) == trivial.c_trivial + assert vectorized_is_trivial(z1, 1, z3) == trivial.c_trivial + assert vectorized_is_trivial(z1, z2, 1) == trivial.c_trivial + assert vectorized_is_trivial(z1[::2, ::2], 1, 1) == trivial.non_trivial + assert vectorized_is_trivial(1, 1, z1[::2, ::2]) == trivial.c_trivial + assert vectorized_is_trivial(1, 1, z3[::2, ::2]) == trivial.non_trivial + assert vectorized_is_trivial(z1, 1, z3[1::4, 1::4]) == trivial.c_trivial + + y1 = np.array(z1, order='F') + y2 = np.array(y1) + y3 = np.array(y1) + assert vectorized_is_trivial(y1, y2, y3) == trivial.f_trivial + assert vectorized_is_trivial(y1, 1, 1) == trivial.f_trivial + assert vectorized_is_trivial(1, y2, 1) == trivial.f_trivial + assert vectorized_is_trivial(1, 1, y3) == trivial.f_trivial + assert vectorized_is_trivial(y1, z2, 1) == trivial.non_trivial + assert vectorized_is_trivial(z1[1::4, 1::4], y2, 1) == trivial.f_trivial + assert vectorized_is_trivial(y1[1::4, 1::4], z2, 1) == trivial.c_trivial + + assert m.vectorized_func(z1, z2, z3).flags.c_contiguous + assert m.vectorized_func(y1, y2, y3).flags.f_contiguous + assert m.vectorized_func(z1, 1, 1).flags.c_contiguous + assert m.vectorized_func(1, y2, 1).flags.f_contiguous + assert m.vectorized_func(z1[1::4, 1::4], y2, 1).flags.f_contiguous + assert m.vectorized_func(y1[1::4, 1::4], z2, 1).flags.c_contiguous + + +def test_passthrough_arguments(doc): + assert doc(m.vec_passthrough) == ( + "vec_passthrough(" + ", ".join([ + "arg0: float", + "arg1: numpy.ndarray[float64]", + "arg2: numpy.ndarray[float64]", + "arg3: numpy.ndarray[int32]", + "arg4: int", + "arg5: m.numpy_vectorize.NonPODClass", + "arg6: numpy.ndarray[float64]"]) + ") -> object") + + b = np.array([[10, 20, 30]], dtype='float64') + c = np.array([100, 200]) # NOT a vectorized argument + d = np.array([[1000], [2000], [3000]], dtype='int') + g = np.array([[1000000, 2000000, 3000000]], dtype='int') # requires casting + assert np.all( + m.vec_passthrough(1, b, c, d, 10000, m.NonPODClass(100000), g) == + np.array([[1111111, 2111121, 3111131], + [1112111, 2112121, 3112131], + [1113111, 2113121, 3113131]])) + + +def test_method_vectorization(): + o = m.VectorizeTestClass(3) + x = np.array([1, 2], dtype='int') + y = np.array([[10], [20]], dtype='float32') + assert np.all(o.method(x, y) == [[14, 15], [24, 25]]) + + +def test_array_collapse(): + assert not isinstance(m.vectorized_func(1, 2, 3), np.ndarray) + assert not isinstance(m.vectorized_func(np.array(1), 2, 3), np.ndarray) + z = m.vectorized_func([1], 2, 3) + assert isinstance(z, np.ndarray) + assert z.shape == (1, ) + z = m.vectorized_func(1, [[[2]]], 3) + assert isinstance(z, np.ndarray) + assert z.shape == (1, 1, 1) diff --git a/pybind11/tests/test_opaque_types.cpp b/pybind11/tests/test_opaque_types.cpp new file mode 100644 index 0000000..0d20d9a --- /dev/null +++ b/pybind11/tests/test_opaque_types.cpp @@ -0,0 +1,67 @@ +/* + 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 + +// IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures +// +// This also deliberately doesn't use the below StringList type alias to test +// that MAKE_OPAQUE can handle a type containing a `,`. (The `std::allocator` +// bit is just the default `std::vector` allocator). +PYBIND11_MAKE_OPAQUE(std::vector>); + +using StringList = std::vector>; + +TEST_SUBMODULE(opaque_types, m) { + // test_string_list + 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>()); + + class ClassWithSTLVecProperty { + public: + StringList stringList; + }; + 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 + "]"; + }); + + // test_pointers + 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/pybind11/tests/test_opaque_types.py b/pybind11/tests/test_opaque_types.py new file mode 100644 index 0000000..6b3802f --- /dev/null +++ b/pybind11/tests/test_opaque_types.py @@ -0,0 +1,46 @@ +import pytest +from pybind11_tests import opaque_types as m +from pybind11_tests import ConstructorStats, UserType + + +def test_string_list(): + lst = m.StringList() + lst.push_back("Element 1") + lst.push_back("Element 2") + assert m.print_opaque_list(lst) == "Opaque list: [Element 1, Element 2]" + assert lst.back() == "Element 2" + + for i, k in enumerate(lst, start=1): + assert k == "Element {}".format(i) + lst.pop_back() + assert m.print_opaque_list(lst) == "Opaque list: [Element 1]" + + cvp = m.ClassWithSTLVecProperty() + assert m.print_opaque_list(cvp.stringList) == "Opaque list: []" + + cvp.stringList = lst + cvp.stringList.push_back("Element 3") + assert m.print_opaque_list(cvp.stringList) == "Opaque list: [Element 1, Element 3]" + + +def test_pointers(msg): + living_before = ConstructorStats.get(UserType).alive() + assert m.get_void_ptr_value(m.return_void_ptr()) == 0x1234 + assert m.get_void_ptr_value(UserType()) # Should also work for other C++ types + assert ConstructorStats.get(UserType).alive() == living_before + + with pytest.raises(TypeError) as excinfo: + m.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] + """ # noqa: E501 line too long + + assert m.return_null_str() is None + assert m.get_null_str_value(m.return_null_str()) is not None + + ptr = m.return_unique_ptr() + assert "StringList" in repr(ptr) + assert m.print_opaque_list(ptr) == "Opaque list: [some value]" diff --git a/pybind11/tests/test_operator_overloading.cpp b/pybind11/tests/test_operator_overloading.cpp new file mode 100644 index 0000000..4ad34d1 --- /dev/null +++ b/pybind11/tests/test_operator_overloading.cpp @@ -0,0 +1,146 @@ +/* + 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 +#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 &operator=(const Vector2 &v) { x = v.x; y = v.y; print_copy_assigned(this); return *this; } + Vector2 &operator=(Vector2 &&v) { x = v.x; y = v.y; v.x = v.y = 0; print_move_assigned(this); return *this; } + ~Vector2() { print_destroyed(this); } + + std::string toString() const { return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; } + + 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) 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+=(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; } + 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; } + + 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; +}; + +class C1 { }; +class C2 { }; + +int operator+(const C1 &, const C1 &) { return 11; } +int operator+(const C2 &, const C2 &) { return 22; } +int operator+(const C2 &, const C1 &) { return 21; } +int operator+(const C1 &, const C2 &) { return 12; } + +namespace std { + template<> + struct hash { + // Not a good hash function, but easy to test + size_t operator()(const Vector2 &) { return 4; } + }; +} + +TEST_SUBMODULE(operators, m) { + + // test_operator_overloading + 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 += py::self) + .def(py::self -= py::self) + .def(py::self *= float()) + .def(py::self /= float()) + .def(py::self *= py::self) + .def(py::self /= py::self) + .def(float() + py::self) + .def(float() - py::self) + .def(float() * py::self) + .def(float() / py::self) + .def("__str__", &Vector2::toString) + .def(hash(py::self)) + ; + + m.attr("Vector") = m.attr("Vector2"); + + // test_operators_notimplemented + // #393: need to return NotSupported to ensure correct arithmetic operator behavior + py::class_(m, "C1") + .def(py::init<>()) + .def(py::self + py::self); + + py::class_(m, "C2") + .def(py::init<>()) + .def(py::self + py::self) + .def("__add__", [](const C2& c2, const C1& c1) { return c2 + c1; }) + .def("__radd__", [](const C2& c2, const C1& c1) { return c1 + c2; }); + + // test_nested + // #328: first member in a class can't be used in operators + struct NestABase { int value = -2; }; + py::class_(m, "NestABase") + .def(py::init<>()) + .def_readwrite("value", &NestABase::value); + + struct NestA : NestABase { + int value = 3; + NestA& operator+=(int i) { value += i; return *this; } + }; + py::class_(m, "NestA") + .def(py::init<>()) + .def(py::self += int()) + .def("as_base", [](NestA &a) -> NestABase& { + return (NestABase&) a; + }, py::return_value_policy::reference_internal); + m.def("get_NestA", [](const NestA &a) { return a.value; }); + + struct NestB { + NestA a; + int value = 4; + NestB& operator-=(int i) { value -= i; return *this; } + }; + py::class_(m, "NestB") + .def(py::init<>()) + .def(py::self -= int()) + .def_readwrite("a", &NestB::a); + m.def("get_NestB", [](const NestB &b) { return b.value; }); + + struct NestC { + NestB b; + int value = 5; + NestC& operator*=(int i) { value *= i; return *this; } + }; + py::class_(m, "NestC") + .def(py::init<>()) + .def(py::self *= int()) + .def_readwrite("b", &NestC::b); + m.def("get_NestC", [](const NestC &c) { return c.value; }); +} diff --git a/pybind11/tests/test_operator_overloading.py b/pybind11/tests/test_operator_overloading.py new file mode 100644 index 0000000..86827d2 --- /dev/null +++ b/pybind11/tests/test_operator_overloading.py @@ -0,0 +1,106 @@ +import pytest +from pybind11_tests import operators as m +from pybind11_tests import ConstructorStats + + +def test_operator_overloading(): + v1 = m.Vector2(1, 2) + v2 = m.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]" + assert str(v1 * v2) == "[3.000000, -2.000000]" + assert str(v2 / v1) == "[3.000000, -0.500000]" + + v1 += 2 * v2 + assert str(v1) == "[7.000000, 0.000000]" + v1 -= v2 + assert str(v1) == "[4.000000, 1.000000]" + v1 *= 2 + assert str(v1) == "[8.000000, 2.000000]" + v1 /= 16 + assert str(v1) == "[0.500000, 0.125000]" + v1 *= v2 + assert str(v1) == "[1.500000, -0.125000]" + v2 /= v1 + assert str(v2) == "[2.000000, 8.000000]" + + assert hash(v1) == 4 + + cstats = ConstructorStats.get(m.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]', + '[3.000000, -2.000000]', '[3.000000, -0.500000]', + '[6.000000, -2.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 + + +def test_operators_notimplemented(): + """#393: need to return NotSupported to ensure correct arithmetic operator behavior""" + + c1, c2 = m.C1(), m.C2() + assert c1 + c1 == 11 + assert c2 + c2 == 22 + assert c2 + c1 == 21 + assert c1 + c2 == 12 + + +def test_nested(): + """#328: first member in a class can't be used in operators""" + + a = m.NestA() + b = m.NestB() + c = m.NestC() + + a += 10 + assert m.get_NestA(a) == 13 + b.a += 100 + assert m.get_NestA(b.a) == 103 + c.b.a += 1000 + assert m.get_NestA(c.b.a) == 1003 + b -= 1 + assert m.get_NestB(b) == 3 + c.b -= 3 + assert m.get_NestB(c.b) == 1 + c *= 7 + assert m.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 + pytest.gc_collect() + del a # Shouldn't delete while abase is still alive + pytest.gc_collect() + + assert abase.value == 42 + del abase, b + pytest.gc_collect() diff --git a/pybind11/tests/test_pickling.cpp b/pybind11/tests/test_pickling.cpp new file mode 100644 index 0000000..9dc63bd --- /dev/null +++ b/pybind11/tests/test_pickling.cpp @@ -0,0 +1,130 @@ +/* + 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" + +TEST_SUBMODULE(pickling, m) { + // test_roundtrip + 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 PickleableNew : public Pickleable { + public: + using Pickleable::Pickleable; + }; + + 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, "PickleableNew") + .def(py::init()) + .def(py::pickle( + [](const PickleableNew &p) { + return py::make_tuple(p.value(), p.extra1(), p.extra2()); + }, + [](py::tuple t) { + if (t.size() != 3) + throw std::runtime_error("Invalid state!"); + auto p = PickleableNew(t[0].cast()); + + p.setExtra1(t[1].cast()); + p.setExtra2(t[2].cast()); + return p; + } + )); + +#if !defined(PYPY_VERSION) + // test_roundtrip_with_dict + class PickleableWithDict { + public: + PickleableWithDict(const std::string &value) : value(value) { } + + std::string value; + int extra; + }; + + class PickleableWithDictNew : public PickleableWithDict { + public: + using PickleableWithDict::PickleableWithDict; + }; + + 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) PickleableWithDict(t[0].cast()); + + /* Assign C++ state */ + p.extra = t[1].cast(); + + /* Assign Python state */ + self.attr("__dict__") = t[2]; + }); + + py::class_(m, "PickleableWithDictNew") + .def(py::init()) + .def(py::pickle( + [](py::object self) { + return py::make_tuple(self.attr("value"), self.attr("extra"), self.attr("__dict__")); + }, + [](const py::tuple &t) { + if (t.size() != 3) + throw std::runtime_error("Invalid state!"); + + auto cpp_state = PickleableWithDictNew(t[0].cast()); + cpp_state.extra = t[1].cast(); + + auto py_state = t[2].cast(); + return std::make_pair(cpp_state, py_state); + } + )); +#endif +} diff --git a/pybind11/tests/test_pickling.py b/pybind11/tests/test_pickling.py new file mode 100644 index 0000000..5ae05aa --- /dev/null +++ b/pybind11/tests/test_pickling.py @@ -0,0 +1,42 @@ +import pytest +from pybind11_tests import pickling as m + +try: + import cPickle as pickle # Use cPickle on Python 2.7 +except ImportError: + import pickle + + +@pytest.mark.parametrize("cls_name", ["Pickleable", "PickleableNew"]) +def test_roundtrip(cls_name): + cls = getattr(m, cls_name) + p = cls("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() + + +@pytest.unsupported_on_pypy +@pytest.mark.parametrize("cls_name", ["PickleableWithDict", "PickleableWithDictNew"]) +def test_roundtrip_with_dict(cls_name): + cls = getattr(m, cls_name) + p = cls("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 + + +def test_enum_pickle(): + from pybind11_tests import enums as e + data = pickle.dumps(e.EOne, 2) + assert e.EOne == pickle.loads(data) diff --git a/pybind11/tests/test_pytypes.cpp b/pybind11/tests/test_pytypes.cpp new file mode 100644 index 0000000..e6c955f --- /dev/null +++ b/pybind11/tests/test_pytypes.cpp @@ -0,0 +1,296 @@ +/* + tests/test_pytypes.cpp -- Python type casters + + Copyright (c) 2017 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" + + +TEST_SUBMODULE(pytypes, m) { + // test_list + m.def("get_list", []() { + py::list list; + list.append("value"); + py::print("Entry at position 0:", list[0]); + list[0] = py::str("overwritten"); + return list; + }); + m.def("print_list", [](py::list list) { + int index = 0; + for (auto item : list) + py::print("list item {}: {}"_s.format(index++, item)); + }); + + // test_set + m.def("get_set", []() { + py::set set; + set.add(py::str("key1")); + set.add("key2"); + set.add(std::string("key3")); + return set; + }); + m.def("print_set", [](py::set set) { + for (auto item : set) + py::print("key:", item); + }); + + // test_dict + m.def("get_dict", []() { return py::dict("key"_a="value"); }); + m.def("print_dict", [](py::dict dict) { + for (auto item : dict) + py::print("key: {}, value={}"_s.format(item.first, item.second)); + }); + m.def("dict_keyword_constructor", []() { + auto d1 = py::dict("x"_a=1, "y"_a=2); + auto d2 = py::dict("z"_a=3, **d1); + return d2; + }); + + // test_str + m.def("str_from_string", []() { return py::str(std::string("baz")); }); + m.def("str_from_bytes", []() { return py::str(py::bytes("boo", 3)); }); + m.def("str_from_object", [](const py::object& obj) { return py::str(obj); }); + m.def("repr_from_object", [](const py::object& obj) { return py::repr(obj); }); + + m.def("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); + }); + + // test_bytes + m.def("bytes_from_string", []() { return py::bytes(std::string("foo")); }); + m.def("bytes_from_str", []() { return py::bytes(py::str("bar", 3)); }); + + // test_capsule + m.def("return_capsule_with_destructor", []() { + py::print("creating capsule"); + return py::capsule([]() { + py::print("destructing capsule"); + }); + }); + + m.def("return_capsule_with_destructor_2", []() { + py::print("creating capsule"); + return py::capsule((void *) 1234, [](void *ptr) { + py::print("destructing capsule: {}"_s.format((size_t) ptr)); + }); + }); + + m.def("return_capsule_with_name_and_destructor", []() { + auto capsule = py::capsule((void *) 1234, "pointer type description", [](PyObject *ptr) { + if (ptr) { + auto name = PyCapsule_GetName(ptr); + py::print("destructing capsule ({}, '{}')"_s.format( + (size_t) PyCapsule_GetPointer(ptr, name), name + )); + } + }); + void *contents = capsule; + py::print("created capsule ({}, '{}')"_s.format((size_t) contents, capsule.name())); + return capsule; + }); + + // test_accessors + m.def("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"] = o.attr("basic_attr").is_none(); + + d["operator()"] = o.attr("func")(1); + d["operator*"] = o.attr("func")(*o.attr("begin_end")); + + // Test implicit conversion + py::list implicit_list = o.attr("begin_end"); + d["implicit_list"] = implicit_list; + py::dict implicit_dict = o.attr("__dict__"); + d["implicit_dict"] = implicit_dict; + + return d; + }); + + m.def("tuple_accessor", [](py::tuple existing_t) { + try { + existing_t[0] = 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] = i; + } + return new_t; + } + return py::tuple(); + }); + + m.def("accessor_assignment", []() { + auto l = py::list(1); + l[0] = 0; + + auto d = py::dict(); + d["get"] = l[0]; + auto var = l[0]; + d["deferred_get"] = var; + l[0] = 1; + d["set"] = l[0]; + var = 99; // this assignment should not overwrite l[0] + d["deferred_set"] = l[0]; + d["var"] = var; + + return d; + }); + + // test_constructors + m.def("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("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("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() + ); + }); + + m.def("get_implicit_casting", []() { + py::dict d; + d["char*_i1"] = "abc"; + const char *c2 = "abc"; + d["char*_i2"] = c2; + d["char*_e"] = py::cast(c2); + d["char*_p"] = py::str(c2); + + d["int_i1"] = 42; + int i = 42; + d["int_i2"] = i; + i++; + d["int_e"] = py::cast(i); + i++; + d["int_p"] = py::int_(i); + + d["str_i1"] = std::string("str"); + std::string s2("str1"); + d["str_i2"] = s2; + s2[3] = '2'; + d["str_e"] = py::cast(s2); + s2[3] = '3'; + d["str_p"] = py::str(s2); + + py::list l(2); + l[0] = 3; + l[1] = py::cast(6); + l.append(9); + l.append(py::cast(12)); + l.append(py::int_(15)); + + return py::dict( + "d"_a=d, + "l"_a=l + ); + }); + + // test_print + m.def("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("print_failure", []() { py::print(42, UnregisteredType()); }); + + m.def("hash_function", [](py::object obj) { return py::hash(obj); }); + + m.def("test_number_protocol", [](py::object a, py::object b) { + py::list l; + l.append(a.equal(b)); + l.append(a.not_equal(b)); + l.append(a < b); + l.append(a <= b); + l.append(a > b); + l.append(a >= b); + l.append(a + b); + l.append(a - b); + l.append(a * b); + l.append(a / b); + l.append(a | b); + l.append(a & b); + l.append(a ^ b); + l.append(a >> b); + l.append(a << b); + return l; + }); + + m.def("test_list_slicing", [](py::list a) { + return a[py::slice(0, -1, 2)]; + }); +} diff --git a/pybind11/tests/test_pytypes.py b/pybind11/tests/test_pytypes.py new file mode 100644 index 0000000..0116d4e --- /dev/null +++ b/pybind11/tests/test_pytypes.py @@ -0,0 +1,253 @@ +from __future__ import division +import pytest +import sys + +from pybind11_tests import pytypes as m +from pybind11_tests import debug_enabled + + +def test_list(capture, doc): + with capture: + lst = m.get_list() + assert lst == ["overwritten"] + + lst.append("value2") + m.print_list(lst) + assert capture.unordered == """ + Entry at position 0: value + list item 0: overwritten + list item 1: value2 + """ + + assert doc(m.get_list) == "get_list() -> list" + assert doc(m.print_list) == "print_list(arg0: list) -> None" + + +def test_set(capture, doc): + s = m.get_set() + assert s == {"key1", "key2", "key3"} + + with capture: + s.add("key4") + m.print_set(s) + assert capture.unordered == """ + key: key1 + key: key2 + key: key3 + key: key4 + """ + + assert doc(m.get_list) == "get_list() -> list" + assert doc(m.print_list) == "print_list(arg0: list) -> None" + + +def test_dict(capture, doc): + d = m.get_dict() + assert d == {"key": "value"} + + with capture: + d["key2"] = "value2" + m.print_dict(d) + assert capture.unordered == """ + key: key, value=value + key: key2, value=value2 + """ + + assert doc(m.get_dict) == "get_dict() -> dict" + assert doc(m.print_dict) == "print_dict(arg0: dict) -> None" + + assert m.dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3} + + +def test_str(doc): + assert m.str_from_string().encode().decode() == "baz" + assert m.str_from_bytes().encode().decode() == "boo" + + assert doc(m.str_from_bytes) == "str_from_bytes() -> str" + + class A(object): + def __str__(self): + return "this is a str" + + def __repr__(self): + return "this is a repr" + + assert m.str_from_object(A()) == "this is a str" + assert m.repr_from_object(A()) == "this is a repr" + + s1, s2 = m.str_format() + assert s1 == "1 + 2 = 3" + assert s1 == s2 + + +def test_bytes(doc): + assert m.bytes_from_string().decode() == "foo" + assert m.bytes_from_str().decode() == "bar" + + assert doc(m.bytes_from_str) == "bytes_from_str() -> {}".format( + "bytes" if sys.version_info[0] == 3 else "str" + ) + + +def test_capsule(capture): + pytest.gc_collect() + with capture: + a = m.return_capsule_with_destructor() + del a + pytest.gc_collect() + assert capture.unordered == """ + creating capsule + destructing capsule + """ + + with capture: + a = m.return_capsule_with_destructor_2() + del a + pytest.gc_collect() + assert capture.unordered == """ + creating capsule + destructing capsule: 1234 + """ + + with capture: + a = m.return_capsule_with_name_and_destructor() + del a + pytest.gc_collect() + assert capture.unordered == """ + created capsule (1234, 'pointer type description') + destructing capsule (1234, 'pointer type description') + """ + + +def test_accessors(): + 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 = m.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 d["implicit_list"] == [1, 2, 3] + assert all(x in TestObject.__dict__ for x in d["implicit_dict"]) + + assert m.tuple_accessor(tuple()) == (0, 1, 2) + + d = m.accessor_assignment() + assert d["get"] == 0 + assert d["deferred_get"] == 0 + assert d["set"] == 1 + assert d["deferred_set"] == 1 + assert d["var"] == 99 + + +def test_constructors(): + """C++ default and converting constructors are equivalent to type calls in Python""" + types = [str, bool, int, float, tuple, list, dict, set] + expected = {t.__name__: t() for t in types} + assert m.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 m.converting_constructors(inputs) == expected + assert m.cast_functions(inputs) == expected + + # Converting constructors and cast functions should just reference rather + # than copy when no conversion is needed: + noconv1 = m.converting_constructors(expected) + for k in noconv1: + assert noconv1[k] is expected[k] + + noconv2 = m.cast_functions(expected) + for k in noconv2: + assert noconv2[k] is expected[k] + + +def test_implicit_casting(): + """Tests implicit casting when assigning or appending to dicts and lists.""" + z = m.get_implicit_casting() + assert z['d'] == { + 'char*_i1': 'abc', 'char*_i2': 'abc', 'char*_e': 'abc', 'char*_p': 'abc', + 'str_i1': 'str', 'str_i2': 'str1', 'str_e': 'str2', 'str_p': 'str3', + 'int_i1': 42, 'int_i2': 42, 'int_e': 43, 'int_p': 44 + } + assert z['l'] == [3, 6, 9, 12, 15] + + +def test_print(capture): + with capture: + m.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" + + with pytest.raises(RuntimeError) as excinfo: + m.print_failure() + assert str(excinfo.value) == "make_tuple(): unable to convert " + ( + "argument of type 'UnregisteredType' to Python object" + if debug_enabled else + "arguments to Python object (compile in debug mode for details)" + ) + + +def test_hash(): + class Hashable(object): + def __init__(self, value): + self.value = value + + def __hash__(self): + return self.value + + class Unhashable(object): + __hash__ = None + + assert m.hash_function(Hashable(42)) == 42 + with pytest.raises(TypeError): + m.hash_function(Unhashable()) + + +def test_number_protocol(): + for a, b in [(1, 1), (3, 5)]: + li = [a == b, a != b, a < b, a <= b, a > b, a >= b, a + b, + a - b, a * b, a / b, a | b, a & b, a ^ b, a >> b, a << b] + assert m.test_number_protocol(a, b) == li + + +def test_list_slicing(): + li = list(range(100)) + assert li[::2] == m.test_list_slicing(li) diff --git a/pybind11/tests/test_sequences_and_iterators.cpp b/pybind11/tests/test_sequences_and_iterators.cpp new file mode 100644 index 0000000..a455212 --- /dev/null +++ b/pybind11/tests/test_sequences_and_iterators.cpp @@ -0,0 +1,334 @@ +/* + 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 + +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; +} + +template +py::list test_random_access_iterator(PythonType x) { + if (x.size() < 5) + throw py::value_error("Please provide at least 5 elements for testing."); + + auto checks = py::list(); + auto assert_equal = [&checks](py::handle a, py::handle b) { + auto result = PyObject_RichCompareBool(a.ptr(), b.ptr(), Py_EQ); + if (result == -1) { throw py::error_already_set(); } + checks.append(result != 0); + }; + + auto it = x.begin(); + assert_equal(x[0], *it); + assert_equal(x[0], it[0]); + assert_equal(x[1], it[1]); + + assert_equal(x[1], *(++it)); + assert_equal(x[1], *(it++)); + assert_equal(x[2], *it); + assert_equal(x[3], *(it += 1)); + assert_equal(x[2], *(--it)); + assert_equal(x[2], *(it--)); + assert_equal(x[1], *it); + assert_equal(x[0], *(it -= 1)); + + assert_equal(it->attr("real"), x[0].attr("real")); + assert_equal((it + 1)->attr("real"), x[1].attr("real")); + + assert_equal(x[1], *(it + 1)); + assert_equal(x[1], *(1 + it)); + it += 3; + assert_equal(x[1], *(it - 2)); + + checks.append(static_cast(x.end() - x.begin()) == x.size()); + checks.append((x.begin() + static_cast(x.size())) == x.end()); + checks.append(x.begin() < x.end()); + + return checks; +} + +TEST_SUBMODULE(sequences_and_iterators, m) { + + // test_sequence + 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 < m_size; ++i) + if (m_data[i] != s[i]) + return false; + return true; + } + bool operator!=(const Sequence &s) const { return !operator==(s); } + + float operator[](size_t index) const { return m_data[index]; } + float &operator[](size_t index) { return m_data[index]; } + + bool contains(float v) const { + for (size_t i = 0; i < m_size; ++i) + if (v == m_data[i]) + return true; + return false; + } + + Sequence reversed() const { + Sequence result(m_size); + for (size_t i = 0; i < m_size; ++i) + result[m_size - i - 1] = m_data[i]; + return result; + } + + size_t size() const { return m_size; } + + const float *begin() const { return m_data; } + const float *end() const { return m_data+m_size; } + + private: + size_t m_size; + float *m_data; + }; + py::class_(m, "Sequence") + .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 < slicelength; ++i) { + (*seq)[i] = s[start]; start += step; + } + return seq; + }) + .def("__setitem__", [](Sequence &s, py::slice slice, const Sequence &value) { + size_t start, stop, step, slicelength; + if (!slice.compute(s.size(), &start, &stop, &step, &slicelength)) + throw py::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 < slicelength; ++i) { + s[start] = value[i]; start += step; + } + }) + /// Comparisons + .def(py::self == py::self) + .def(py::self != py::self) + // Could also define py::self + py::self for concatenation, etc. + ; + + // test_map_iterator + // 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(); } + }; + py::class_(m, "StringMap") + .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>()) + ; + + // test_generalized_iterators + class IntPairs { + public: + IntPairs(std::vector> data) : data_(std::move(data)) {} + const std::pair* begin() const { return data_.data(); } + private: + std::vector> data_; + }; + 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 + + // test_python_iterator_in_cpp + m.def("object_to_list", [](py::object o) { + auto l = py::list(); + for (auto item : o) { + l.append(item); + } + return l; + }); + + m.def("iterator_to_list", [](py::iterator it) { + auto l = py::list(); + while (it != py::iterator::sentinel()) { + l.append(*it); + ++it; + } + return l; + }); + + // Make sure that py::iterator works with std algorithms + m.def("count_none", [](py::object o) { + return std::count_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); }); + }); + + m.def("find_none", [](py::object o) { + auto it = std::find_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); }); + return it->is_none(); + }); + + m.def("count_nonzeros", [](py::dict d) { + return std::count_if(d.begin(), d.end(), [](std::pair p) { + return p.second.cast() != 0; + }); + }); + + m.def("tuple_iterator", &test_random_access_iterator); + m.def("list_iterator", &test_random_access_iterator); + m.def("sequence_iterator", &test_random_access_iterator); + + // test_iterator_passthrough + // #181: iterator passthrough did not compile + m.def("iterator_passthrough", [](py::iterator s) -> py::iterator { + return py::make_iterator(std::begin(s), std::end(s)); + }); + + // test_iterator_rvp + // #388: Can't make iterators via make_iterator() with different r/v policies + static std::vector list = { 1, 2, 3 }; + m.def("make_iterator_1", []() { return py::make_iterator(list); }); + m.def("make_iterator_2", []() { return py::make_iterator(list); }); +} diff --git a/pybind11/tests/test_sequences_and_iterators.py b/pybind11/tests/test_sequences_and_iterators.py new file mode 100644 index 0000000..f6c0620 --- /dev/null +++ b/pybind11/tests/test_sequences_and_iterators.py @@ -0,0 +1,158 @@ +import pytest +from pybind11_tests import sequences_and_iterators as m +from pybind11_tests import ConstructorStats + + +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(): + assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero()) == [(1, 2), (3, 4)] + assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero()) == [(1, 2)] + assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero()) == [] + + assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero_keys()) == [1, 3] + assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero_keys()) == [1] + assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero_keys()) == [] + + # __next__ must continue to raise StopIteration + it = m.IntPairs([(0, 0)]).nonzero() + for _ in range(3): + with pytest.raises(StopIteration): + next(it) + + it = m.IntPairs([(0, 0)]).nonzero_keys() + for _ in range(3): + with pytest.raises(StopIteration): + next(it) + + +def test_sequence(): + cstats = ConstructorStats.get(m.Sequence) + + s = m.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'] + + it = iter(m.Sequence(0)) + for _ in range(3): # __next__ must continue to raise StopIteration + with pytest.raises(StopIteration): + next(it) + assert cstats.values() == ['of size', '0'] + + expected = [0, 56.78, 0, 0, 12.34] + assert allclose(rev, expected) + assert allclose(rev2, expected) + assert rev == rev2 + + rev[0::2] = m.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() == 4 + del it + 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(): + sm = m.StringMap({'hi': 'bye', 'black': 'white'}) + assert sm['hi'] == 'bye' + assert len(sm) == 2 + assert sm['black'] == 'white' + + with pytest.raises(KeyError): + assert sm['orange'] + sm['orange'] = 'banana' + assert sm['orange'] == 'banana' + + expected = {'hi': 'bye', 'black': 'white', 'orange': 'banana'} + for k in sm: + assert sm[k] == expected[k] + for k, v in sm.items(): + assert v == expected[k] + + it = iter(m.StringMap({})) + for _ in range(3): # __next__ must continue to raise StopIteration + with pytest.raises(StopIteration): + next(it) + + +def test_python_iterator_in_cpp(): + t = (1, 2, 3) + assert m.object_to_list(t) == [1, 2, 3] + assert m.object_to_list(iter(t)) == [1, 2, 3] + assert m.iterator_to_list(iter(t)) == [1, 2, 3] + + with pytest.raises(TypeError) as excinfo: + m.object_to_list(1) + assert "object is not iterable" in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + m.iterator_to_list(1) + assert "incompatible function arguments" in str(excinfo.value) + + def bad_next_call(): + raise RuntimeError("py::iterator::advance() should propagate errors") + + with pytest.raises(RuntimeError) as excinfo: + m.iterator_to_list(iter(bad_next_call, None)) + assert str(excinfo.value) == "py::iterator::advance() should propagate errors" + + lst = [1, None, 0, None] + assert m.count_none(lst) == 2 + assert m.find_none(lst) is True + assert m.count_nonzeros({"a": 0, "b": 1, "c": 2}) == 2 + + r = range(5) + assert all(m.tuple_iterator(tuple(r))) + assert all(m.list_iterator(list(r))) + assert all(m.sequence_iterator(r)) + + +def test_iterator_passthrough(): + """#181: iterator passthrough did not compile""" + from pybind11_tests.sequences_and_iterators import iterator_passthrough + + assert list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15]))) == [3, 5, 7, 9, 11, 13, 15] + + +def test_iterator_rvp(): + """#388: Can't make iterators via make_iterator() with different r/v policies """ + import pybind11_tests.sequences_and_iterators as m + + assert list(m.make_iterator_1()) == [1, 2, 3] + assert list(m.make_iterator_2()) == [1, 2, 3] + assert not isinstance(m.make_iterator_1(), type(m.make_iterator_2())) diff --git a/pybind11/tests/test_smart_ptr.cpp b/pybind11/tests/test_smart_ptr.cpp new file mode 100644 index 0000000..5f1fd07 --- /dev/null +++ b/pybind11/tests/test_smart_ptr.cpp @@ -0,0 +1,364 @@ +/* + 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. +*/ + +#if defined(_MSC_VER) && _MSC_VER < 1910 +# pragma warning(disable: 4702) // unreachable code in system header +#endif + +#include "pybind11_tests.h" +#include "object.h" + +// Make pybind aware of the ref-counted wrapper type (s): + +// ref is a wrapper for 'Object' which uses intrusive reference counting +// It is always possible to construct a ref from an Object* pointer without +// possible inconsistencies, hence the 'true' argument at the end. +PYBIND11_DECLARE_HOLDER_TYPE(T, ref, true); +// Make pybind11 aware of the non-standard getter member function +namespace pybind11 { namespace detail { + template + struct holder_helper> { + static const T *get(const ref &p) { return p.get_ptr(); } + }; +}} + +// The following is not required anymore for std::shared_ptr, but it should compile without error: +PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); + +// This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the +// holder size to trigger the non-simple-layout internal instance layout for single inheritance with +// large holder type: +template class huge_unique_ptr { + std::unique_ptr ptr; + uint64_t padding[10]; +public: + huge_unique_ptr(T *p) : ptr(p) {}; + T *get() { return ptr.get(); } +}; +PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr); + +// Simple custom holder that works like unique_ptr +template +class custom_unique_ptr { + std::unique_ptr impl; +public: + custom_unique_ptr(T* p) : impl(p) { } + T* get() const { return impl.get(); } + T* release_ptr() { return impl.release(); } +}; +PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr); + +// Simple custom holder that works like shared_ptr and has operator& overload +// To obtain address of an instance of this holder pybind should use std::addressof +// Attempt to get address via operator& may leads to segmentation fault +template +class shared_ptr_with_addressof_operator { + std::shared_ptr impl; +public: + shared_ptr_with_addressof_operator( ) = default; + shared_ptr_with_addressof_operator(T* p) : impl(p) { } + T* get() const { return impl.get(); } + T** operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); } +}; +PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator); + +// Simple custom holder that works like unique_ptr and has operator& overload +// To obtain address of an instance of this holder pybind should use std::addressof +// Attempt to get address via operator& may leads to segmentation fault +template +class unique_ptr_with_addressof_operator { + std::unique_ptr impl; +public: + unique_ptr_with_addressof_operator() = default; + unique_ptr_with_addressof_operator(T* p) : impl(p) { } + T* get() const { return impl.get(); } + T* release_ptr() { return impl.release(); } + T** operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); } +}; +PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator); + + +TEST_SUBMODULE(smart_ptr, m) { + + // test_smart_ptr + + // Object implementation in `object.h` + py::class_> obj(m, "Object"); + obj.def("getRefCount", &Object::getRefCount); + + // 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; + }; + py::class_>(m, "MyObject1", obj) + .def(py::init()); + py::implicitly_convertible(); + + m.def("make_object_1", []() -> Object * { return new MyObject1(1); }); + m.def("make_object_2", []() -> ref { return new MyObject1(2); }); + m.def("make_myobject1_1", []() -> MyObject1 * { return new MyObject1(4); }); + m.def("make_myobject1_2", []() -> ref { return new MyObject1(5); }); + m.def("print_object_1", [](const Object *obj) { py::print(obj->toString()); }); + m.def("print_object_2", [](ref obj) { py::print(obj->toString()); }); + m.def("print_object_3", [](const ref &obj) { py::print(obj->toString()); }); + m.def("print_object_4", [](const ref *obj) { py::print((*obj)->toString()); }); + m.def("print_myobject1_1", [](const MyObject1 *obj) { py::print(obj->toString()); }); + m.def("print_myobject1_2", [](ref obj) { py::print(obj->toString()); }); + m.def("print_myobject1_3", [](const ref &obj) { py::print(obj->toString()); }); + m.def("print_myobject1_4", [](const ref *obj) { py::print((*obj)->toString()); }); + + // Expose constructor stats for the ref type + m.def("cstats_ref", &ConstructorStats::get); + + + // Object managed by a std::shared_ptr<> + class MyObject2 { + public: + MyObject2(const MyObject2 &) = default; + 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; + }; + py::class_>(m, "MyObject2") + .def(py::init()); + m.def("make_myobject2_1", []() { return new MyObject2(6); }); + m.def("make_myobject2_2", []() { return std::make_shared(7); }); + m.def("print_myobject2_1", [](const MyObject2 *obj) { py::print(obj->toString()); }); + m.def("print_myobject2_2", [](std::shared_ptr obj) { py::print(obj->toString()); }); + m.def("print_myobject2_3", [](const std::shared_ptr &obj) { py::print(obj->toString()); }); + m.def("print_myobject2_4", [](const std::shared_ptr *obj) { py::print((*obj)->toString()); }); + + // 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(const MyObject3 &) = default; + 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; + }; + py::class_>(m, "MyObject3") + .def(py::init()); + m.def("make_myobject3_1", []() { return new MyObject3(8); }); + m.def("make_myobject3_2", []() { return std::make_shared(9); }); + m.def("print_myobject3_1", [](const MyObject3 *obj) { py::print(obj->toString()); }); + m.def("print_myobject3_2", [](std::shared_ptr obj) { py::print(obj->toString()); }); + m.def("print_myobject3_3", [](const std::shared_ptr &obj) { py::print(obj->toString()); }); + m.def("print_myobject3_4", [](const std::shared_ptr *obj) { py::print((*obj)->toString()); }); + + // test_smart_ptr_refcounting + m.def("test_object1_refcounting", []() { + ref o = new MyObject1(0); + bool good = o->getRefCount() == 1; + py::object o2 = py::cast(o, py::return_value_policy::reference); + // always request (partial) ownership for objects with intrusive + // reference counting even when using the 'reference' RVP + good &= o->getRefCount() == 2; + return good; + }); + + // test_unique_nodelete + // Object with a private destructor + class MyObject4 { + public: + MyObject4(int value) : value{value} { print_created(this); } + int value; + private: + ~MyObject4() { print_destroyed(this); } + }; + py::class_>(m, "MyObject4") + .def(py::init()) + .def_readwrite("value", &MyObject4::value); + + // test_unique_deleter + // Object with std::unique_ptr where D is not matching the base class + // Object with a protected destructor + class MyObject4a { + public: + MyObject4a(int i) { + value = i; + print_created(this); + }; + int value; + protected: + virtual ~MyObject4a() { print_destroyed(this); } + }; + py::class_>(m, "MyObject4a") + .def(py::init()) + .def_readwrite("value", &MyObject4a::value); + + // Object derived but with public destructor and no Deleter in default holder + class MyObject4b : public MyObject4a { + public: + MyObject4b(int i) : MyObject4a(i) { print_created(this); } + ~MyObject4b() { print_destroyed(this); } + }; + py::class_(m, "MyObject4b") + .def(py::init()); + + // test_large_holder + class MyObject5 { // managed by huge_unique_ptr + public: + MyObject5(int value) : value{value} { print_created(this); } + ~MyObject5() { print_destroyed(this); } + int value; + }; + py::class_>(m, "MyObject5") + .def(py::init()) + .def_readwrite("value", &MyObject5::value); + + // test_shared_ptr_and_references + 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(); + }; + 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; }); + + // test_shared_ptr_from_this_and_references + 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(); + }; + 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; }); + + // Issue #865: shared_from_this doesn't work with virtual inheritance + struct SharedFromThisVBase : std::enable_shared_from_this { + SharedFromThisVBase() = default; + SharedFromThisVBase(const SharedFromThisVBase &) = default; + virtual ~SharedFromThisVBase() = default; + }; + struct SharedFromThisVirt : virtual SharedFromThisVBase {}; + static std::shared_ptr sft(new SharedFromThisVirt()); + py::class_>(m, "SharedFromThisVirt") + .def_static("get", []() { return sft.get(); }); + + // test_move_only_holder + struct C { + C() { print_created(this); } + ~C() { print_destroyed(this); } + }; + py::class_>(m, "TypeWithMoveOnlyHolder") + .def_static("make", []() { return custom_unique_ptr(new C); }); + + // test_holder_with_addressof_operator + struct TypeForHolderWithAddressOf { + TypeForHolderWithAddressOf() { print_created(this); } + TypeForHolderWithAddressOf(const TypeForHolderWithAddressOf &) { print_copy_created(this); } + TypeForHolderWithAddressOf(TypeForHolderWithAddressOf &&) { print_move_created(this); } + ~TypeForHolderWithAddressOf() { print_destroyed(this); } + std::string toString() const { + return "TypeForHolderWithAddressOf[" + std::to_string(value) + "]"; + } + int value = 42; + }; + using HolderWithAddressOf = shared_ptr_with_addressof_operator; + py::class_(m, "TypeForHolderWithAddressOf") + .def_static("make", []() { return HolderWithAddressOf(new TypeForHolderWithAddressOf); }) + .def("get", [](const HolderWithAddressOf &self) { return self.get(); }) + .def("print_object_1", [](const TypeForHolderWithAddressOf *obj) { py::print(obj->toString()); }) + .def("print_object_2", [](HolderWithAddressOf obj) { py::print(obj.get()->toString()); }) + .def("print_object_3", [](const HolderWithAddressOf &obj) { py::print(obj.get()->toString()); }) + .def("print_object_4", [](const HolderWithAddressOf *obj) { py::print((*obj).get()->toString()); }); + + // test_move_only_holder_with_addressof_operator + struct TypeForMoveOnlyHolderWithAddressOf { + TypeForMoveOnlyHolderWithAddressOf(int value) : value{value} { print_created(this); } + ~TypeForMoveOnlyHolderWithAddressOf() { print_destroyed(this); } + std::string toString() const { + return "MoveOnlyHolderWithAddressOf[" + std::to_string(value) + "]"; + } + int value; + }; + using MoveOnlyHolderWithAddressOf = unique_ptr_with_addressof_operator; + py::class_(m, "TypeForMoveOnlyHolderWithAddressOf") + .def_static("make", []() { return MoveOnlyHolderWithAddressOf(new TypeForMoveOnlyHolderWithAddressOf(0)); }) + .def_readwrite("value", &TypeForMoveOnlyHolderWithAddressOf::value) + .def("print_object", [](const TypeForMoveOnlyHolderWithAddressOf *obj) { py::print(obj->toString()); }); + + // test_smart_ptr_from_default + struct HeldByDefaultHolder { }; + py::class_(m, "HeldByDefaultHolder") + .def(py::init<>()) + .def_static("load_shared_ptr", [](std::shared_ptr) {}); + + // test_shared_ptr_gc + // #187: issue involving std::shared_ptr<> return value policy & garbage collection + struct ElementBase { virtual void foo() { } /* Force creation of virtual table */ }; + py::class_>(m, "ElementBase"); + + struct ElementA : ElementBase { + ElementA(int v) : v(v) { } + int value() { return v; } + int v; + }; + py::class_>(m, "ElementA") + .def(py::init()) + .def("value", &ElementA::value); + + struct ElementList { + void add(std::shared_ptr e) { l.push_back(e); } + std::vector> l; + }; + py::class_>(m, "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; + }); +} diff --git a/pybind11/tests/test_smart_ptr.py b/pybind11/tests/test_smart_ptr.py new file mode 100644 index 0000000..72b1c2a --- /dev/null +++ b/pybind11/tests/test_smart_ptr.py @@ -0,0 +1,285 @@ +import pytest +from pybind11_tests import smart_ptr as m +from pybind11_tests import ConstructorStats + + +def test_smart_ptr(capture): + # Object1 + for i, o in enumerate([m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1): + assert o.getRefCount() == 1 + with capture: + m.print_object_1(o) + m.print_object_2(o) + m.print_object_3(o) + m.print_object_4(o) + assert capture == "MyObject1[{i}]\n".format(i=i) * 4 + + for i, o in enumerate([m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7], + start=4): + print(o) + with capture: + if not isinstance(o, int): + m.print_object_1(o) + m.print_object_2(o) + m.print_object_3(o) + m.print_object_4(o) + m.print_myobject1_1(o) + m.print_myobject1_2(o) + m.print_myobject1_3(o) + m.print_myobject1_4(o) + assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8) + + cstats = ConstructorStats.get(m.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 + for i, o in zip([8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()]): + print(o) + with capture: + m.print_myobject2_1(o) + m.print_myobject2_2(o) + m.print_myobject2_3(o) + m.print_myobject2_4(o) + assert capture == "MyObject2[{i}]\n".format(i=i) * 4 + + cstats = ConstructorStats.get(m.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 + for i, o in zip([9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()]): + print(o) + with capture: + m.print_myobject3_1(o) + m.print_myobject3_2(o) + m.print_myobject3_3(o) + m.print_myobject3_4(o) + assert capture == "MyObject3[{i}]\n".format(i=i) * 4 + + cstats = ConstructorStats.get(m.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 + cstats = ConstructorStats.get(m.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 + + # ref<> + cstats = m.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_smart_ptr_refcounting(): + assert m.test_object1_refcounting() + + +def test_unique_nodelete(): + o = m.MyObject4(23) + assert o.value == 23 + cstats = ConstructorStats.get(m.MyObject4) + assert cstats.alive() == 1 + del o + assert cstats.alive() == 1 # Leak, but that's intentional + + +def test_unique_nodelete4a(): + o = m.MyObject4a(23) + assert o.value == 23 + cstats = ConstructorStats.get(m.MyObject4a) + assert cstats.alive() == 1 + del o + assert cstats.alive() == 1 # Leak, but that's intentional + + +def test_unique_deleter(): + o = m.MyObject4b(23) + assert o.value == 23 + cstats4a = ConstructorStats.get(m.MyObject4a) + assert cstats4a.alive() == 2 # Two becaue of previous test + cstats4b = ConstructorStats.get(m.MyObject4b) + assert cstats4b.alive() == 1 + del o + assert cstats4a.alive() == 1 # Should now only be one leftover from previous test + assert cstats4b.alive() == 0 # Should be deleted + + +def test_large_holder(): + o = m.MyObject5(5) + assert o.value == 5 + cstats = ConstructorStats.get(m.MyObject5) + assert cstats.alive() == 1 + del o + assert cstats.alive() == 0 + + +def test_shared_ptr_and_references(): + s = m.SharedPtrRef() + stats = ConstructorStats.get(m.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(): + s = m.SharedFromThisRef() + stats = ConstructorStats.get(m.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 + + z = m.SharedFromThisVirt.get() + y = m.SharedFromThisVirt.get() + assert y is z + + +def test_move_only_holder(): + a = m.TypeWithMoveOnlyHolder.make() + stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder) + assert stats.alive() == 1 + del a + assert stats.alive() == 0 + + +def test_holder_with_addressof_operator(): + # this test must not throw exception from c++ + a = m.TypeForHolderWithAddressOf.make() + a.print_object_1() + a.print_object_2() + a.print_object_3() + a.print_object_4() + + stats = ConstructorStats.get(m.TypeForHolderWithAddressOf) + assert stats.alive() == 1 + + np = m.TypeForHolderWithAddressOf.make() + assert stats.alive() == 2 + del a + assert stats.alive() == 1 + del np + assert stats.alive() == 0 + + b = m.TypeForHolderWithAddressOf.make() + c = b + assert b.get() is c.get() + assert stats.alive() == 1 + + del b + assert stats.alive() == 1 + + del c + assert stats.alive() == 0 + + +def test_move_only_holder_with_addressof_operator(): + a = m.TypeForMoveOnlyHolderWithAddressOf.make() + a.print_object() + + stats = ConstructorStats.get(m.TypeForMoveOnlyHolderWithAddressOf) + assert stats.alive() == 1 + + a.value = 42 + assert a.value == 42 + + del a + assert stats.alive() == 0 + + +def test_smart_ptr_from_default(): + instance = m.HeldByDefaultHolder() + with pytest.raises(RuntimeError) as excinfo: + m.HeldByDefaultHolder.load_shared_ptr(instance) + assert "Unable to load a custom holder type from a default-holder instance" in str(excinfo) + + +def test_shared_ptr_gc(): + """#187: issue involving std::shared_ptr<> return value policy & garbage collection""" + el = m.ElementList() + for i in range(10): + el.add(m.ElementA(i)) + pytest.gc_collect() + for i, v in enumerate(el.get()): + assert i == v.value() diff --git a/pybind11/tests/test_stl.cpp b/pybind11/tests/test_stl.cpp new file mode 100644 index 0000000..207c9fb --- /dev/null +++ b/pybind11/tests/test_stl.cpp @@ -0,0 +1,284 @@ +/* + tests/test_stl.cpp -- STL type casters + + Copyright (c) 2017 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 + +// Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14 +#if PYBIND11_HAS_VARIANT +using std::variant; +#elif defined(PYBIND11_TEST_BOOST) && (!defined(_MSC_VER) || _MSC_VER >= 1910) +# include +# define PYBIND11_HAS_VARIANT 1 +using boost::variant; + +namespace pybind11 { namespace detail { +template +struct type_caster> : variant_caster> {}; + +template <> +struct visit_helper { + template + static auto call(Args &&...args) -> decltype(boost::apply_visitor(args...)) { + return boost::apply_visitor(args...); + } +}; +}} // namespace pybind11::detail +#endif + +PYBIND11_MAKE_OPAQUE(std::vector>); + +/// Issue #528: templated constructor +struct TplCtorClass { + template TplCtorClass(const T &) { } + bool operator==(const TplCtorClass &) const { return true; } +}; + +namespace std { + template <> + struct hash { size_t operator()(const TplCtorClass &) const { return 0; } }; +} + + +TEST_SUBMODULE(stl, m) { + // test_vector + m.def("cast_vector", []() { return std::vector{1}; }); + m.def("load_vector", [](const std::vector &v) { return v.at(0) == 1 && v.at(1) == 2; }); + // `std::vector` is special because it returns proxy objects instead of references + m.def("cast_bool_vector", []() { return std::vector{true, false}; }); + m.def("load_bool_vector", [](const std::vector &v) { + return v.at(0) == true && v.at(1) == false; + }); + // Unnumbered regression (caused by #936): pointers to stl containers aren't castable + static std::vector lvv{2}; + m.def("cast_ptr_vector", []() { return &lvv; }); + + // test_deque + m.def("cast_deque", []() { return std::deque{1}; }); + m.def("load_deque", [](const std::deque &v) { return v.at(0) == 1 && v.at(1) == 2; }); + + // test_array + m.def("cast_array", []() { return std::array {{1 , 2}}; }); + m.def("load_array", [](const std::array &a) { return a[0] == 1 && a[1] == 2; }); + + // test_valarray + m.def("cast_valarray", []() { return std::valarray{1, 4, 9}; }); + m.def("load_valarray", [](const std::valarray& v) { + return v.size() == 3 && v[0] == 1 && v[1] == 4 && v[2] == 9; + }); + + // test_map + m.def("cast_map", []() { return std::map{{"key", "value"}}; }); + m.def("load_map", [](const std::map &map) { + return map.at("key") == "value" && map.at("key2") == "value2"; + }); + + // test_set + m.def("cast_set", []() { return std::set{"key1", "key2"}; }); + m.def("load_set", [](const std::set &set) { + return set.count("key1") && set.count("key2") && set.count("key3"); + }); + + // test_recursive_casting + m.def("cast_rv_vector", []() { return std::vector{2}; }); + m.def("cast_rv_array", []() { return std::array(); }); + // NB: map and set keys are `const`, so while we technically do move them (as `const Type &&`), + // casters don't typically do anything with that, which means they fall to the `const Type &` + // caster. + m.def("cast_rv_map", []() { return std::unordered_map{{"a", RValueCaster{}}}; }); + m.def("cast_rv_nested", []() { + std::vector>, 2>> v; + v.emplace_back(); // add an array + v.back()[0].emplace_back(); // add a map to the array + v.back()[0].back().emplace("b", RValueCaster{}); + v.back()[0].back().emplace("c", RValueCaster{}); + v.back()[1].emplace_back(); // add a map to the array + v.back()[1].back().emplace("a", RValueCaster{}); + return v; + }); + static std::array lva; + static std::unordered_map lvm{{"a", RValueCaster{}}, {"b", RValueCaster{}}}; + static std::unordered_map>>> lvn; + lvn["a"].emplace_back(); // add a list + lvn["a"].back().emplace_back(); // add an array + lvn["a"].emplace_back(); // another list + lvn["a"].back().emplace_back(); // add an array + lvn["b"].emplace_back(); // add a list + lvn["b"].back().emplace_back(); // add an array + lvn["b"].back().emplace_back(); // add another array + m.def("cast_lv_vector", []() -> const decltype(lvv) & { return lvv; }); + m.def("cast_lv_array", []() -> const decltype(lva) & { return lva; }); + m.def("cast_lv_map", []() -> const decltype(lvm) & { return lvm; }); + m.def("cast_lv_nested", []() -> const decltype(lvn) & { return lvn; }); + // #853: + m.def("cast_unique_ptr_vector", []() { + std::vector> v; + v.emplace_back(new UserType{7}); + v.emplace_back(new UserType{42}); + return v; + }); + + // test_move_out_container + struct MoveOutContainer { + struct Value { int value; }; + std::list move_list() const { return {{0}, {1}, {2}}; } + }; + 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); + + // Class that can be move- and copy-constructed, but not assigned + struct NoAssign { + int value; + + explicit NoAssign(int value = 0) : value(value) { } + NoAssign(const NoAssign &) = default; + NoAssign(NoAssign &&) = default; + + NoAssign &operator=(const NoAssign &) = delete; + NoAssign &operator=(NoAssign &&) = delete; + }; + py::class_(m, "NoAssign", "Class with no C++ assignment operators") + .def(py::init<>()) + .def(py::init()); + +#ifdef PYBIND11_HAS_OPTIONAL + // test_optional + m.attr("has_optional") = true; + + using opt_int = std::optional; + using opt_no_assign = 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")); + m.def("test_no_assign", [](const opt_no_assign &x) { + return x ? x->value : 42; + }, py::arg_v("x", std::nullopt, "None")); + + m.def("nodefer_none_optional", [](std::optional) { return true; }); + m.def("nodefer_none_optional", [](py::none) { return false; }); +#endif + +#ifdef PYBIND11_HAS_EXP_OPTIONAL + // test_exp_optional + m.attr("has_exp_optional") = true; + + using exp_opt_int = std::experimental::optional; + using exp_opt_no_assign = std::experimental::optional; + m.def("double_or_zero_exp", [](const exp_opt_int& x) -> int { + return x.value_or(0) * 2; + }); + m.def("half_or_none_exp", [](int x) -> exp_opt_int { + return x ? exp_opt_int(x / 2) : exp_opt_int(); + }); + m.def("test_nullopt_exp", [](exp_opt_int x) { + return x.value_or(42); + }, py::arg_v("x", std::experimental::nullopt, "None")); + m.def("test_no_assign_exp", [](const exp_opt_no_assign &x) { + return x ? x->value : 42; + }, py::arg_v("x", std::experimental::nullopt, "None")); +#endif + +#ifdef PYBIND11_HAS_VARIANT + static_assert(std::is_same::value, + "visitor::result_type is required by boost::variant in C++11 mode"); + + struct visitor { + using result_type = const char *; + + result_type operator()(int) { return "int"; } + result_type operator()(std::string) { return "std::string"; } + result_type operator()(double) { return "double"; } + result_type operator()(std::nullptr_t) { return "std::nullptr_t"; } + }; + + // test_variant + m.def("load_variant", [](variant v) { + return py::detail::visit_helper::call(visitor(), v); + }); + m.def("load_variant_2pass", [](variant v) { + return py::detail::visit_helper::call(visitor(), v); + }); + m.def("cast_variant", []() { + using V = variant; + return py::make_tuple(V(5), V("Hello")); + }); +#endif + + // #528: templated constructor + // (no python tests: the test here is that this compiles) + m.def("tpl_ctor_vector", [](std::vector &) {}); + m.def("tpl_ctor_map", [](std::unordered_map &) {}); + m.def("tpl_ctor_set", [](std::unordered_set &) {}); +#if defined(PYBIND11_HAS_OPTIONAL) + m.def("tpl_constr_optional", [](std::optional &) {}); +#elif defined(PYBIND11_HAS_EXP_OPTIONAL) + m.def("tpl_constr_optional", [](std::experimental::optional &) {}); +#endif + + // test_vec_of_reference_wrapper + // #171: Can't return STL structures containing reference wrapper + m.def("return_vec_of_reference_wrapper", [](std::reference_wrapper p4) { + static UserType p1{1}, p2{2}, p3{3}; + return std::vector> { + std::ref(p1), std::ref(p2), std::ref(p3), p4 + }; + }); + + // test_stl_pass_by_pointer + m.def("stl_pass_by_pointer", [](std::vector* v) { return *v; }, "v"_a=nullptr); + + // #1258: pybind11/stl.h converts string to vector + m.def("func_with_string_or_vector_string_arg_overload", [](std::vector) { return 1; }); + m.def("func_with_string_or_vector_string_arg_overload", [](std::list) { return 2; }); + m.def("func_with_string_or_vector_string_arg_overload", [](std::string) { return 3; }); + + class Placeholder { + public: + Placeholder() { print_created(this); } + Placeholder(const Placeholder &) = delete; + ~Placeholder() { print_destroyed(this); } + }; + py::class_(m, "Placeholder"); + + /// test_stl_vector_ownership + m.def("test_stl_ownership", + []() { + std::vector result; + result.push_back(new Placeholder()); + return result; + }, + py::return_value_policy::take_ownership); + + m.def("array_cast_sequence", [](std::array x) { return x; }); + + /// test_issue_1561 + struct Issue1561Inner { std::string data; }; + struct Issue1561Outer { std::vector list; }; + + py::class_(m, "Issue1561Inner") + .def(py::init()) + .def_readwrite("data", &Issue1561Inner::data); + + py::class_(m, "Issue1561Outer") + .def(py::init<>()) + .def_readwrite("list", &Issue1561Outer::list); +} diff --git a/pybind11/tests/test_stl.py b/pybind11/tests/test_stl.py new file mode 100644 index 0000000..bf185d5 --- /dev/null +++ b/pybind11/tests/test_stl.py @@ -0,0 +1,239 @@ +import pytest + +from pybind11_tests import stl as m +from pybind11_tests import UserType +from pybind11_tests import ConstructorStats + + +def test_vector(doc): + """std::vector <-> list""" + lst = m.cast_vector() + assert lst == [1] + lst.append(2) + assert m.load_vector(lst) + assert m.load_vector(tuple(lst)) + + assert m.cast_bool_vector() == [True, False] + assert m.load_bool_vector([True, False]) + + assert doc(m.cast_vector) == "cast_vector() -> List[int]" + assert doc(m.load_vector) == "load_vector(arg0: List[int]) -> bool" + + # Test regression caused by 936: pointers to stl containers weren't castable + assert m.cast_ptr_vector() == ["lvalue", "lvalue"] + + +def test_deque(doc): + """std::deque <-> list""" + lst = m.cast_deque() + assert lst == [1] + lst.append(2) + assert m.load_deque(lst) + assert m.load_deque(tuple(lst)) + + +def test_array(doc): + """std::array <-> list""" + lst = m.cast_array() + assert lst == [1, 2] + assert m.load_array(lst) + + assert doc(m.cast_array) == "cast_array() -> List[int[2]]" + assert doc(m.load_array) == "load_array(arg0: List[int[2]]) -> bool" + + +def test_valarray(doc): + """std::valarray <-> list""" + lst = m.cast_valarray() + assert lst == [1, 4, 9] + assert m.load_valarray(lst) + + assert doc(m.cast_valarray) == "cast_valarray() -> List[int]" + assert doc(m.load_valarray) == "load_valarray(arg0: List[int]) -> bool" + + +def test_map(doc): + """std::map <-> dict""" + d = m.cast_map() + assert d == {"key": "value"} + d["key2"] = "value2" + assert m.load_map(d) + + assert doc(m.cast_map) == "cast_map() -> Dict[str, str]" + assert doc(m.load_map) == "load_map(arg0: Dict[str, str]) -> bool" + + +def test_set(doc): + """std::set <-> set""" + s = m.cast_set() + assert s == {"key1", "key2"} + s.add("key3") + assert m.load_set(s) + + assert doc(m.cast_set) == "cast_set() -> Set[str]" + assert doc(m.load_set) == "load_set(arg0: Set[str]) -> bool" + + +def test_recursive_casting(): + """Tests that stl casters preserve lvalue/rvalue context for container values""" + assert m.cast_rv_vector() == ["rvalue", "rvalue"] + assert m.cast_lv_vector() == ["lvalue", "lvalue"] + assert m.cast_rv_array() == ["rvalue", "rvalue", "rvalue"] + assert m.cast_lv_array() == ["lvalue", "lvalue"] + assert m.cast_rv_map() == {"a": "rvalue"} + assert m.cast_lv_map() == {"a": "lvalue", "b": "lvalue"} + assert m.cast_rv_nested() == [[[{"b": "rvalue", "c": "rvalue"}], [{"a": "rvalue"}]]] + assert m.cast_lv_nested() == { + "a": [[["lvalue", "lvalue"]], [["lvalue", "lvalue"]]], + "b": [[["lvalue", "lvalue"], ["lvalue", "lvalue"]]] + } + + # Issue #853 test case: + z = m.cast_unique_ptr_vector() + assert z[0].value == 7 and z[1].value == 42 + + +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.""" + c = m.MoveOutContainer() + moved_out_list = c.move_list + assert [x.value for x in moved_out_list] == [0, 1, 2] + + +@pytest.mark.skipif(not hasattr(m, "has_optional"), reason='no ') +def test_optional(): + assert m.double_or_zero(None) == 0 + assert m.double_or_zero(42) == 84 + pytest.raises(TypeError, m.double_or_zero, 'foo') + + assert m.half_or_none(0) is None + assert m.half_or_none(42) == 21 + pytest.raises(TypeError, m.half_or_none, 'foo') + + assert m.test_nullopt() == 42 + assert m.test_nullopt(None) == 42 + assert m.test_nullopt(42) == 42 + assert m.test_nullopt(43) == 43 + + assert m.test_no_assign() == 42 + assert m.test_no_assign(None) == 42 + assert m.test_no_assign(m.NoAssign(43)) == 43 + pytest.raises(TypeError, m.test_no_assign, 43) + + assert m.nodefer_none_optional(None) + + +@pytest.mark.skipif(not hasattr(m, "has_exp_optional"), reason='no ') +def test_exp_optional(): + assert m.double_or_zero_exp(None) == 0 + assert m.double_or_zero_exp(42) == 84 + pytest.raises(TypeError, m.double_or_zero_exp, 'foo') + + assert m.half_or_none_exp(0) is None + assert m.half_or_none_exp(42) == 21 + pytest.raises(TypeError, m.half_or_none_exp, 'foo') + + assert m.test_nullopt_exp() == 42 + assert m.test_nullopt_exp(None) == 42 + assert m.test_nullopt_exp(42) == 42 + assert m.test_nullopt_exp(43) == 43 + + assert m.test_no_assign_exp() == 42 + assert m.test_no_assign_exp(None) == 42 + assert m.test_no_assign_exp(m.NoAssign(43)) == 43 + pytest.raises(TypeError, m.test_no_assign_exp, 43) + + +@pytest.mark.skipif(not hasattr(m, "load_variant"), reason='no ') +def test_variant(doc): + assert m.load_variant(1) == "int" + assert m.load_variant("1") == "std::string" + assert m.load_variant(1.0) == "double" + assert m.load_variant(None) == "std::nullptr_t" + + assert m.load_variant_2pass(1) == "int" + assert m.load_variant_2pass(1.0) == "double" + + assert m.cast_variant() == (5, "Hello") + + assert doc(m.load_variant) == "load_variant(arg0: Union[int, str, float, None]) -> str" + + +def test_vec_of_reference_wrapper(): + """#171: Can't return reference wrappers (or STL structures containing them)""" + assert str(m.return_vec_of_reference_wrapper(UserType(4))) == \ + "[UserType(1), UserType(2), UserType(3), UserType(4)]" + + +def test_stl_pass_by_pointer(msg): + """Passing nullptr or None to an STL container pointer is not expected to work""" + with pytest.raises(TypeError) as excinfo: + m.stl_pass_by_pointer() # default value is `nullptr` + assert msg(excinfo.value) == """ + stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported: + 1. (v: List[int] = None) -> List[int] + + Invoked with: + """ # noqa: E501 line too long + + with pytest.raises(TypeError) as excinfo: + m.stl_pass_by_pointer(None) + assert msg(excinfo.value) == """ + stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported: + 1. (v: List[int] = None) -> List[int] + + Invoked with: None + """ # noqa: E501 line too long + + assert m.stl_pass_by_pointer([1, 2, 3]) == [1, 2, 3] + + +def test_missing_header_message(): + """Trying convert `list` to a `std::vector`, or vice versa, without including + should result in a helpful suggestion in the error message""" + import pybind11_cross_module_tests as cm + + expected_message = ("Did you forget to `#include `? Or ,\n" + ", , etc. Some automatic\n" + "conversions are optional and require extra headers to be included\n" + "when compiling your pybind11 module.") + + with pytest.raises(TypeError) as excinfo: + cm.missing_header_arg([1.0, 2.0, 3.0]) + assert expected_message in str(excinfo.value) + + with pytest.raises(TypeError) as excinfo: + cm.missing_header_return() + assert expected_message in str(excinfo.value) + + +def test_function_with_string_and_vector_string_arg(): + """Check if a string is NOT implicitly converted to a list, which was the + behavior before fix of issue #1258""" + assert m.func_with_string_or_vector_string_arg_overload(('A', 'B', )) == 2 + assert m.func_with_string_or_vector_string_arg_overload(['A', 'B']) == 2 + assert m.func_with_string_or_vector_string_arg_overload('A') == 3 + + +def test_stl_ownership(): + cstats = ConstructorStats.get(m.Placeholder) + assert cstats.alive() == 0 + r = m.test_stl_ownership() + assert len(r) == 1 + del r + assert cstats.alive() == 0 + + +def test_array_cast_sequence(): + assert m.array_cast_sequence((1, 2, 3)) == [1, 2, 3] + + +def test_issue_1561(): + """ check fix for issue #1561 """ + bar = m.Issue1561Outer() + bar.list = [m.Issue1561Inner('bar')] + bar.list + assert bar.list[0].data == 'bar' diff --git a/pybind11/tests/test_stl_binders.cpp b/pybind11/tests/test_stl_binders.cpp new file mode 100644 index 0000000..a88b589 --- /dev/null +++ b/pybind11/tests/test_stl_binders.cpp @@ -0,0 +1,107 @@ +/* + 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 +#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_SUBMODULE(stl_binders, m) { + // test_vector_int + py::bind_vector>(m, "VectorInt", py::buffer_protocol()); + + // test_vector_custom + py::class_(m, "El") + .def(py::init()); + py::bind_vector>(m, "VectorEl"); + py::bind_vector>>(m, "VectorVectorEl"); + + // test_map_string_double + py::bind_map>(m, "MapStringDouble"); + py::bind_map>(m, "UnorderedMapStringDouble"); + + // test_map_string_double_const + py::bind_map>(m, "MapStringDoubleConst"); + py::bind_map>(m, "UnorderedMapStringDoubleConst"); + + py::class_(m, "ENC") + .def(py::init()) + .def_readwrite("value", &E_nc::value); + + // test_noncopyable_containers + 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); + + // test_vector_buffer + py::bind_vector>(m, "VectorUChar", py::buffer_protocol()); + // no dtype declared for this version: + struct VUndeclStruct { bool w; uint32_t x; double y; bool z; }; + m.def("create_undeclstruct", [m] () mutable { + py::bind_vector>(m, "VectorUndeclStruct", py::buffer_protocol()); + }); + + // The rest depends on numpy: + try { py::module::import("numpy"); } + catch (...) { return; } + + // test_vector_buffer_numpy + struct VStruct { bool w; uint32_t x; double y; bool z; }; + PYBIND11_NUMPY_DTYPE(VStruct, w, x, y, z); + py::class_(m, "VStruct").def_readwrite("x", &VStruct::x); + py::bind_vector>(m, "VectorStruct", py::buffer_protocol()); + m.def("get_vectorstruct", [] {return std::vector {{0, 5, 3.0, 1}, {1, 30, -1e4, 0}};}); +} diff --git a/pybind11/tests/test_stl_binders.py b/pybind11/tests/test_stl_binders.py new file mode 100644 index 0000000..0030924 --- /dev/null +++ b/pybind11/tests/test_stl_binders.py @@ -0,0 +1,205 @@ +import pytest +import sys +from pybind11_tests import stl_binders as m + +with pytest.suppress(ImportError): + import numpy as np + + +def test_vector_int(): + v_int = m.VectorInt([0, 0]) + assert len(v_int) == 2 + assert bool(v_int) is True + + v_int2 = m.VectorInt([0, 0]) + assert v_int == v_int2 + v_int2[1] = 1 + assert v_int != v_int2 + + v_int2.append(2) + v_int2.insert(0, 1) + v_int2.insert(0, 2) + v_int2.insert(0, 3) + v_int2.insert(6, 3) + assert str(v_int2) == "VectorInt[3, 2, 1, 0, 1, 2, 3]" + with pytest.raises(IndexError): + v_int2.insert(8, 4) + + v_int.append(99) + v_int2[2:-2] = v_int + assert v_int2 == m.VectorInt([3, 2, 0, 0, 99, 2, 3]) + del v_int2[1:3] + assert v_int2 == m.VectorInt([3, 0, 99, 2, 3]) + del v_int2[0] + assert v_int2 == m.VectorInt([0, 99, 2, 3]) + + +# related to the PyPy's buffer protocol. +@pytest.unsupported_on_pypy +def test_vector_buffer(): + b = bytearray([1, 2, 3, 4]) + v = m.VectorUChar(b) + assert v[1] == 2 + v[2] = 5 + mv = memoryview(v) # We expose the buffer interface + if sys.version_info.major > 2: + assert mv[2] == 5 + mv[2] = 6 + else: + assert mv[2] == '\x05' + mv[2] = '\x06' + assert v[2] == 6 + + with pytest.raises(RuntimeError) as excinfo: + m.create_undeclstruct() # Undeclared struct contents, no buffer interface + assert "NumPy type info missing for " in str(excinfo.value) + + +@pytest.unsupported_on_pypy +@pytest.requires_numpy +def test_vector_buffer_numpy(): + a = np.array([1, 2, 3, 4], dtype=np.int32) + with pytest.raises(TypeError): + m.VectorInt(a) + + a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], dtype=np.uintc) + v = m.VectorInt(a[0, :]) + assert len(v) == 4 + assert v[2] == 3 + ma = np.asarray(v) + ma[2] = 5 + assert v[2] == 5 + + v = m.VectorInt(a[:, 1]) + assert len(v) == 3 + assert v[2] == 10 + + v = m.get_vectorstruct() + assert v[0].x == 5 + ma = np.asarray(v) + ma[1]['x'] = 99 + assert v[1].x == 99 + + v = m.VectorStruct(np.zeros(3, dtype=np.dtype([('w', 'bool'), ('x', 'I'), + ('y', 'float64'), ('z', 'bool')], align=True))) + assert len(v) == 3 + + +def test_vector_bool(): + import pybind11_cross_module_tests as cm + + vv_c = cm.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_vector_custom(): + v_a = m.VectorEl() + v_a.append(m.El(1)) + v_a.append(m.El(2)) + assert str(v_a) == "VectorEl[El{1}, El{2}]" + + vv_a = m.VectorVectorEl() + vv_a.append(v_a) + vv_b = vv_a[0] + assert str(vv_b) == "VectorEl[El{1}, El{2}]" + + +def test_map_string_double(): + mm = m.MapStringDouble() + mm['a'] = 1 + mm['b'] = 2.5 + + assert list(mm) == ['a', 'b'] + assert list(mm.items()) == [('a', 1), ('b', 2.5)] + assert str(mm) == "MapStringDouble{a: 1, b: 2.5}" + + um = m.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(): + mc = m.MapStringDoubleConst() + mc['a'] = 10 + mc['b'] = 20.5 + assert str(mc) == "MapStringDoubleConst{a: 10, b: 20.5}" + + umc = m.UnorderedMapStringDoubleConst() + umc['a'] = 11 + umc['b'] = 21.5 + + str(umc) + + +def test_noncopyable_containers(): + # std::vector + vnc = m.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 + + # std::deque + dnc = m.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 + + # std::map + mnc = m.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 + + # std::unordered_map + mnc = m.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 + + +def test_map_delitem(): + mm = m.MapStringDouble() + mm['a'] = 1 + mm['b'] = 2.5 + + assert list(mm) == ['a', 'b'] + assert list(mm.items()) == [('a', 1), ('b', 2.5)] + del mm['a'] + assert list(mm) == ['b'] + assert list(mm.items()) == [('b', 2.5)] + + um = m.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)] + del um['ua'] + assert sorted(list(um)) == ['ub'] + assert sorted(list(um.items())) == [('ub', 2.6)] diff --git a/pybind11/tests/test_tagbased_polymorphic.cpp b/pybind11/tests/test_tagbased_polymorphic.cpp new file mode 100644 index 0000000..272e460 --- /dev/null +++ b/pybind11/tests/test_tagbased_polymorphic.cpp @@ -0,0 +1,136 @@ +/* + tests/test_tagbased_polymorphic.cpp -- test of polymorphic_type_hook + + Copyright (c) 2018 Hudson River Trading LLC + + 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 + +struct Animal +{ + enum class Kind { + Unknown = 0, + Dog = 100, Labrador, Chihuahua, LastDog = 199, + Cat = 200, Panther, LastCat = 299 + }; + static const std::type_info* type_of_kind(Kind kind); + static std::string name_of_kind(Kind kind); + + const Kind kind; + const std::string name; + + protected: + Animal(const std::string& _name, Kind _kind) + : kind(_kind), name(_name) + {} +}; + +struct Dog : Animal +{ + Dog(const std::string& _name, Kind _kind = Kind::Dog) : Animal(_name, _kind) {} + std::string bark() const { return name_of_kind(kind) + " " + name + " goes " + sound; } + std::string sound = "WOOF!"; +}; + +struct Labrador : Dog +{ + Labrador(const std::string& _name, int _excitement = 9001) + : Dog(_name, Kind::Labrador), excitement(_excitement) {} + int excitement; +}; + +struct Chihuahua : Dog +{ + Chihuahua(const std::string& _name) : Dog(_name, Kind::Chihuahua) { sound = "iyiyiyiyiyi"; } + std::string bark() const { return Dog::bark() + " and runs in circles"; } +}; + +struct Cat : Animal +{ + Cat(const std::string& _name, Kind _kind = Kind::Cat) : Animal(_name, _kind) {} + std::string purr() const { return "mrowr"; } +}; + +struct Panther : Cat +{ + Panther(const std::string& _name) : Cat(_name, Kind::Panther) {} + std::string purr() const { return "mrrrRRRRRR"; } +}; + +std::vector> create_zoo() +{ + std::vector> ret; + ret.emplace_back(new Labrador("Fido", 15000)); + + // simulate some new type of Dog that the Python bindings + // haven't been updated for; it should still be considered + // a Dog, not just an Animal. + ret.emplace_back(new Dog("Ginger", Dog::Kind(150))); + + ret.emplace_back(new Chihuahua("Hertzl")); + ret.emplace_back(new Cat("Tiger", Cat::Kind::Cat)); + ret.emplace_back(new Panther("Leo")); + return ret; +} + +const std::type_info* Animal::type_of_kind(Kind kind) +{ + switch (kind) { + case Kind::Unknown: break; + + case Kind::Dog: break; + case Kind::Labrador: return &typeid(Labrador); + case Kind::Chihuahua: return &typeid(Chihuahua); + case Kind::LastDog: break; + + case Kind::Cat: break; + case Kind::Panther: return &typeid(Panther); + case Kind::LastCat: break; + } + + if (kind >= Kind::Dog && kind <= Kind::LastDog) return &typeid(Dog); + if (kind >= Kind::Cat && kind <= Kind::LastCat) return &typeid(Cat); + return nullptr; +} + +std::string Animal::name_of_kind(Kind kind) +{ + std::string raw_name = type_of_kind(kind)->name(); + py::detail::clean_type_id(raw_name); + return raw_name; +} + +namespace pybind11 { + template + struct polymorphic_type_hook::value>> + { + static const void *get(const itype *src, const std::type_info*& type) + { type = src ? Animal::type_of_kind(src->kind) : nullptr; return src; } + }; +} + +TEST_SUBMODULE(tagbased_polymorphic, m) { + py::class_(m, "Animal") + .def_readonly("name", &Animal::name); + py::class_(m, "Dog") + .def(py::init()) + .def_readwrite("sound", &Dog::sound) + .def("bark", &Dog::bark); + py::class_(m, "Labrador") + .def(py::init(), "name"_a, "excitement"_a = 9001) + .def_readwrite("excitement", &Labrador::excitement); + py::class_(m, "Chihuahua") + .def(py::init()) + .def("bark", &Chihuahua::bark); + py::class_(m, "Cat") + .def(py::init()) + .def("purr", &Cat::purr); + py::class_(m, "Panther") + .def(py::init()) + .def("purr", &Panther::purr); + m.def("create_zoo", &create_zoo); +}; diff --git a/pybind11/tests/test_tagbased_polymorphic.py b/pybind11/tests/test_tagbased_polymorphic.py new file mode 100644 index 0000000..2574d7d --- /dev/null +++ b/pybind11/tests/test_tagbased_polymorphic.py @@ -0,0 +1,20 @@ +from pybind11_tests import tagbased_polymorphic as m + + +def test_downcast(): + zoo = m.create_zoo() + assert [type(animal) for animal in zoo] == [ + m.Labrador, m.Dog, m.Chihuahua, m.Cat, m.Panther + ] + assert [animal.name for animal in zoo] == [ + "Fido", "Ginger", "Hertzl", "Tiger", "Leo" + ] + zoo[1].sound = "woooooo" + assert [dog.bark() for dog in zoo[:3]] == [ + "Labrador Fido goes WOOF!", + "Dog Ginger goes woooooo", + "Chihuahua Hertzl goes iyiyiyiyiyi and runs in circles" + ] + assert [cat.purr() for cat in zoo[3:]] == ["mrowr", "mrrrRRRRRR"] + zoo[0].excitement -= 1000 + assert zoo[0].excitement == 14000 diff --git a/pybind11/tests/test_virtual_functions.cpp b/pybind11/tests/test_virtual_functions.cpp new file mode 100644 index 0000000..c9a561c --- /dev/null +++ b/pybind11/tests/test_virtual_functions.cpp @@ -0,0 +1,478 @@ +/* + 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 +#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; } + virtual ~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); + } +}; + +struct Base { + /* for some reason MSVC2015 can't compile this if the function is pure virtual */ + virtual std::string dispatch() const { return {}; }; + virtual ~Base() = default; +}; + +struct DispatchIssue : Base { + virtual std::string dispatch() const { + PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */); + } +}; + +static void test_gil() { + { + py::gil_scoped_acquire lock; + py::print("1st lock acquired"); + + } + + { + py::gil_scoped_acquire lock; + py::print("2nd lock acquired"); + } + +} + +static void test_gil_from_thread() { + py::gil_scoped_release release; + + std::thread t(test_gil); + t.join(); +} + + +// Forward declaration (so that we can put the main tests here; the inherited virtual approaches are +// rather long). +void initialize_inherited_virtuals(py::module &m); + +TEST_SUBMODULE(virtual_functions, m) { + // test_override + 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()); + + // test_move_support +#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", [](ExampleVirt *ex, int value) { return ex->run(value); }); + m.def("runExampleVirtBool", [](ExampleVirt* ex) { return ex->run_bool(); }); + m.def("runExampleVirtVirtual", [](ExampleVirt *ex) { ex->pure_virtual(); }); + + m.def("cstats_debug", &ConstructorStats::get); + initialize_inherited_virtuals(m); + + // test_alias_delay_initialization1 + // 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()"); + // This convolution just gives a `void`, but tests that PYBIND11_TYPE() works to protect + // a type containing a , + PYBIND11_OVERLOAD(PYBIND11_TYPE(typename std::enable_if::type), A, f); + } + }; + + py::class_(m, "A") + .def(py::init<>()) + .def("f", &A::f); + + m.def("call_f", [](A *a) { a->f(); }); + + // test_alias_delay_initialization2 + // ... 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(py::init([](int) { return new PyA2(); })) + .def("f", &A2::f); + + m.def("call_f", [](A2 *a2) { a2->f(); }); + + // test_dispatch_issue + // #159: virtual function dispatch has problems with similar-named functions + py::class_(m, "DispatchIssue") + .def(py::init<>()) + .def("dispatch", &Base::dispatch); + + m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); }); + + // test_override_ref + // #392/397: overriding 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; } + virtual ~OverrideTest() = default; + }; + + 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_(m, "OverrideTest_A") + .def_readwrite("value", &OverrideTest::A::value); + py::class_(m, "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); +} + + +// 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 + virtual ~A_Repeat() = default; +}; +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; virtual ~A_Tpl() = default; }; +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) { + // test_inherited_virtuals + + // 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<>()); + + // test_ + // 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<>()); + + + // Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7) + m.def("test_gil", &test_gil); + m.def("test_gil_from_thread", &test_gil_from_thread); +}; diff --git a/pybind11/tests/test_virtual_functions.py b/pybind11/tests/test_virtual_functions.py new file mode 100644 index 0000000..5ce9abd --- /dev/null +++ b/pybind11/tests/test_virtual_functions.py @@ -0,0 +1,377 @@ +import pytest + +from pybind11_tests import virtual_functions as m +from pybind11_tests import ConstructorStats + + +def test_override(capture, msg): + class ExtendedExampleVirt(m.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 = m.ExampleVirt(10) + with capture: + assert m.runExampleVirt(ex12, 20) == 30 + assert capture == """ + Original implementation of ExampleVirt::run(state=10, value=20, str1=default1, str2=default2) + """ # noqa: E501 line too long + + with pytest.raises(RuntimeError) as excinfo: + m.runExampleVirtVirtual(ex12) + assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"' + + ex12p = ExtendedExampleVirt(10) + with capture: + assert m.runExampleVirt(ex12p, 20) == 32 + assert capture == """ + ExtendedExampleVirt::run(20), calling parent.. + Original implementation of ExampleVirt::run(state=11, value=21, str1=override1, str2=default2) + """ # noqa: E501 line too long + with capture: + assert m.runExampleVirtBool(ex12p) is False + assert capture == "ExtendedExampleVirt::run_bool()" + with capture: + m.runExampleVirtVirtual(ex12p) + assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world" + + ex12p2 = ExtendedExampleVirt2(15) + with capture: + assert m.runExampleVirt(ex12p2, 50) == 68 + assert capture == """ + ExtendedExampleVirt::run(50), calling parent.. + Original implementation of ExampleVirt::run(state=17, value=51, str1=override1, str2=override2) + """ # noqa: E501 line too long + + cstats = ConstructorStats.get(m.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_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). + """ + class B(m.A): + def __init__(self): + super(B, self).__init__() + + def f(self): + print("In python f()") + + # C++ version + with capture: + a = m.A() + m.call_f(a) + del a + pytest.gc_collect() + assert capture == "A.f()" + + # Python version + with capture: + b = B() + m.call_f(b) + del b + pytest.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. + """ + class B2(m.A2): + def __init__(self): + super(B2, self).__init__() + + def f(self): + print("In python B2.f()") + + # No python subclass version + with capture: + a2 = m.A2() + m.call_f(a2) + del a2 + pytest.gc_collect() + a3 = m.A2(1) + m.call_f(a3) + del a3 + pytest.gc_collect() + assert capture == """ + PyA2.PyA2() + PyA2.f() + A2.f() + PyA2.~PyA2() + PyA2.PyA2() + PyA2.f() + A2.f() + PyA2.~PyA2() + """ + + # Python subclass version + with capture: + b2 = B2() + m.call_f(b2) + del b2 + pytest.gc_collect() + assert capture == """ + PyA2.PyA2() + PyA2.f() + In python B2.f() + PyA2.~PyA2() + """ + + +# PyPy: Reference count > 1 causes call with noncopyable instance +# to fail in ncv1.print_nc() +@pytest.unsupported_on_pypy +@pytest.mark.skipif(not hasattr(m, "NCVirt"), reason="NCVirt test broken on ICPC") +def test_move_support(): + class NCVirtExt(m.NCVirt): + def get_noncopyable(self, a, b): + # Constructs and returns a new instance: + nc = m.NonCopyable(a * a, b * b) + return nc + + def get_movable(self, a, b): + # Return a referenced copy + self.movable = m.Movable(a, b) + return self.movable + + class NCVirtExt2(m.NCVirt): + def get_noncopyable(self, a, b): + # Keep a reference: this is going to throw an exception + self.nc = m.NonCopyable(a, b) + return self.nc + + def get_movable(self, a, b): + # Return a new instance without storing it + return m.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(m.NonCopyable) + mv_stats = ConstructorStats.get(m.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 + + +def test_dispatch_issue(msg): + """#159: virtual function dispatch has problems with similar-named functions""" + class PyClass1(m.DispatchIssue): + def dispatch(self): + return "Yay.." + + class PyClass2(m.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 m.dispatch_issue_go(p) + + b = PyClass2() + assert m.dispatch_issue_go(b) == "Yay.." + + +def test_override_ref(): + """#392/397: overriding reference-returning functions""" + o = m.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_inherited_virtuals(): + class AR(m.A_Repeat): + def unlucky_number(self): + return 99 + + class AT(m.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 [m.B_Repeat(), m.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 [m.C_Repeat(), m.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(m.C_Repeat): + def lucky_number(self): + return m.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(m.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(m.D_Repeat): + def unlucky_number(self): + return 123 + + def lucky_number(self): + return 42.0 + + for obj in [m.D_Repeat(), m.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(m.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(m.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" + + +def test_issue_1454(): + # Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7) + m.test_gil() + m.test_gil_from_thread() diff --git a/pybind11/tools/FindCatch.cmake b/pybind11/tools/FindCatch.cmake new file mode 100644 index 0000000..9d490c5 --- /dev/null +++ b/pybind11/tools/FindCatch.cmake @@ -0,0 +1,57 @@ +# - Find the Catch test framework or download it (single header) +# +# This is a quick module for internal use. It assumes that Catch is +# REQUIRED and that a minimum version is provided (not EXACT). If +# a suitable version isn't found locally, the single header file +# will be downloaded and placed in the build dir: PROJECT_BINARY_DIR. +# +# This code sets the following variables: +# CATCH_INCLUDE_DIR - path to catch.hpp +# CATCH_VERSION - version number + +if(NOT Catch_FIND_VERSION) + message(FATAL_ERROR "A version number must be specified.") +elseif(Catch_FIND_REQUIRED) + message(FATAL_ERROR "This module assumes Catch is not required.") +elseif(Catch_FIND_VERSION_EXACT) + message(FATAL_ERROR "Exact version numbers are not supported, only minimum.") +endif() + +# Extract the version number from catch.hpp +function(_get_catch_version) + file(STRINGS "${CATCH_INCLUDE_DIR}/catch.hpp" version_line REGEX "Catch v.*" LIMIT_COUNT 1) + if(version_line MATCHES "Catch v([0-9]+)\\.([0-9]+)\\.([0-9]+)") + set(CATCH_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}" PARENT_SCOPE) + endif() +endfunction() + +# Download the single-header version of Catch +function(_download_catch version destination_dir) + message(STATUS "Downloading catch v${version}...") + set(url https://github.com/philsquared/Catch/releases/download/v${version}/catch.hpp) + file(DOWNLOAD ${url} "${destination_dir}/catch.hpp" STATUS status) + list(GET status 0 error) + if(error) + message(FATAL_ERROR "Could not download ${url}") + endif() + set(CATCH_INCLUDE_DIR "${destination_dir}" CACHE INTERNAL "") +endfunction() + +# Look for catch locally +find_path(CATCH_INCLUDE_DIR NAMES catch.hpp PATH_SUFFIXES catch) +if(CATCH_INCLUDE_DIR) + _get_catch_version() +endif() + +# Download the header if it wasn't found or if it's outdated +if(NOT CATCH_VERSION OR CATCH_VERSION VERSION_LESS ${Catch_FIND_VERSION}) + if(DOWNLOAD_CATCH) + _download_catch(${Catch_FIND_VERSION} "${PROJECT_BINARY_DIR}/catch/") + _get_catch_version() + else() + set(CATCH_FOUND FALSE) + return() + endif() +endif() + +set(CATCH_FOUND TRUE) diff --git a/pybind11/tools/FindEigen3.cmake b/pybind11/tools/FindEigen3.cmake new file mode 100644 index 0000000..9c546a0 --- /dev/null +++ b/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/pybind11/tools/FindPythonLibsNew.cmake b/pybind11/tools/FindPythonLibsNew.cmake new file mode 100644 index 0000000..919a384 --- /dev/null +++ b/pybind11/tools/FindPythonLibsNew.cmake @@ -0,0 +1,198 @@ +# - Find python libraries +# This module finds the libraries corresponding to the Python interpreter +# 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. +#============================================================================= + +# Checking for the extension makes sure that `LibsNew` was found and not just `Libs`. +if(PYTHONLIBS_FOUND AND PYTHON_MODULE_EXTENSION) + 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 +if(WIN32) + string(REGEX REPLACE "\\\\" "/" _PYTHON_VALUES ${_PYTHON_VALUES}) +endif() +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/pybind11/tools/check-style.sh b/pybind11/tools/check-style.sh new file mode 100644 index 0000000..0a9f7d2 --- /dev/null +++ b/pybind11/tools/check-style.sh @@ -0,0 +1,70 @@ +#!/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. MSDOS-style CRLF endings +# 3. trailing spaces +# 4. missing space between keyword and parenthesis, e.g.: for(, if(, while( +# 5. Missing space between right parenthesis and brace, e.g. 'for (...){' +# 6. opening brace on its own line. It should always be on the same line as the +# if/while/for/do statement. +# +# Invoke as: tools/check-style.sh +# + +check_style_errors=0 +IFS=$'\n' + +found="$( GREP_COLORS='mt=41' GREP_COLOR='41' grep $'\t' include tests/*.{cpp,py,h} docs/*.rst -rn --color=always )" +if [ -n "$found" ]; then + # The mt=41 sets a red background for matched tabs: + echo -e '\033[31;01mError: found tab characters in the following files:\033[0m' + check_style_errors=1 + echo "$found" | sed -e 's/^/ /' +fi + + +found="$( grep -IUlr $'\r' include tests/*.{cpp,py,h} docs/*.rst --color=always )" +if [ -n "$found" ]; then + echo -e '\033[31;01mError: found CRLF characters in the following files:\033[0m' + check_style_errors=1 + echo "$found" | sed -e 's/^/ /' +fi + +found="$(GREP_COLORS='mt=41' GREP_COLOR='41' grep '[[:blank:]]\+$' include tests/*.{cpp,py,h} docs/*.rst -rn --color=always )" +if [ -n "$found" ]; then + # The mt=41 sets a red background for matched trailing spaces + echo -e '\033[31;01mError: found trailing spaces in the following files:\033[0m' + check_style_errors=1 + echo "$found" | sed -e 's/^/ /' +fi + +found="$(grep '\<\(if\|for\|while\|catch\)(\|){' include tests/*.{cpp,h} -rn --color=always)" +if [ -n "$found" ]; then + echo -e '\033[31;01mError: found the following coding style problems:\033[0m' + check_style_errors=1 + echo "$found" | sed -e 's/^/ /' +fi + +found="$(awk ' +function prefix(filename, lineno) { + return " \033[35m" filename "\033[36m:\033[32m" lineno "\033[36m:\033[0m" +} +function mark(pattern, string) { sub(pattern, "\033[01;31m&\033[0m", string); return string } +last && /^\s*{/ { + print prefix(FILENAME, FNR-1) mark("\\)\\s*$", last) + print prefix(FILENAME, FNR) mark("^\\s*{", $0) + last="" +} +{ last = /(if|for|while|catch|switch)\s*\(.*\)\s*$/ ? $0 : "" } +' $(find include -type f) tests/*.{cpp,h} docs/*.rst)" +if [ -n "$found" ]; then + check_style_errors=1 + echo -e '\033[31;01mError: braces should occur on the same line as the if/while/.. statement. Found issues in the following files:\033[0m' + echo "$found" +fi + +exit $check_style_errors diff --git a/pybind11/tools/libsize.py b/pybind11/tools/libsize.py new file mode 100644 index 0000000..5dcb8b0 --- /dev/null +++ b/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/pybind11/tools/mkdoc.py b/pybind11/tools/mkdoc.py new file mode 100644 index 0000000..1fd8cce --- /dev/null +++ b/pybind11/tools/mkdoc.py @@ -0,0 +1,304 @@ +#!/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) + +output = [] + +def d(s): + return s.decode('utf8') + + +def sanitize_name(name): + 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)) + 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): + 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(): + extract(filename, i, sub_prefix) + 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)) + global output + output.append((name, filename, comment)) + + +class ExtractionThread(Thread): + def __init__(self, filename, parameters): + Thread.__init__(self) + self.filename = filename + self.parameters = parameters + 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, '') + 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.clear() + for filename in filenames: + thr = ExtractionThread(filename, parameters) + thr.start() + + print('Waiting for jobs to finish ..', file=sys.stderr) + for i in range(job_count): + job_semaphore.acquire() + + name_ctr = 1 + name_prev = None + for name, _, comment in list(sorted(output, key=lambda x: (x[0], x[1]))): + if name == name_prev: + name_ctr += 1 + name = name + "_%i" % name_ctr + else: + name_prev = name + name_ctr = 1 + print('\nstatic const char *%s =%sR"doc(%s)doc";' % + (name, '\n' if '\n' in comment else ' ', comment)) + + print(''' +#if defined(__GNUG__) +#pragma GCC diagnostic pop +#endif +''') diff --git a/pybind11/tools/pybind11Config.cmake.in b/pybind11/tools/pybind11Config.cmake.in new file mode 100644 index 0000000..3dd1b2c --- /dev/null +++ b/pybind11/tools/pybind11Config.cmake.in @@ -0,0 +1,100 @@ +# pybind11Config.cmake +# -------------------- +# +# PYBIND11 cmake module. +# This module sets the following variables in your project:: +# +# pybind11_FOUND - true if pybind11 and all required components found on the system +# pybind11_VERSION - pybind11 version in format Major.Minor.Release +# pybind11_INCLUDE_DIRS - Directories where pybind11 and python headers are located. +# pybind11_INCLUDE_DIR - Directory where pybind11 headers are located. +# pybind11_DEFINITIONS - Definitions necessary to use pybind11, namely USING_pybind11. +# pybind11_LIBRARIES - compile flags and python libraries (as needed) to link against. +# pybind11_LIBRARY - empty. +# CMAKE_MODULE_PATH - appends location of accompanying FindPythonLibsNew.cmake and +# pybind11Tools.cmake modules. +# +# +# Available components: None +# +# +# Exported targets:: +# +# If pybind11 is found, this module defines the following :prop_tgt:`IMPORTED` +# interface library targets:: +# +# pybind11::module - for extension modules +# pybind11::embed - for embedding the Python interpreter +# +# Python headers, libraries (as needed by platform), and the C++ standard +# are attached to the target. Set PythonLibsNew variables to influence +# python detection and PYBIND11_CPP_STANDARD (-std=c++11 or -std=c++14) to +# influence standard setting. :: +# +# find_package(pybind11 CONFIG REQUIRED) +# message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}") +# +# # Create an extension module +# add_library(mylib MODULE main.cpp) +# target_link_libraries(mylib pybind11::module) +# +# # Or embed the Python interpreter into an executable +# add_executable(myexe main.cpp) +# target_link_libraries(myexe pybind11::embed) +# +# Suggested usage:: +# +# find_package with version info is not recommended except for release versions. :: +# +# find_package(pybind11 CONFIG) +# find_package(pybind11 2.0 EXACT CONFIG REQUIRED) +# +# +# The following variables can be set to guide the search for this package:: +# +# pybind11_DIR - CMake variable, set to directory containing this Config file +# CMAKE_PREFIX_PATH - CMake variable, set to root directory of this package +# PATH - environment variable, set to bin directory of this package +# CMAKE_DISABLE_FIND_PACKAGE_pybind11 - CMake variable, disables +# find_package(pybind11) when not REQUIRED, perhaps to force internal build + +@PACKAGE_INIT@ + +set(PN pybind11) + +# location of pybind11/pybind11.h +set(${PN}_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/@CMAKE_INSTALL_INCLUDEDIR@") + +set(${PN}_LIBRARY "") +set(${PN}_DEFINITIONS USING_${PN}) + +check_required_components(${PN}) + +# make detectable the FindPythonLibsNew.cmake module +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) + +include(pybind11Tools) + +if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) +#----------------------------------------------------------------------------- +# Don't include targets if this file is being picked up by another +# project which has already built this as a subproject +#----------------------------------------------------------------------------- +if(NOT TARGET ${PN}::pybind11) + include("${CMAKE_CURRENT_LIST_DIR}/${PN}Targets.cmake") + + find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} MODULE REQUIRED) + set_property(TARGET ${PN}::pybind11 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PYTHON_INCLUDE_DIRS}) + set_property(TARGET ${PN}::embed APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${PYTHON_LIBRARIES}) + if(WIN32 OR CYGWIN) + set_property(TARGET ${PN}::module APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${PYTHON_LIBRARIES}) + endif() + + set_property(TARGET ${PN}::pybind11 APPEND PROPERTY INTERFACE_COMPILE_OPTIONS "${PYBIND11_CPP_STANDARD}") + + get_property(_iid TARGET ${PN}::pybind11 PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + get_property(_ill TARGET ${PN}::module PROPERTY INTERFACE_LINK_LIBRARIES) + set(${PN}_INCLUDE_DIRS ${_iid}) + set(${PN}_LIBRARIES ${_ico} ${_ill}) +endif() +endif() diff --git a/pybind11/tools/pybind11Tools.cmake b/pybind11/tools/pybind11Tools.cmake new file mode 100644 index 0000000..ab8bf62 --- /dev/null +++ b/pybind11/tools/pybind11Tools.cmake @@ -0,0 +1,223 @@ +# tools/pybind11Tools.cmake -- 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) + +# Add a CMake parameter for choosing a desired Python version +if(NOT PYBIND11_PYTHON_VERSION) + set(PYBIND11_PYTHON_VERSION "" CACHE STRING "Python version to use for compiling modules") +endif() + +set(Python_ADDITIONAL_VERSIONS 3.7 3.6 3.5 3.4) +find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} REQUIRED) + +include(CheckCXXCompilerFlag) +include(CMakeParseArguments) + +if(NOT PYBIND11_CPP_STANDARD AND NOT CMAKE_CXX_STANDARD) + if(NOT MSVC) + check_cxx_compiler_flag("-std=c++14" HAS_CPP14_FLAG) + + if (HAS_CPP14_FLAG) + set(PYBIND11_CPP_STANDARD -std=c++14) + else() + check_cxx_compiler_flag("-std=c++11" HAS_CPP11_FLAG) + if (HAS_CPP11_FLAG) + set(PYBIND11_CPP_STANDARD -std=c++11) + else() + message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!") + endif() + endif() + elseif(MSVC) + set(PYBIND11_CPP_STANDARD /std:c++14) + endif() + + set(PYBIND11_CPP_STANDARD ${PYBIND11_CPP_STANDARD} CACHE STRING + "C++ standard flag, e.g. -std=c++11, -std=c++14, /std:c++14. Defaults to C++14 mode." FORCE) +endif() + +# Checks whether the given CXX/linker flags can compile and link a cxx file. cxxflags and +# linkerflags are lists of flags to use. The result variable is a unique variable name for each set +# of flags: the compilation result will be cached base on the result variable. If the flags work, +# sets them in cxxflags_out/linkerflags_out internal cache variables (in addition to ${result}). +function(_pybind11_return_if_cxx_and_linker_flags_work result cxxflags linkerflags cxxflags_out linkerflags_out) + set(CMAKE_REQUIRED_LIBRARIES ${linkerflags}) + check_cxx_compiler_flag("${cxxflags}" ${result}) + if (${result}) + set(${cxxflags_out} "${cxxflags}" CACHE INTERNAL "" FORCE) + set(${linkerflags_out} "${linkerflags}" CACHE INTERNAL "" FORCE) + endif() +endfunction() + +# Internal: find the appropriate link time optimization flags for this compiler +function(_pybind11_add_lto_flags target_name prefer_thin_lto) + if (NOT DEFINED PYBIND11_LTO_CXX_FLAGS) + set(PYBIND11_LTO_CXX_FLAGS "" CACHE INTERNAL "") + set(PYBIND11_LTO_LINKER_FLAGS "" CACHE INTERNAL "") + + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + set(cxx_append "") + set(linker_append "") + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT APPLE) + # Clang Gold plugin does not support -Os; append -O3 to MinSizeRel builds to override it + set(linker_append ";$<$:-O3>") + elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + set(cxx_append ";-fno-fat-lto-objects") + endif() + + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND prefer_thin_lto) + _pybind11_return_if_cxx_and_linker_flags_work(HAS_FLTO_THIN + "-flto=thin${cxx_append}" "-flto=thin${linker_append}" + PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) + endif() + + if (NOT HAS_FLTO_THIN) + _pybind11_return_if_cxx_and_linker_flags_work(HAS_FLTO + "-flto${cxx_append}" "-flto${linker_append}" + PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) + endif() + elseif (CMAKE_CXX_COMPILER_ID MATCHES "Intel") + # Intel equivalent to LTO is called IPO + _pybind11_return_if_cxx_and_linker_flags_work(HAS_INTEL_IPO + "-ipo" "-ipo" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) + elseif(MSVC) + # cmake only interprets libraries as linker flags when they start with a - (otherwise it + # converts /LTCG to \LTCG as if it was a Windows path). Luckily MSVC supports passing flags + # with - instead of /, even if it is a bit non-standard: + _pybind11_return_if_cxx_and_linker_flags_work(HAS_MSVC_GL_LTCG + "/GL" "-LTCG" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) + endif() + + if (PYBIND11_LTO_CXX_FLAGS) + message(STATUS "LTO enabled") + else() + message(STATUS "LTO disabled (not supported by the compiler and/or linker)") + endif() + endif() + + # Enable LTO flags if found, except for Debug builds + if (PYBIND11_LTO_CXX_FLAGS) + target_compile_options(${target_name} PRIVATE "$<$>:${PYBIND11_LTO_CXX_FLAGS}>") + endif() + if (PYBIND11_LTO_LINKER_FLAGS) + target_link_libraries(${target_name} PRIVATE "$<$>:${PYBIND11_LTO_LINKER_FLAGS}>") + endif() +endfunction() + +# Build a Python extension module: +# pybind11_add_module( [MODULE | SHARED] [EXCLUDE_FROM_ALL] +# [NO_EXTRAS] [SYSTEM] [THIN_LTO] source1 [source2 ...]) +# +function(pybind11_add_module target_name) + set(options MODULE SHARED EXCLUDE_FROM_ALL NO_EXTRAS SYSTEM THIN_LTO) + cmake_parse_arguments(ARG "${options}" "" "" ${ARGN}) + + if(ARG_MODULE AND ARG_SHARED) + message(FATAL_ERROR "Can't be both MODULE and SHARED") + elseif(ARG_SHARED) + set(lib_type SHARED) + else() + set(lib_type MODULE) + endif() + + if(ARG_EXCLUDE_FROM_ALL) + set(exclude_from_all EXCLUDE_FROM_ALL) + endif() + + add_library(${target_name} ${lib_type} ${exclude_from_all} ${ARG_UNPARSED_ARGUMENTS}) + + if(ARG_SYSTEM) + set(inc_isystem SYSTEM) + endif() + + target_include_directories(${target_name} ${inc_isystem} + PRIVATE ${PYBIND11_INCLUDE_DIR} # from project CMakeLists.txt + PRIVATE ${pybind11_INCLUDE_DIR} # from pybind11Config + PRIVATE ${PYTHON_INCLUDE_DIRS}) + + # Python debug libraries expose slightly different objects + # https://docs.python.org/3.6/c-api/intro.html#debugging-builds + # https://stackoverflow.com/questions/39161202/how-to-work-around-missing-pymodule-create2-in-amd64-win-python35-d-lib + if(PYTHON_IS_DEBUG) + target_compile_definitions(${target_name} PRIVATE Py_DEBUG) + endif() + + # 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}") + + # -fvisibility=hidden is required to allow multiple modules compiled against + # different pybind versions to work properly, and for some features (e.g. + # py::module_local). We force it on everything inside the `pybind11` + # namespace; also turning it on for a pybind module compilation here avoids + # potential warnings or issues from having mixed hidden/non-hidden types. + set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden") + set_target_properties(${target_name} PROPERTIES CUDA_VISIBILITY_PRESET "hidden") + + 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") + + if(ARG_SHARED) + # Suppress CMake >= 3.0 warning for shared libraries + set_target_properties(${target_name} PROPERTIES MACOSX_RPATH ON) + endif() + endif() + + # Make sure C++11/14 are enabled + target_compile_options(${target_name} PUBLIC ${PYBIND11_CPP_STANDARD}) + + if(ARG_NO_EXTRAS) + return() + endif() + + _pybind11_add_lto_flags(${target_name} ${ARG_THIN_LTO}) + + if (NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug) + # 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} -x $) + else() + add_custom_command(TARGET ${target_name} POST_BUILD + COMMAND ${CMAKE_STRIP} $) + endif() + endif() + endif() + + if(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 /bigobj) + if(CMAKE_VERSION VERSION_LESS 3.11) + target_compile_options(${target_name} PRIVATE $<$>:/MP>) + else() + # Only set these options for C++ files. This is important so that, for + # instance, projects that include other types of source files like CUDA + # .cu files don't get these options propagated to nvcc since that would + # cause the build to fail. + target_compile_options(${target_name} PRIVATE $<$>:$<$:/MP>>) + endif() + endif() +endfunction() diff --git a/ref/PythonGraphPers_withCompInfo.so b/ref/PythonGraphPers_withCompInfo.so new file mode 100644 index 0000000000000000000000000000000000000000..2e5e6b6163923f823515f404a50ec6d220d14318 GIT binary patch literal 4463808 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 qEzqf;kh-QJytH)l)943 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

    &Yz>LPwMCJPyxf2jpg4LIx=TBFnM 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%0AC`|Ax6hx6hBB0F|2pFA;tv!#{oOU5byFs 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�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