From a0c1ccf0a9487ce2516ad8eee27202e512affb60 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Fri, 12 Aug 2016 13:50:00 +0200 Subject: [PATCH 1/8] Port tests to pytest Use simple asserts and pytest's powerful introspection to make testing simpler. This merges the old .py/.ref file pairs into simple .py files where the expected values are right next to the code being tested. This commit does not touch the C++ part of the code and replicates the Python tests exactly like the old .ref-file-based approach. --- .appveyor.yml | 7 +- .gitignore | 8 +- .travis.yml | 4 +- CMakeLists.txt | 12 +- example/CMakeLists.txt | 68 ----- example/eigen.py | 114 -------- example/eigen.ref | 60 ---- example/example-arg-keywords-and-defaults.py | 53 ---- example/example-arg-keywords-and-defaults.ref | 75 ----- example/example-buffers.py | 45 --- example/example-buffers.ref | 24 -- example/example-callbacks.py | 95 ------ example/example-callbacks.ref | 46 --- example/example-constants-and-functions.py | 96 ------- example/example-constants-and-functions.ref | 56 ---- example/example-custom-exceptions.py | 42 --- example/example-custom-exceptions.ref | 15 - example/example-eval.py | 5 - example/example-eval.ref | 13 - example/example-eval_call.py | 1 - example/example-inheritance.py | 12 - example/example-inheritance.ref | 3 - example/example-keep-alive.py | 67 ----- example/example-keep-alive.ref | 33 --- example/example-methods-and-attributes.py | 50 ---- example/example-methods-and-attributes.ref | 34 --- example/example-modules.py | 43 --- example/example-modules.ref | 31 -- example/example-numpy-dtypes.py | 102 ------- example/example-numpy-dtypes.ref | 28 -- example/example-numpy-vectorize.py | 36 --- example/example-numpy-vectorize.ref | 79 ----- example/example-opaque-types.py | 52 ---- example/example-opaque-types.ref | 19 -- example/example-operator-overloading.py | 41 --- example/example-operator-overloading.ref | 66 ----- example/example-pickling.py | 21 -- example/example-pickling.ref | 2 - example/example-python-types.py | 85 ------ example/example-python-types.ref | 146 ---------- example/example-sequences-and-iterators.py | 64 ----- example/example-sequences-and-iterators.ref | 41 --- example/example-smart-ptr.py | 85 ------ example/example-smart-ptr.ref | 270 ------------------ example/example-stl-binder-vector.py | 48 ---- example/example-stl-binder-vector.ref | 11 - example/example-virtual-functions.py | 135 --------- example/example-virtual-functions.ref | 106 ------- example/issues.py | 111 ------- example/issues.ref | 55 ---- example/run_test.py | 67 ----- setup.py | 2 +- tests/CMakeLists.txt | 62 ++++ tests/conftest.py | 204 +++++++++++++ .../constructor_stats.h | 7 +- {example => tests}/object.h | 2 +- .../example.cpp => tests/pybind11_tests.cpp | 19 +- example/example.h => tests/pybind11_tests.h | 0 .../test_buffers.cpp | 6 +- tests/test_buffers.py | 57 ++++ .../test_callbacks.cpp | 6 +- tests/test_callbacks.py | 130 +++++++++ .../test_constants_and_functions.cpp | 4 +- tests/test_constants_and_functions.py | 130 +++++++++ example/eigen.cpp => tests/test_eigen.cpp | 4 +- tests/test_eigen.py | 136 +++++++++ .../example-eval.cpp => tests/test_eval.cpp | 8 +- tests/test_eval.py | 22 ++ tests/test_eval_call.py | 4 + .../test_exceptions.cpp | 4 +- tests/test_exceptions.py | 31 ++ .../test_inheritance.cpp | 4 +- tests/test_inheritance.py | 8 + example/issues.cpp => tests/test_issues.cpp | 6 +- tests/test_issues.py | 176 ++++++++++++ .../test_keep_alive.cpp | 4 +- tests/test_keep_alive.py | 98 +++++++ .../test_kwargs_and_defaults.cpp | 4 +- tests/test_kwargs_and_defaults.py | 93 ++++++ .../test_methods_and_attributes.cpp | 6 +- tests/test_methods_and_attributes.py | 46 +++ .../test_modules.cpp | 6 +- tests/test_modules.py | 56 ++++ .../test_numpy_dtypes.cpp | 6 +- tests/test_numpy_dtypes.py | 169 +++++++++++ .../test_numpy_vectorize.cpp | 10 +- tests/test_numpy_vectorize.py | 80 ++++++ .../test_opaque_types.cpp | 8 +- tests/test_opaque_types.py | 64 +++++ .../test_operator_overloading.cpp | 6 +- tests/test_operator_overloading.py | 41 +++ .../test_pickling.cpp | 4 +- tests/test_pickling.py | 18 ++ .../test_python_types.cpp | 6 +- tests/test_python_types.py | 220 ++++++++++++++ .../test_sequences_and_iterators.cpp | 6 +- tests/test_sequences_and_iterators.py | 78 +++++ .../test_smart_ptr.cpp | 4 +- tests/test_smart_ptr.py | 115 ++++++++ .../test_stl_binders.cpp | 4 +- tests/test_stl_binders.py | 53 ++++ .../test_virtual_functions.cpp | 6 +- tests/test_virtual_functions.py | 227 +++++++++++++++ 103 files changed, 2410 insertions(+), 2842 deletions(-) delete mode 100644 example/CMakeLists.txt delete mode 100644 example/eigen.py delete mode 100644 example/eigen.ref delete mode 100755 example/example-arg-keywords-and-defaults.py delete mode 100644 example/example-arg-keywords-and-defaults.ref delete mode 100755 example/example-buffers.py delete mode 100644 example/example-buffers.ref delete mode 100755 example/example-callbacks.py delete mode 100644 example/example-callbacks.ref delete mode 100755 example/example-constants-and-functions.py delete mode 100644 example/example-constants-and-functions.ref delete mode 100644 example/example-custom-exceptions.py delete mode 100644 example/example-custom-exceptions.ref delete mode 100644 example/example-eval.py delete mode 100644 example/example-eval.ref delete mode 100644 example/example-eval_call.py delete mode 100644 example/example-inheritance.py delete mode 100644 example/example-inheritance.ref delete mode 100644 example/example-keep-alive.py delete mode 100644 example/example-keep-alive.ref delete mode 100755 example/example-methods-and-attributes.py delete mode 100644 example/example-methods-and-attributes.ref delete mode 100755 example/example-modules.py delete mode 100644 example/example-modules.ref delete mode 100644 example/example-numpy-dtypes.py delete mode 100644 example/example-numpy-dtypes.ref delete mode 100755 example/example-numpy-vectorize.py delete mode 100644 example/example-numpy-vectorize.ref delete mode 100644 example/example-opaque-types.py delete mode 100644 example/example-opaque-types.ref delete mode 100755 example/example-operator-overloading.py delete mode 100644 example/example-operator-overloading.ref delete mode 100644 example/example-pickling.py delete mode 100644 example/example-pickling.ref delete mode 100755 example/example-python-types.py delete mode 100644 example/example-python-types.ref delete mode 100755 example/example-sequences-and-iterators.py delete mode 100644 example/example-sequences-and-iterators.ref delete mode 100755 example/example-smart-ptr.py delete mode 100644 example/example-smart-ptr.ref delete mode 100644 example/example-stl-binder-vector.py delete mode 100644 example/example-stl-binder-vector.ref delete mode 100644 example/example-virtual-functions.py delete mode 100644 example/example-virtual-functions.ref delete mode 100644 example/issues.py delete mode 100644 example/issues.ref delete mode 100755 example/run_test.py create mode 100644 tests/CMakeLists.txt create mode 100644 tests/conftest.py rename example/constructor-stats.h => tests/constructor_stats.h (98%) rename {example => tests}/object.h (99%) rename example/example.cpp => tests/pybind11_tests.cpp (87%) rename example/example.h => tests/pybind11_tests.h (100%) rename example/example-buffers.cpp => tests/test_buffers.cpp (97%) create mode 100644 tests/test_buffers.py rename example/example-callbacks.cpp => tests/test_callbacks.cpp (96%) create mode 100644 tests/test_callbacks.py rename example/example-constants-and-functions.cpp => tests/test_constants_and_functions.cpp (94%) create mode 100644 tests/test_constants_and_functions.py rename example/eigen.cpp => tests/test_eigen.cpp (98%) create mode 100644 tests/test_eigen.py rename example/example-eval.cpp => tests/test_eval.cpp (90%) create mode 100644 tests/test_eval.py create mode 100644 tests/test_eval_call.py rename example/example-custom-exceptions.cpp => tests/test_exceptions.cpp (97%) create mode 100644 tests/test_exceptions.py rename example/example-inheritance.cpp => tests/test_inheritance.cpp (94%) create mode 100644 tests/test_inheritance.py rename example/issues.cpp => tests/test_issues.cpp (98%) create mode 100644 tests/test_issues.py rename example/example-keep-alive.cpp => tests/test_keep_alive.cpp (92%) create mode 100644 tests/test_keep_alive.py rename example/example-arg-keywords-and-defaults.cpp => tests/test_kwargs_and_defaults.cpp (94%) create mode 100644 tests/test_kwargs_and_defaults.py rename example/example-methods-and-attributes.cpp => tests/test_methods_and_attributes.cpp (96%) create mode 100644 tests/test_methods_and_attributes.py rename example/example-modules.cpp => tests/test_modules.cpp (93%) create mode 100644 tests/test_modules.py rename example/example-numpy-dtypes.cpp => tests/test_numpy_dtypes.cpp (98%) create mode 100644 tests/test_numpy_dtypes.py rename example/example-numpy-vectorize.cpp => tests/test_numpy_vectorize.cpp (85%) create mode 100644 tests/test_numpy_vectorize.py rename example/example-opaque-types.cpp => tests/test_opaque_types.cpp (89%) create mode 100644 tests/test_opaque_types.py rename example/example-operator-overloading.cpp => tests/test_operator_overloading.cpp (95%) create mode 100644 tests/test_operator_overloading.py rename example/example-pickling.cpp => tests/test_pickling.cpp (95%) create mode 100644 tests/test_pickling.py rename example/example-python-types.cpp => tests/test_python_types.cpp (98%) create mode 100644 tests/test_python_types.py rename example/example-sequences-and-iterators.cpp => tests/test_sequences_and_iterators.cpp (97%) create mode 100644 tests/test_sequences_and_iterators.py rename example/example-smart-ptr.cpp => tests/test_smart_ptr.cpp (98%) create mode 100644 tests/test_smart_ptr.py rename example/example-stl-binder-vector.cpp => tests/test_stl_binders.cpp (87%) create mode 100644 tests/test_stl_binders.py rename example/example-virtual-functions.cpp => tests/test_virtual_functions.cpp (98%) create mode 100644 tests/test_virtual_functions.py diff --git a/.appveyor.yml b/.appveyor.yml index 12a51b8fc..688a92efc 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -5,7 +5,6 @@ platform: - x86 - x64 environment: - CTEST_OUTPUT_ON_FAILURE: 1 matrix: - CONDA: 27 - CONDA: 35 @@ -16,12 +15,12 @@ install: if ($env:PLATFORM -eq "x64") { $env:PYTHON = "$env:PYTHON-x64" } $env:PATH = "C:\Python$env:PYTHON\;C:\Python$env:PYTHON\Scripts\;$env:PATH" pip install --disable-pip-version-check --user --upgrade pip wheel - pip install numpy scipy + pip install pytest numpy scipy } elseif ($env:CONDA) { if ($env:CONDA -eq "27") { $env:CONDA = "" } if ($env:PLATFORM -eq "x64") { $env:CONDA = "$env:CONDA-x64" } $env:PATH = "C:\Miniconda$env:CONDA\;C:\Miniconda$env:CONDA\Scripts\;$env:PATH" - conda install -y -q numpy scipy + conda install -y -q pytest numpy scipy } - ps: | Start-FileDownload 'http://bitbucket.org/eigen/eigen/get/3.2.9.zip' @@ -30,4 +29,4 @@ install: build_script: - cmake -A "%CMAKE_ARCH%" -DPYBIND11_WERROR=ON - set MSBuildLogger="C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" -- cmake --build . --config Release --target check -- /v:m /logger:%MSBuildLogger% +- cmake --build . --config Release --target pytest -- /v:m /logger:%MSBuildLogger% diff --git a/.gitignore b/.gitignore index d1676c9b3..ab6675853 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,9 @@ CMakeFiles Makefile cmake_install.cmake .DS_Store -/example/example*.so -/example/example.cpython*.so -/example/example.pyd -/example/example*.dll +*.so +*.pyd +*.dll *.sln *.sdf *.opensdf @@ -32,3 +31,4 @@ MANIFEST /dist /build /cmake/ +.cache/ diff --git a/.travis.yml b/.travis.yml index abdb4bb42..e74a25066 100644 --- a/.travis.yml +++ b/.travis.yml @@ -98,12 +98,12 @@ install: wget -q -O eigen.tar.gz https://bitbucket.org/eigen/eigen/get/3.2.9.tar.gz tar xzf eigen.tar.gz - export CMAKE_EXTRA_ARGS="${CMAKE_EXTRA_ARGS} -DCMAKE_INCLUDE_PATH=eigen-eigen-dc6cfdf9bcec" + export CMAKE_EXTRA_ARGS="${CMAKE_EXTRA_ARGS} -DCMAKE_INCLUDE_PATH=$PWD/eigen-eigen-dc6cfdf9bcec" script: - $SCRIPT_RUN_PREFIX cmake ${CMAKE_EXTRA_ARGS} -DPYBIND11_PYTHON_VERSION=$PYTHON -DPYBIND11_CPP_STANDARD=-std=c++$CPP -DPYBIND11_WERROR=ON -- $SCRIPT_RUN_PREFIX make CTEST_OUTPUT_ON_FAILURE=TRUE check -j 2 +- $SCRIPT_RUN_PREFIX make pytest -j 2 after_script: - if [ -n "$DOCKER" ]; then docker stop "$containerid"; docker rm "$containerid"; fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 450f651c5..cd2c4cb2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# CMakeLists.txt -- Build system for the pybind11 examples +# CMakeLists.txt -- Build system for the pybind11 modules # # Copyright (c) 2015 Wenzel Jakob # @@ -20,7 +20,7 @@ option(PYBIND11_TEST "Build pybind11 test suite?" ${PYBIND11_MASTER_PROJE option(PYBIND11_WERROR "Report all warnings as errors" OFF) # Add a CMake parameter for choosing a desired Python version -set(PYBIND11_PYTHON_VERSION "" CACHE STRING "Python version to use for compiling the example application") +set(PYBIND11_PYTHON_VERSION "" CACHE STRING "Python version to use for compiling modules") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/tools") set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6 3.7) @@ -146,17 +146,15 @@ function(pybind11_enable_warnings target_name) if(PYBIND11_WERROR) if(MSVC) - target_compile_options(${target_name} PRIVATE /WX) + target_compile_options(${target_name} PRIVATE /WX) else() - target_compile_options(${target_name} PRIVATE -Werror) + target_compile_options(${target_name} PRIVATE -Werror) endif() endif() endfunction() if (PYBIND11_TEST) - enable_testing() - add_subdirectory(example) - add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} -C $ DEPENDS example) + add_subdirectory(tests) endif() if (PYBIND11_INSTALL) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt deleted file mode 100644 index 2cc8f8326..000000000 --- a/example/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -# Set a default build configuration if none is specified. 'MinSizeRel' produces the smallest binaries -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - message(STATUS "Setting 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() - -set(PYBIND11_EXAMPLES - example-methods-and-attributes.cpp - example-python-types.cpp - example-operator-overloading.cpp - example-constants-and-functions.cpp - example-callbacks.cpp - example-sequences-and-iterators.cpp - example-buffers.cpp - example-smart-ptr.cpp - example-modules.cpp - example-numpy-vectorize.cpp - example-arg-keywords-and-defaults.cpp - example-virtual-functions.cpp - example-keep-alive.cpp - example-opaque-types.cpp - example-pickling.cpp - example-inheritance.cpp - example-stl-binder-vector.cpp - example-eval.cpp - example-custom-exceptions.cpp - example-numpy-dtypes.cpp - issues.cpp -) - -# Check if Eigen is available -find_package(Eigen3 QUIET) - -if(EIGEN3_FOUND) - list(APPEND PYBIND11_EXAMPLES eigen.cpp) - message(STATUS "Building Eigen v${EIGEN3_VERSION} testcase") -else() - message(STATUS "NOT Building Eigen testcase") -endif() - -# Create the binding library -pybind11_add_module(example example.cpp ${PYBIND11_EXAMPLES}) -pybind11_enable_warnings(example) - -if(EIGEN3_FOUND) - target_include_directories(example PRIVATE ${EIGEN3_INCLUDE_DIR}) - target_compile_definitions(example PRIVATE -DPYBIND11_TEST_EIGEN) -endif() - -# Always write the output file directly into the 'example' directory (even on MSVC) -set(CompilerFlags - LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_RELEASE LIBRARY_OUTPUT_DIRECTORY_DEBUG - LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO - RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_RELEASE RUNTIME_OUTPUT_DIRECTORY_DEBUG - RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO) - -foreach(CompilerFlag ${CompilerFlags}) - set_target_properties(example PROPERTIES ${CompilerFlag} ${PROJECT_SOURCE_DIR}/example) -endforeach() - -set(RUN_TEST ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/run_test.py) - -foreach(VALUE ${PYBIND11_EXAMPLES}) - string(REGEX REPLACE "^(.+).cpp$" "\\1" EXAMPLE_NAME "${VALUE}") - add_test(NAME ${EXAMPLE_NAME} COMMAND ${RUN_TEST} ${EXAMPLE_NAME}) -endforeach() diff --git a/example/eigen.py b/example/eigen.py deleted file mode 100644 index 18c8a453b..000000000 --- a/example/eigen.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import sys -sys.path.append('.') - -from example import fixed_r, fixed_c -from example import fixed_passthrough_r, fixed_passthrough_c -from example import dense_r, dense_c -from example import dense_passthrough_r, dense_passthrough_c -from example import sparse_r, sparse_c -from example import sparse_passthrough_r, sparse_passthrough_c -from example import double_row, double_col -from example import double_mat_cm, double_mat_rm -from example import cholesky1, cholesky2, cholesky3, cholesky4, cholesky5, cholesky6 -from example import diagonal, diagonal_1, diagonal_n -from example import block -from example import incr_diag, symmetric_upper, symmetric_lower -try: - import numpy as np - import scipy -except ImportError: - # NumPy missing: skip test - exit(99) - -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 check(mat): - return 'OK' if np.sum(abs(mat - ref)) == 0 else 'NOT OK' - -print("should_give_NOT_OK = %s" % check(ref[:, ::-1])) - -print("fixed_r = %s" % check(fixed_r())) -print("fixed_c = %s" % check(fixed_c())) -print("pt_r(fixed_r) = %s" % check(fixed_passthrough_r(fixed_r()))) -print("pt_c(fixed_c) = %s" % check(fixed_passthrough_c(fixed_c()))) -print("pt_r(fixed_c) = %s" % check(fixed_passthrough_r(fixed_c()))) -print("pt_c(fixed_r) = %s" % check(fixed_passthrough_c(fixed_r()))) - -print("dense_r = %s" % check(dense_r())) -print("dense_c = %s" % check(dense_c())) -print("pt_r(dense_r) = %s" % check(dense_passthrough_r(dense_r()))) -print("pt_c(dense_c) = %s" % check(dense_passthrough_c(dense_c()))) -print("pt_r(dense_c) = %s" % check(dense_passthrough_r(dense_c()))) -print("pt_c(dense_r) = %s" % check(dense_passthrough_c(dense_r()))) - -print("sparse_r = %s" % check(sparse_r())) -print("sparse_c = %s" % check(sparse_c())) -print("pt_r(sparse_r) = %s" % check(sparse_passthrough_r(sparse_r()))) -print("pt_c(sparse_c) = %s" % check(sparse_passthrough_c(sparse_c()))) -print("pt_r(sparse_c) = %s" % check(sparse_passthrough_r(sparse_c()))) -print("pt_c(sparse_r) = %s" % check(sparse_passthrough_c(sparse_r()))) - -def check_got_vs_ref(got_x, ref_x): - return 'OK' if np.array_equal(got_x, ref_x) else 'NOT OK' - -counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3)) -first_row = counting_mat[0, :] -first_col = counting_mat[:, 0] - -print("double_row(first_row) = %s" % check_got_vs_ref(double_row(first_row), 2.0 * first_row)) -print("double_col(first_row) = %s" % check_got_vs_ref(double_col(first_row), 2.0 * first_row)) -print("double_row(first_col) = %s" % check_got_vs_ref(double_row(first_col), 2.0 * first_col)) -print("double_col(first_col) = %s" % check_got_vs_ref(double_col(first_col), 2.0 * first_col)) - -counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3)) -slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]] - -for slice_idx, ref_mat in enumerate(slices): - print("double_mat_cm(%d) = %s" % (slice_idx, check_got_vs_ref(double_mat_cm(ref_mat), 2.0 * ref_mat))) - print("double_mat_rm(%d) = %s" % (slice_idx, check_got_vs_ref(double_mat_rm(ref_mat), 2.0 * ref_mat))) - -i = 1 -for chol in [cholesky1, cholesky2, cholesky3, cholesky4, cholesky5, cholesky6]: - mymat = chol(np.array([[1,2,4], [2,13,23], [4,23,77]])) - print("cholesky" + str(i) + " " + ("OK" if (mymat == np.array([[1,0,0], [2,3,0], [4,5,6]])).all() else "NOT OKAY")) - i += 1 - -print("diagonal() %s" % ("OK" if (diagonal(ref) == ref.diagonal()).all() else "FAILED")) -print("diagonal_1() %s" % ("OK" if (diagonal_1(ref) == ref.diagonal(1)).all() else "FAILED")) -for i in range(-5, 7): - print("diagonal_n(%d) %s" % (i, "OK" if (diagonal_n(ref, i) == ref.diagonal(i)).all() else "FAILED")) - -print("block(2,1,3,3) %s" % ("OK" if (block(ref, 2, 1, 3, 3) == ref[2:5, 1:4]).all() else "FAILED")) -print("block(1,4,4,2) %s" % ("OK" if (block(ref, 1, 4, 4, 2) == ref[1:, 4:]).all() else "FAILED")) -print("block(1,4,3,2) %s" % ("OK" if (block(ref, 1, 4, 3, 2) == ref[1:4, 4:]).all() else "FAILED")) - -print("incr_diag %s" % ("OK" if (incr_diag(7) == np.diag([1,2,3,4,5,6,7])).all() else "FAILED")) - -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] - -print("symmetric_lower %s" % ("OK" if (symmetric_lower(asymm) == symm_lower).all() else "FAILED")) -print("symmetric_upper %s" % ("OK" if (symmetric_upper(asymm) == symm_upper).all() else "FAILED")) - -print(double_col.__doc__) -print(double_row.__doc__) -print(double_mat_rm.__doc__) -print(sparse_passthrough_r.__doc__) -print(sparse_passthrough_c.__doc__) diff --git a/example/eigen.ref b/example/eigen.ref deleted file mode 100644 index 626c60485..000000000 --- a/example/eigen.ref +++ /dev/null @@ -1,60 +0,0 @@ -should_give_NOT_OK = NOT OK -fixed_r = OK -fixed_c = OK -pt_r(fixed_r) = OK -pt_c(fixed_c) = OK -pt_r(fixed_c) = OK -pt_c(fixed_r) = OK -dense_r = OK -dense_c = OK -pt_r(dense_r) = OK -pt_c(dense_c) = OK -pt_r(dense_c) = OK -pt_c(dense_r) = OK -sparse_r = OK -sparse_c = OK -pt_r(sparse_r) = OK -pt_c(sparse_c) = OK -pt_r(sparse_c) = OK -pt_c(sparse_r) = OK -double_row(first_row) = OK -double_col(first_row) = OK -double_row(first_col) = OK -double_col(first_col) = OK -double_mat_cm(0) = OK -double_mat_rm(0) = OK -double_mat_cm(1) = OK -double_mat_rm(1) = OK -double_mat_cm(2) = OK -double_mat_rm(2) = OK -cholesky1 OK -cholesky2 OK -cholesky3 OK -cholesky4 OK -cholesky5 OK -cholesky6 OK -diagonal() OK -diagonal_1() OK -diagonal_n(-5) OK -diagonal_n(-4) OK -diagonal_n(-3) OK -diagonal_n(-2) OK -diagonal_n(-1) OK -diagonal_n(0) OK -diagonal_n(1) OK -diagonal_n(2) OK -diagonal_n(3) OK -diagonal_n(4) OK -diagonal_n(5) OK -diagonal_n(6) OK -block(2,1,3,3) OK -block(1,4,4,2) OK -block(1,4,3,2) OK -incr_diag OK -symmetric_lower OK -symmetric_upper OK -double_col(arg0: numpy.ndarray[float32[m, 1]]) -> numpy.ndarray[float32[m, 1]] -double_row(arg0: numpy.ndarray[float32[1, n]]) -> numpy.ndarray[float32[1, n]] -double_mat_rm(arg0: numpy.ndarray[float32[m, n]]) -> numpy.ndarray[float32[m, n]] -sparse_passthrough_r(arg0: scipy.sparse.csr_matrix[float32]) -> scipy.sparse.csr_matrix[float32] -sparse_passthrough_c(arg0: scipy.sparse.csc_matrix[float32]) -> scipy.sparse.csc_matrix[float32] diff --git a/example/example-arg-keywords-and-defaults.py b/example/example-arg-keywords-and-defaults.py deleted file mode 100755 index 2536782fc..000000000 --- a/example/example-arg-keywords-and-defaults.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import sys -import pydoc - -sys.path.append('.') - -from example import kw_func0, kw_func1, kw_func2, kw_func3, kw_func4, call_kw_func -from example import args_function, args_kwargs_function, kw_func_udl, kw_func_udl_z -from example import KWClass - -print(pydoc.render_doc(kw_func0, "Help on %s")) -print(pydoc.render_doc(kw_func1, "Help on %s")) -print(pydoc.render_doc(kw_func2, "Help on %s")) -print(pydoc.render_doc(kw_func3, "Help on %s")) -print(pydoc.render_doc(kw_func4, "Help on %s")) -print(pydoc.render_doc(kw_func_udl, "Help on %s")) -print(pydoc.render_doc(kw_func_udl_z, "Help on %s")) -print(pydoc.render_doc(args_function, "Help on %s")) -print(pydoc.render_doc(args_kwargs_function, "Help on %s")) - -print(KWClass.foo0.__doc__) -print(KWClass.foo1.__doc__) - -kw_func1(5, 10) -kw_func1(5, y=10) -kw_func1(y=10, x=5) - -kw_func2() - -kw_func2(5) -kw_func2(x=5) - -kw_func2(y=10) - -kw_func2(5, 10) -kw_func2(x=5, y=10) - -try: - kw_func2(x=5, y=10, z=12) -except Exception as e: - print("Caught expected exception: " + str(e)) - -kw_func4() -kw_func4(myList=[1, 2, 3]) - -call_kw_func(kw_func2) - -args_function('arg1_value', 'arg2_value', 3) -args_kwargs_function('arg1_value', 'arg2_value', arg3='arg3_value', arg4=4) - -kw_func_udl(x=5, y=10) -kw_func_udl_z(x=5) diff --git a/example/example-arg-keywords-and-defaults.ref b/example/example-arg-keywords-and-defaults.ref deleted file mode 100644 index d3ca99765..000000000 --- a/example/example-arg-keywords-and-defaults.ref +++ /dev/null @@ -1,75 +0,0 @@ -Help on built-in function kw_func0 in module example - -kkww__ffuunncc00(...) - kw_func0(arg0: int, arg1: int) -> None - -Help on built-in function kw_func1 in module example - -kkww__ffuunncc11(...) - kw_func1(x: int, y: int) -> None - -Help on built-in function kw_func2 in module example - -kkww__ffuunncc22(...) - kw_func2(x: int=100L, y: int=200L) -> None - -Help on built-in function kw_func3 in module example - -kkww__ffuunncc33(...) - kw_func3(data: unicode=u'Hello world!') -> None - -Help on built-in function kw_func4 in module example - -kkww__ffuunncc44(...) - kw_func4(myList: List[int]=[13L, 17L]) -> None - -Help on built-in function kw_func_udl in module example - -kkww__ffuunncc__uuddll(...) - kw_func_udl(x: int, y: int=300L) -> None - -Help on built-in function kw_func_udl_z in module example - -kkww__ffuunncc__uuddll__zz(...) - kw_func_udl_z(x: int, y: int=0L) -> None - -Help on built-in function args_function in module example - -aarrggss__ffuunnccttiioonn(...) - args_function(*args) -> None - -Help on built-in function args_kwargs_function in module example - -aarrggss__kkwwaarrggss__ffuunnccttiioonn(...) - args_kwargs_function(*args, **kwargs) -> None - - -foo0(self: KWClass, arg0: int, arg1: float) -> None -foo1(self: KWClass, x: int, y: float) -> None - - -kw_func(x=5, y=10) -kw_func(x=5, y=10) -kw_func(x=5, y=10) -kw_func(x=100, y=200) -kw_func(x=5, y=200) -kw_func(x=5, y=200) -kw_func(x=100, y=10) -kw_func(x=5, y=10) -kw_func(x=5, y=10) -Caught expected exception: Incompatible function arguments. The following argument types are supported: - 1. (x: int=100L, y: int=200L) -> None - Invoked with: -kw_func4: 13 17 -kw_func4: 1 2 3 -kw_func(x=1234, y=5678) -got argument: arg1_value -got argument: arg2_value -got argument: 3 -got argument: arg1_value -got argument: arg2_value -got keyword argument: arg3 -> arg3_value -got keyword argument: arg4 -> 4 - -kw_func(x=5, y=10) -kw_func(x=5, y=0) diff --git a/example/example-buffers.py b/example/example-buffers.py deleted file mode 100755 index 185e6d3cc..000000000 --- a/example/example-buffers.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import sys -sys.path.append('.') - -from example import Matrix - -try: - import numpy as np -except ImportError: - # NumPy missing: skip test - exit(99) - -m = Matrix(5, 5) - -print(m[2, 3]) -m[2, 3] = 4 -print(m[2, 3]) - -m2 = np.array(m, copy=False) -print(m2) -print(m2[2, 3]) -m2[2, 3] = 5 -print(m[2, 3]) - -m3 = np.array([[1,2,3],[4,5,6]]).astype(np.float32) -print(m3) -m4 = Matrix(m3) -for i in range(m4.rows()): - for j in range(m4.cols()): - print(m4[i, j], end = ' ') - print() - -from example import ConstructorStats -cstats = ConstructorStats.get(Matrix) -print("Instances not destroyed:", cstats.alive()) -m = m4 = None -print("Instances not destroyed:", cstats.alive()) -m2 = None # m2 holds an m reference -print("Instances not destroyed:", cstats.alive()) -print("Constructor values:", cstats.values()) -print("Copy constructions:", cstats.copy_constructions) -#print("Move constructions:", cstats.move_constructions >= 0) # Don't invoke any -print("Copy assignments:", cstats.copy_assignments) -print("Move assignments:", cstats.move_assignments) diff --git a/example/example-buffers.ref b/example/example-buffers.ref deleted file mode 100644 index 1e02ffd97..000000000 --- a/example/example-buffers.ref +++ /dev/null @@ -1,24 +0,0 @@ -### Matrix @ 0x1df1920 created 5x5 matrix -0.0 -4.0 -[[ 0. 0. 0. 0. 0.] - [ 0. 0. 0. 0. 0.] - [ 0. 0. 0. 4. 0.] - [ 0. 0. 0. 0. 0.] - [ 0. 0. 0. 0. 0.]] -4.0 -5.0 -[[ 1. 2. 3.] - [ 4. 5. 6.]] -### Matrix @ 0x1fa8cf0 created 2x3 matrix -1.0 2.0 3.0 -4.0 5.0 6.0 -Instances not destroyed: 2 -### Matrix @ 0x1fa8cf0 destroyed 2x3 matrix -Instances not destroyed: 1 -### Matrix @ 0x1df1920 destroyed 5x5 matrix -Instances not destroyed: 0 -Constructor values: ['5x5 matrix', '2x3 matrix'] -Copy constructions: 0 -Copy assignments: 0 -Move assignments: 0 diff --git a/example/example-callbacks.py b/example/example-callbacks.py deleted file mode 100755 index 68a485a7d..000000000 --- a/example/example-callbacks.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -from functools import partial -import sys -sys.path.append('.') - -from example import Pet -from example import Dog -from example import Rabbit -from example import dog_bark -from example import pet_print - -polly = Pet('Polly', 'parrot') -molly = Dog('Molly') -roger = Rabbit('Rabbit') -print(roger.name() + " is a " + roger.species()) -pet_print(roger) -print(polly.name() + " is a " + polly.species()) -pet_print(polly) -print(molly.name() + " is a " + molly.species()) -pet_print(molly) -dog_bark(molly) -try: - dog_bark(polly) -except Exception as e: - print('The following error is expected: ' + str(e)) - -from example import test_callback1 -from example import test_callback2 -from example import test_callback3 -from example import test_callback4 -from example import test_callback5 -from example import test_cleanup - -def func1(): - print('Callback function 1 called!') - -def func2(a, b, c, d): - print('Callback function 2 called : ' + str(a) + ", " + str(b) + ", " + str(c) + ", "+ str(d)) - return d - -def func3(a): - print('Callback function 3 called : ' + str(a)) - -print(test_callback1(func1)) -print(test_callback2(func2)) -print(test_callback1(partial(func2, "Hello", "from", "partial", "object"))) -print(test_callback1(partial(func3, "Partial object with one argument"))) - -test_callback3(lambda i: i + 1) -f = test_callback4() -print("func(43) = %i" % f(43)) -f = test_callback5() -print("func(number=43) = %i" % f(number=43)) - -test_cleanup() - -from example import payload_cstats -cstats = payload_cstats() -print("Payload instances not destroyed:", cstats.alive()) -print("Copy constructions:", cstats.copy_constructions) -print("Move constructions:", cstats.move_constructions >= 1) - -from example import dummy_function -from example import dummy_function2 -from example import test_dummy_function -from example import roundtrip - -test_dummy_function(dummy_function) -test_dummy_function(roundtrip(dummy_function)) -if roundtrip(None) is not None: - print("Problem!") -test_dummy_function(lambda x: x + 2) - -try: - test_dummy_function(dummy_function2) - print("Problem!") -except Exception as e: - if 'Incompatible function arguments' in str(e): - print("All OK!") - else: - print("Problem!") - -try: - test_dummy_function(lambda x, y: x + y) - print("Problem!") -except Exception as e: - if 'missing 1 required positional argument' in str(e) or \ - 'takes exactly 2 arguments' in str(e): - print("All OK!") - else: - print("Problem!") - -print(test_callback3.__doc__) -print(test_callback4.__doc__) diff --git a/example/example-callbacks.ref b/example/example-callbacks.ref deleted file mode 100644 index c6f8f531f..000000000 --- a/example/example-callbacks.ref +++ /dev/null @@ -1,46 +0,0 @@ -Rabbit is a parrot -Rabbit is a parrot -Polly is a parrot -Polly is a parrot -Molly is a dog -Molly is a dog -Woof! -The following error is expected: Incompatible function arguments. The following argument types are supported: - 1. (arg0: example.Dog) -> None - Invoked with: -Callback function 1 called! -False -Callback function 2 called : Hello, x, True, 5 -5 -Callback function 2 called : Hello, from, partial, object -False -Callback function 3 called : Partial object with one argument -False -func(43) = 44 -func(43) = 44 -func(number=43) = 44 -### Payload @ 0x7ffdcee09c80 created via default constructor -### Payload @ 0x7ffdcee09c88 created via copy constructor -### Payload @ 0xb54500 created via move constructor -### Payload @ 0x7ffdcee09c88 destroyed -### Payload @ 0x7ffdcee09c80 destroyed -### Payload @ 0xb54500 destroyed -Payload instances not destroyed: 0 -Copy constructions: 1 -Move constructions: True -argument matches dummy_function -eval(1) = 2 -roundtrip (got None).. -roundtrip.. -argument matches dummy_function -eval(1) = 2 -could not convert to a function pointer. -eval(1) = 3 -could not convert to a function pointer. -All OK! -could not convert to a function pointer. -All OK! -test_callback3(arg0: Callable[[int], int]) -> None - -test_callback4() -> Callable[[int], int] - diff --git a/example/example-constants-and-functions.py b/example/example-constants-and-functions.py deleted file mode 100755 index 852902f07..000000000 --- a/example/example-constants-and-functions.py +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import sys -sys.path.append('.') - -from example import test_function -from example import some_constant -from example import EMyEnumeration -from example import ECMyEnum, test_ecenum -from example import EFirstEntry -from example import ExampleWithEnum -from example import return_bytes -from example import print_bytes - -print(EMyEnumeration) -print(EMyEnumeration.EFirstEntry) -print(EMyEnumeration.ESecondEntry) -print(EFirstEntry) - -print(test_function()) -print(test_function(7)) -print(test_function(EMyEnumeration.EFirstEntry)) -print(test_function(EMyEnumeration.ESecondEntry)) -test_ecenum(ECMyEnum.Three) -z = ECMyEnum.Two -test_ecenum(z) -try: - z == 2 - print("Bad: expected a TypeError exception") -except TypeError: - try: - z != 3 - print("Bad: expected a TypeError exception") - except TypeError: - print("Good: caught expected TypeError exceptions for scoped enum ==/!= int comparisons") - -y = EMyEnumeration.ESecondEntry -try: - y == 2 - y != 2 - print("Good: no TypeError exception for unscoped enum ==/!= int comparisions") -except TypeError: - print("Bad: caught TypeError exception for unscoped enum ==/!= int comparisons") - -print("enum->integer = %i" % int(EMyEnumeration.ESecondEntry)) -print("integer->enum = %s" % str(EMyEnumeration(2))) - -print("A constant = " + str(some_constant)) - -print(ExampleWithEnum.EMode) -print(ExampleWithEnum.EMode.EFirstMode) -print(ExampleWithEnum.EFirstMode) -ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode) - -print("Equality test 1: " + str( - ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode) == - ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode))) - -print("Inequality test 1: " + str( - ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode) != - ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode))) - -print("Equality test 2: " + str( - ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode) == - ExampleWithEnum.test_function(ExampleWithEnum.ESecondMode))) - -print("Inequality test 2: " + str( - ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode) != - ExampleWithEnum.test_function(ExampleWithEnum.ESecondMode))) - -print("Equality test 3: " + str( - ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode) == - int(ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode)))) - -print("Inequality test 3: " + str( - ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode) != - int(ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode)))) - -print("Equality test 4: " + str( - ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode) == - int(ExampleWithEnum.test_function(ExampleWithEnum.ESecondMode)))) - -print("Inequality test 4: " + str( - ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode) != - int(ExampleWithEnum.test_function(ExampleWithEnum.ESecondMode)))) - -x = { - ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode): 1, - ExampleWithEnum.test_function(ExampleWithEnum.ESecondMode): 2 -} - -x[ExampleWithEnum.test_function(ExampleWithEnum.EFirstMode)] = 3 -x[ExampleWithEnum.test_function(ExampleWithEnum.ESecondMode)] = 4 -print("Hashing test = " + str(x)) - -print_bytes(return_bytes()) diff --git a/example/example-constants-and-functions.ref b/example/example-constants-and-functions.ref deleted file mode 100644 index 480563114..000000000 --- a/example/example-constants-and-functions.ref +++ /dev/null @@ -1,56 +0,0 @@ - -EMyEnumeration.EFirstEntry -EMyEnumeration.ESecondEntry -EMyEnumeration.EFirstEntry -test_function() -False -test_function(7) -3.5 -test_function(enum=1) -None -test_function(enum=2) -None -test_ecenum(ECMyEnum::Three) -test_ecenum(ECMyEnum::Two) -Good: caught expected TypeError exceptions for scoped enum ==/!= int comparisons -Good: no TypeError exception for unscoped enum ==/!= int comparisions -enum->integer = 2 -integer->enum = EMyEnumeration.ESecondEntry -A constant = 14 - -EMode.EFirstMode -EMode.EFirstMode -ExampleWithEnum::test_function(enum=1) -ExampleWithEnum::test_function(enum=1) -ExampleWithEnum::test_function(enum=1) -Equality test 1: True -ExampleWithEnum::test_function(enum=1) -ExampleWithEnum::test_function(enum=1) -Inequality test 1: False -ExampleWithEnum::test_function(enum=1) -ExampleWithEnum::test_function(enum=2) -Equality test 2: False -ExampleWithEnum::test_function(enum=1) -ExampleWithEnum::test_function(enum=2) -Inequality test 2: True -ExampleWithEnum::test_function(enum=1) -ExampleWithEnum::test_function(enum=1) -Equality test 3: True -ExampleWithEnum::test_function(enum=1) -ExampleWithEnum::test_function(enum=1) -Inequality test 3: False -ExampleWithEnum::test_function(enum=1) -ExampleWithEnum::test_function(enum=2) -Equality test 4: False -ExampleWithEnum::test_function(enum=1) -ExampleWithEnum::test_function(enum=2) -Inequality test 4: True -ExampleWithEnum::test_function(enum=1) -ExampleWithEnum::test_function(enum=2) -ExampleWithEnum::test_function(enum=1) -ExampleWithEnum::test_function(enum=2) -Hashing test = {EMode.EFirstMode: 3, EMode.ESecondMode: 4} -bytes[0]=1 -bytes[1]=0 -bytes[2]=2 -bytes[3]=0 diff --git a/example/example-custom-exceptions.py b/example/example-custom-exceptions.py deleted file mode 100644 index d4ee5f853..000000000 --- a/example/example-custom-exceptions.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import sys -sys.path.append('.') - -import example - -print("Can we catch a MyException?") -try: - example.throws1() -except example.MyException as e: - print(e.__class__.__name__, ":", e) -print("") - -print("Can we translate to standard Python exceptions?") -try: - example.throws2() -except Exception as e: - print(e.__class__.__name__, ":", e) -print("") - -print("Can we handle unknown exceptions?") -try: - example.throws3() -except Exception as e: - print(e.__class__.__name__, ":", e) -print("") - -print("Can we delegate to another handler by rethrowing?") -try: - example.throws4() -except example.MyException as e: - print(e.__class__.__name__, ":", e) -print("") - -print("Can we fall-through to the default handler?") -try: - example.throws_logic_error() -except Exception as e: - print(e.__class__.__name__, ":", e) -print("") - diff --git a/example/example-custom-exceptions.ref b/example/example-custom-exceptions.ref deleted file mode 100644 index a0489234a..000000000 --- a/example/example-custom-exceptions.ref +++ /dev/null @@ -1,15 +0,0 @@ -Can we catch a MyException? -MyException : this error should go to a custom type - -Can we translate to standard Python exceptions? -RuntimeError : this error should go to a standard Python exception - -Can we handle unknown exceptions? -RuntimeError : Caught an unknown exception! - -Can we delegate to another handler by rethrowing? -MyException : this error is rethrown - -Can we fall-through to the default handler? -RuntimeError : this error should fall through to the standard handler - diff --git a/example/example-eval.py b/example/example-eval.py deleted file mode 100644 index eec10c3b0..000000000 --- a/example/example-eval.py +++ /dev/null @@ -1,5 +0,0 @@ -from example import example_eval - -example_eval() - - diff --git a/example/example-eval.ref b/example/example-eval.ref deleted file mode 100644 index db350bde8..000000000 --- a/example/example-eval.ref +++ /dev/null @@ -1,13 +0,0 @@ -eval_statements test -eval_statements passed -eval test -eval passed -eval_single_statement test -eval_single_statement passed -eval_file test -eval_file passed -eval failure test -eval failure test passed -eval_file failure test -eval_file failure test passed -Hello World! diff --git a/example/example-eval_call.py b/example/example-eval_call.py deleted file mode 100644 index db96fd3f2..000000000 --- a/example/example-eval_call.py +++ /dev/null @@ -1 +0,0 @@ -call_test2(y) \ No newline at end of file diff --git a/example/example-inheritance.py b/example/example-inheritance.py deleted file mode 100644 index b4bcb655d..000000000 --- a/example/example-inheritance.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import print_function -import sys - -sys.path.append('.') - -from example import return_class_1 -from example import return_class_2 -from example import return_none - -print(type(return_class_1()).__name__) -print(type(return_class_2()).__name__) -print(type(return_none()).__name__) diff --git a/example/example-inheritance.ref b/example/example-inheritance.ref deleted file mode 100644 index 96003367b..000000000 --- a/example/example-inheritance.ref +++ /dev/null @@ -1,3 +0,0 @@ -DerivedClass1 -DerivedClass2 -NoneType diff --git a/example/example-keep-alive.py b/example/example-keep-alive.py deleted file mode 100644 index 187ad534f..000000000 --- a/example/example-keep-alive.py +++ /dev/null @@ -1,67 +0,0 @@ -from __future__ import print_function -import sys -import gc -sys.path.append('.') - -from example import Parent, Child - -if True: - p = Parent() - p.addChild(Child()) - gc.collect() - print(p) - p = None - -gc.collect() -print("") - -if True: - p = Parent() - p.returnChild() - gc.collect() - print(p) - p = None - -gc.collect() -print("") - -if True: - p = Parent() - p.addChildKeepAlive(Child()) - gc.collect() - print(p) - p = None - -gc.collect() -print("") - -if True: - p = Parent() - p.returnChildKeepAlive() - gc.collect() - print(p) - p = None - -gc.collect() -print("") - -if True: - p = Parent() - p.returnNullChildKeepAliveChild() - gc.collect() - print(p) - p = None - -gc.collect() -print("") - -if True: - p = Parent() - p.returnNullChildKeepAliveParent() - gc.collect() - print(p) - p = None - -gc.collect() -print("") -print("Terminating..") diff --git a/example/example-keep-alive.ref b/example/example-keep-alive.ref deleted file mode 100644 index 775aff418..000000000 --- a/example/example-keep-alive.ref +++ /dev/null @@ -1,33 +0,0 @@ -Allocating parent. -Allocating child. -Releasing child. - -Releasing parent. - -Allocating parent. -Allocating child. -Releasing child. - -Releasing parent. - -Allocating parent. -Allocating child. - -Releasing parent. -Releasing child. - -Allocating parent. -Allocating child. - -Releasing parent. -Releasing child. - -Allocating parent. - -Releasing parent. - -Allocating parent. - -Releasing parent. - -Terminating.. diff --git a/example/example-methods-and-attributes.py b/example/example-methods-and-attributes.py deleted file mode 100755 index 8f2a5243d..000000000 --- a/example/example-methods-and-attributes.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import sys -sys.path.append('.') - -from example import ExampleMandA - -instance1 = ExampleMandA() -instance2 = ExampleMandA(32) -instance1.add1(instance2) -instance1.add2(instance2) -instance1.add3(instance2) -instance1.add4(instance2) -instance1.add5(instance2) -instance1.add6(32) -instance1.add7(32) -instance1.add8(32) -instance1.add9(32) -instance1.add10(32) - -print("Instance 1: " + str(instance1)) -print("Instance 2: " + str(instance2)) - -print(instance1.self1()) -print(instance1.self2()) -print(instance1.self3()) -print(instance1.self4()) -print(instance1.self5()) -print(instance1.internal1()) -print(instance1.internal2()) -print(instance1.internal3()) -print(instance1.internal4()) -print(instance1.internal5()) - -print("Instance 1, direct access = %i" % instance1.value) -instance1.value = 100 -print("Instance 1: " + str(instance1)) - -from example import ConstructorStats - -cstats = ConstructorStats.get(ExampleMandA) -print("Instances not destroyed:", cstats.alive()) -instance1 = instance2 = None -print("Instances not destroyed:", cstats.alive()) -print("Constructor values:", cstats.values()) -print("Default constructions:", cstats.default_constructions) -print("Copy constructions:", cstats.copy_constructions) -print("Move constructions:", cstats.move_constructions >= 1) -print("Copy assignments:", cstats.copy_assignments) -print("Move assignments:", cstats.move_assignments) diff --git a/example/example-methods-and-attributes.ref b/example/example-methods-and-attributes.ref deleted file mode 100644 index 338539e76..000000000 --- a/example/example-methods-and-attributes.ref +++ /dev/null @@ -1,34 +0,0 @@ -### ExampleMandA @ 0x2801910 created via default constructor -### ExampleMandA @ 0x27fa780 created 32 -### ExampleMandA @ 0x7fff80a98a74 created via copy constructor -### ExampleMandA @ 0x7fff80a98a78 created via copy constructor -### ExampleMandA @ 0x7fff80a98a78 destroyed -### ExampleMandA @ 0x7fff80a98a74 destroyed -Instance 1: ExampleMandA[value=320] -Instance 2: ExampleMandA[value=32] -### ExampleMandA @ 0x7fff80a98a84 created via copy constructor -### ExampleMandA @ 0x2801fd0 created via move constructor -### ExampleMandA @ 0x7fff80a98a84 destroyed -ExampleMandA[value=320] -### ExampleMandA @ 0x2801fd0 destroyed -ExampleMandA[value=320] -ExampleMandA[value=320] -ExampleMandA[value=320] -ExampleMandA[value=320] -320 -320 -320 -320 -320 -Instance 1, direct access = 320 -Instance 1: ExampleMandA[value=100] -Instances not destroyed: 2 -### ExampleMandA @ 0x2801910 destroyed -### ExampleMandA @ 0x27fa780 destroyed -Instances not destroyed: 0 -Constructor values: ['32'] -Default constructions: 1 -Copy constructions: 3 -Move constructions: True -Copy assignments: 0 -Move assignments: 0 diff --git a/example/example-modules.py b/example/example-modules.py deleted file mode 100755 index 91c075c75..000000000 --- a/example/example-modules.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import sys -sys.path.append('.') - -import example - -print(example.__name__) -print(example.submodule.__name__) - -from example.submodule import * -from example import OD - -submodule_func() - -b = B() -print(b.get_a1()) -print(b.a1) -print(b.get_a2()) -print(b.a2) - -b.a1 = A(42) -b.a2 = A(43) - -print(b.get_a1()) -print(b.a1) -print(b.get_a2()) -print(b.a2) - -print(OD([(1, 'a'), (2, 'b')])) - -from example import ConstructorStats - -cstats = [ConstructorStats.get(A), ConstructorStats.get(B)] -print("Instances not destroyed:", [x.alive() for x in cstats]) -b = None -print("Instances not destroyed:", [x.alive() for x in cstats]) -print("Constructor values:", [x.values() for x in cstats]) -print("Default constructions:", [x.default_constructions for x in cstats]) -print("Copy constructions:", [x.copy_constructions for x in cstats]) -#print("Move constructions:", [x.move_constructions >= 0 for x in cstats]) # Don't invoke any -print("Copy assignments:", [x.copy_assignments for x in cstats]) -print("Move assignments:", [x.move_assignments for x in cstats]) diff --git a/example/example-modules.ref b/example/example-modules.ref deleted file mode 100644 index 1ca078349..000000000 --- a/example/example-modules.ref +++ /dev/null @@ -1,31 +0,0 @@ -example -example.submodule -submodule_func() -### A @ 0x21a5bc0 created 1 -### A @ 0x21a5bc4 created 2 -### B @ 0x21a5bc0 created via default constructor -A[1] -A[1] -A[2] -A[2] -### A @ 0x20f93b0 created 42 -### A @ 0x21a5bc0 assigned via copy assignment -### A @ 0x20f93b0 destroyed -### A @ 0x20f93d0 created 43 -### A @ 0x21a5bc4 assigned via copy assignment -### A @ 0x20f93d0 destroyed -A[42] -A[42] -A[43] -A[43] -OrderedDict([(1, 'a'), (2, 'b')]) -Instances not destroyed: [2, 1] -### B @ 0x21a5bc0 destroyed -### A @ 0x21a5bc4 destroyed -### A @ 0x21a5bc0 destroyed -Instances not destroyed: [0, 0] -Constructor values: [['1', '2', '42', '43'], []] -Default constructions: [0, 1] -Copy constructions: [0, 0] -Copy assignments: [2, 0] -Move assignments: [0, 0] diff --git a/example/example-numpy-dtypes.py b/example/example-numpy-dtypes.py deleted file mode 100644 index 06185914b..000000000 --- a/example/example-numpy-dtypes.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function - -import numpy as np -from example import ( - create_rec_simple, create_rec_packed, create_rec_nested, print_format_descriptors, - print_rec_simple, print_rec_packed, print_rec_nested, print_dtypes, get_format_unbound, - create_rec_partial, create_rec_partial_nested, create_string_array, print_string_array, - test_array_ctors, test_dtype_ctors, test_dtype_methods -) - - -def check_eq(arr, data, dtype): - np.testing.assert_equal(arr, np.array(data, dtype=dtype)) - -try: - get_format_unbound() - raise Exception -except RuntimeError as e: - assert 'unsupported buffer format' in str(e) - -print_format_descriptors() -print_dtypes() - -simple_dtype = np.dtype({'names': ['x', 'y', 'z'], - 'formats': ['?', 'u4', 'f4'], - 'offsets': [0, 4, 8]}) -packed_dtype = np.dtype([('x', '?'), ('y', 'u4'), ('z', 'f4')]) - -elements = [(False, 0, 0.0), (True, 1, 1.5), (False, 2, 3.0)] - -for func, dtype in [(create_rec_simple, simple_dtype), (create_rec_packed, packed_dtype)]: - arr = func(0) - assert arr.dtype == dtype - check_eq(arr, [], simple_dtype) - check_eq(arr, [], packed_dtype) - - arr = func(3) - assert arr.dtype == dtype - check_eq(arr, elements, simple_dtype) - check_eq(arr, elements, packed_dtype) - - if dtype == simple_dtype: - print_rec_simple(arr) - else: - print_rec_packed(arr) - -arr = create_rec_partial(3) -print(arr.dtype) -partial_dtype = arr.dtype -assert '' not in arr.dtype.fields -assert partial_dtype.itemsize > simple_dtype.itemsize -check_eq(arr, elements, simple_dtype) -check_eq(arr, elements, packed_dtype) - -arr = create_rec_partial_nested(3) -print(arr.dtype) -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'], create_rec_partial(3)) - -nested_dtype = np.dtype([('a', simple_dtype), ('b', packed_dtype)]) - -arr = create_rec_nested(0) -assert arr.dtype == nested_dtype -check_eq(arr, [], nested_dtype) - -arr = create_rec_nested(3) -assert arr.dtype == nested_dtype -check_eq(arr, [((False, 0, 0.0), (True, 1, 1.5)), - ((True, 1, 1.5), (False, 2, 3.0)), - ((False, 2, 3.0), (True, 3, 4.5))], nested_dtype) -print_rec_nested(arr) - -assert create_rec_nested.__doc__.strip().endswith('numpy.ndarray[NestedStruct]') - -arr = create_string_array(True) -print(arr.dtype) -print_string_array(arr) -dtype = arr.dtype -assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc'] -assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc'] -arr = create_string_array(False) -assert dtype == arr.dtype - -data = np.arange(1, 7, dtype='int32') -for i in range(8): - np.testing.assert_array_equal(test_array_ctors(10 + i), data.reshape((3, 2))) - np.testing.assert_array_equal(test_array_ctors(20 + i), data.reshape((3, 2))) -for i in range(5): - np.testing.assert_array_equal(test_array_ctors(30 + i), data) - np.testing.assert_array_equal(test_array_ctors(40 + i), data) - -d1 = np.dtype({'names': ['a', 'b'], 'formats': ['int32', 'float64'], - 'offsets': [1, 10], 'itemsize': 20}) -d2 = np.dtype([('a', 'i4'), ('b', 'f4')]) -assert test_dtype_ctors() == [np.dtype('int32'), np.dtype('float64'), - np.dtype('bool'), d1, d1, np.dtype('uint32'), d2] - -assert test_dtype_methods() == [np.dtype('int32'), simple_dtype, False, True, - np.dtype('int32').itemsize, simple_dtype.itemsize] diff --git a/example/example-numpy-dtypes.ref b/example/example-numpy-dtypes.ref deleted file mode 100644 index 4f07ce445..000000000 --- a/example/example-numpy-dtypes.ref +++ /dev/null @@ -1,28 +0,0 @@ -T{=?:x:3x=I:y:=f:z:} -T{=?:x:=I:y:=f:z:} -T{=T{=?:x:3x=I:y:=f:z:}:a:=T{=?:x:=I:y:=f:z:}:b:} -T{=?:x:3x=I:y:=f:z:12x} -T{8x=T{=?:x:3x=I:y:=f:z:12x}:a:8x} -T{=3s:a:=3s:b:} -{'names':['x','y','z'], 'formats':['?',' object diff --git a/example/example-opaque-types.py b/example/example-opaque-types.py deleted file mode 100644 index 103563469..000000000 --- a/example/example-opaque-types.py +++ /dev/null @@ -1,52 +0,0 @@ -from __future__ import print_function -import sys - -sys.path.append('.') - -from example import StringList, print_opaque_list -from example import ClassWithSTLVecProperty -from example import return_void_ptr, print_void_ptr -from example import return_null_str, print_null_str -from example import return_unique_ptr -from example import ExampleMandA - -##### - -l = StringList() -l.push_back("Element 1") -l.push_back("Element 2") -print_opaque_list(l) -print("Back element is %s" % l.back()) -for i, k in enumerate(l): - print("%i/%i : %s" % (i + 1, len(l), k)) -l.pop_back() -print_opaque_list(l) - -##### -cvp = ClassWithSTLVecProperty() -print_opaque_list(cvp.stringList) - -cvp.stringList = l -cvp.stringList.push_back("Element 3") -print_opaque_list(cvp.stringList) - -##### - -print_void_ptr(return_void_ptr()) -print_void_ptr(ExampleMandA()) # Should also work for other C++ types -from example import ConstructorStats -print("ExampleMandA still alive:", ConstructorStats.get(ExampleMandA).alive()) - -try: - print_void_ptr([1, 2, 3]) # This should not work -except Exception as e: - print("Caught expected exception: " + str(e)) - -print(return_null_str()) -print_null_str(return_null_str()) - -##### - -ptr = return_unique_ptr() -print(ptr) -print_opaque_list(ptr) diff --git a/example/example-opaque-types.ref b/example/example-opaque-types.ref deleted file mode 100644 index 12b87d35b..000000000 --- a/example/example-opaque-types.ref +++ /dev/null @@ -1,19 +0,0 @@ -Opaque list: [Element 1, Element 2] -Back element is Element 2 -1/2 : Element 1 -2/2 : Element 2 -Opaque list: [Element 1] -Opaque list: [] -Opaque list: [Element 1, Element 3] -Got void ptr : 0x1234 -### ExampleMandA @ 0x2ac5370 created via default constructor -Got void ptr : 0x2ac5370 -### ExampleMandA @ 0x2ac5370 destroyed -ExampleMandA still alive: 0 -Caught expected exception: Incompatible function arguments. The following argument types are supported: - 1. (arg0: capsule) -> None - Invoked with: [1, 2, 3] -None -Got null str : 0x0 - -Opaque list: [some value] diff --git a/example/example-operator-overloading.py b/example/example-operator-overloading.py deleted file mode 100755 index 4253a75af..000000000 --- a/example/example-operator-overloading.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import sys -sys.path.append('.') - -from example import Vector2, Vector - -v1 = Vector2(1, 2) -v2 = Vector(3, -1) - -print("v1 = " + str(v1)) -print("v2 = " + str(v2)) -print("v1+v2 = " + str(v1+v2)) -print("v1-v2 = " + str(v1-v2)) -print("v1-8 = " + str(v1-8)) -print("v1+8 = " + str(v1+8)) -print("v1*8 = " + str(v1*8)) -print("v1/8 = " + str(v1/8)) -print("8-v1 = " + str(8-v1)) -print("8+v1 = " + str(8+v1)) -print("8*v1 = " + str(8*v1)) -print("8/v1 = " + str(8/v1)) - -v1 += v2 -v1 *= 2 - -print("(v1+v2)*2 = " + str(v1)) - -from example import ConstructorStats -cstats = ConstructorStats.get(Vector2) -print("Instances not destroyed:", cstats.alive()) -v1 = None -print("Instances not destroyed:", cstats.alive()) -v2 = None -print("Instances not destroyed:", cstats.alive()) -print("Constructor values:", cstats.values()) -print("Default constructions:", cstats.default_constructions) -print("Copy constructions:", cstats.copy_constructions) -print("Move constructions:", cstats.move_constructions >= 10) -print("Copy assignments:", cstats.copy_assignments) -print("Move assignments:", cstats.move_assignments) diff --git a/example/example-operator-overloading.ref b/example/example-operator-overloading.ref deleted file mode 100644 index 82365312a..000000000 --- a/example/example-operator-overloading.ref +++ /dev/null @@ -1,66 +0,0 @@ -### Vector2 @ 0x11f7830 created [1.000000, 2.000000] -### Vector2 @ 0x11427c0 created [3.000000, -1.000000] -v1 = [1.000000, 2.000000] -v2 = [3.000000, -1.000000] -### Vector2 @ 0x7ffef6b144b8 created [4.000000, 1.000000] -### Vector2 @ 0x11f7e90 created via move constructor -### Vector2 @ 0x7ffef6b144b8 destroyed -### Vector2 @ 0x11f7e90 destroyed -v1+v2 = [4.000000, 1.000000] -### Vector2 @ 0x7ffef6b144b8 created [-2.000000, 3.000000] -### Vector2 @ 0x11f7e90 created via move constructor -### Vector2 @ 0x7ffef6b144b8 destroyed -### Vector2 @ 0x11f7e90 destroyed -v1-v2 = [-2.000000, 3.000000] -### Vector2 @ 0x7ffef6b144c8 created [-7.000000, -6.000000] -### Vector2 @ 0x1115760 created via move constructor -### Vector2 @ 0x7ffef6b144c8 destroyed -### Vector2 @ 0x1115760 destroyed -v1-8 = [-7.000000, -6.000000] -### Vector2 @ 0x7ffef6b144c8 created [9.000000, 10.000000] -### Vector2 @ 0x1115760 created via move constructor -### Vector2 @ 0x7ffef6b144c8 destroyed -### Vector2 @ 0x1115760 destroyed -v1+8 = [9.000000, 10.000000] -### Vector2 @ 0x7ffef6b144b8 created [8.000000, 16.000000] -### Vector2 @ 0x1115760 created via move constructor -### Vector2 @ 0x7ffef6b144b8 destroyed -### Vector2 @ 0x1115760 destroyed -v1*8 = [8.000000, 16.000000] -### Vector2 @ 0x7ffef6b144a8 created [0.125000, 0.250000] -### Vector2 @ 0x112f150 created via move constructor -### Vector2 @ 0x7ffef6b144a8 destroyed -### Vector2 @ 0x112f150 destroyed -v1/8 = [0.125000, 0.250000] -### Vector2 @ 0x7ffef6b144f8 created [7.000000, 6.000000] -### Vector2 @ 0x112f1b0 created via move constructor -### Vector2 @ 0x7ffef6b144f8 destroyed -### Vector2 @ 0x112f1b0 destroyed -8-v1 = [7.000000, 6.000000] -### Vector2 @ 0x7ffef6b144f8 created [9.000000, 10.000000] -### Vector2 @ 0x112f1b0 created via move constructor -### Vector2 @ 0x7ffef6b144f8 destroyed -### Vector2 @ 0x112f1b0 destroyed -8+v1 = [9.000000, 10.000000] -### Vector2 @ 0x7ffef6b144e8 created [8.000000, 16.000000] -### Vector2 @ 0x112f230 created via move constructor -### Vector2 @ 0x7ffef6b144e8 destroyed -### Vector2 @ 0x112f230 destroyed -8*v1 = [8.000000, 16.000000] -### Vector2 @ 0x7ffef6b144d8 created [8.000000, 4.000000] -### Vector2 @ 0x11fb360 created via move constructor -### Vector2 @ 0x7ffef6b144d8 destroyed -### Vector2 @ 0x11fb360 destroyed -8/v1 = [8.000000, 4.000000] -(v1+v2)*2 = [8.000000, 2.000000] -Instances not destroyed: 2 -### Vector2 @ 0x11f7830 destroyed -Instances not destroyed: 1 -### Vector2 @ 0x11427c0 destroyed -Instances not destroyed: 0 -Constructor 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]'] -Default constructions: 0 -Copy constructions: 0 -Move constructions: True -Copy assignments: 0 -Move assignments: 0 diff --git a/example/example-pickling.py b/example/example-pickling.py deleted file mode 100644 index 1810d3e2e..000000000 --- a/example/example-pickling.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import print_function -import sys - -sys.path.append('.') - -from example import Pickleable - -try: - import cPickle as pickle # Use cPickle on Python 2.7 -except ImportError: - import pickle - -p = Pickleable("test_value") -p.setExtra1(15) -p.setExtra2(48) - -data = pickle.dumps(p, 2) # Must use pickle protocol >= 2 -print("%s %i %i" % (p.value(), p.extra1(), p.extra2())) - -p2 = pickle.loads(data) -print("%s %i %i" % (p2.value(), p2.extra1(), p2.extra2())) diff --git a/example/example-pickling.ref b/example/example-pickling.ref deleted file mode 100644 index d804973a1..000000000 --- a/example/example-pickling.ref +++ /dev/null @@ -1,2 +0,0 @@ -test_value 15 48 -test_value 15 48 diff --git a/example/example-python-types.py b/example/example-python-types.py deleted file mode 100755 index 11b89bfe2..000000000 --- a/example/example-python-types.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import sys, pydoc -sys.path.append('.') - -import example -from example import ExamplePythonTypes - -ExamplePythonTypes.value = 15 -print(ExamplePythonTypes.value) -print(ExamplePythonTypes.value2) - -try: - ExamplePythonTypes() -except Exception as e: - print(e) - -try: - ExamplePythonTypes.value2 = 15 -except Exception as e: - print(e) - -instance = ExamplePythonTypes.new_instance() - -dict_result = instance.get_dict() -dict_result['key2'] = 'value2' -instance.print_dict(dict_result) - -dict_result = instance.get_dict_2() -dict_result['key2'] = 'value2' -instance.print_dict_2(dict_result) - -set_result = instance.get_set() -set_result.add('key3') -instance.print_set(set_result) - -set_result = instance.get_set2() -set_result.add('key3') -instance.print_set_2(set_result) - -list_result = instance.get_list() -list_result.append('value2') -instance.print_list(list_result) - -list_result = instance.get_list_2() -list_result.append('value2') -instance.print_list_2(list_result) - -array_result = instance.get_array() -print(array_result) -instance.print_array(array_result) - -try: - instance.throw_exception() -except Exception as e: - print(e) - -print(instance.pair_passthrough((True, "test"))) -print(instance.tuple_passthrough((True, "test", 5))) - -print(pydoc.render_doc(ExamplePythonTypes, "Help on %s")) - -print("__name__(example) = %s" % example.__name__) -print("__name__(example.ExamplePythonTypes) = %s" % ExamplePythonTypes.__name__) -print("__module__(example.ExamplePythonTypes) = %s" % ExamplePythonTypes.__module__) -print("__name__(example.ExamplePythonTypes.get_set) = %s" % ExamplePythonTypes.get_set.__name__) -print("__module__(example.ExamplePythonTypes.get_set) = %s" % ExamplePythonTypes.get_set.__module__) - -print(instance.get_bytes_from_string().decode()) -print(instance.get_bytes_from_str().decode()) -print(instance.get_str_from_string().encode().decode()) -print(instance.get_str_from_bytes().encode().decode()) - -class A(object): - __str__ = lambda _: 'this is a str' - __repr__ = lambda _: 'this is a repr' - -instance.test_print(A()) - -from example import ConstructorStats - -cstats = ConstructorStats.get(ExamplePythonTypes) -print("Instances not destroyed:", cstats.alive()) -instance = None -print("Instances not destroyed:", cstats.alive()) diff --git a/example/example-python-types.ref b/example/example-python-types.ref deleted file mode 100644 index d89acb651..000000000 --- a/example/example-python-types.ref +++ /dev/null @@ -1,146 +0,0 @@ -15 -5 -example.ExamplePythonTypes: No constructor defined! -can't set attribute -### ExamplePythonTypes @ 0x1045b80 created via new_instance -key: key2, value=value2 -key: key, value=value -key: key, value=value -key: key2, value=value2 -key: key3 -key: key2 -key: key1 -key: key1 -key: key2 -key: key3 -Entry at positon 0: value -list item 0: overwritten -list item 1: value2 -list item 0: value -list item 1: value2 -[u'array entry 1', u'array entry 2'] -array item 0: array entry 1 -array item 1: array entry 2 -This exception was intentionally thrown. -(u'test', True) -(5L, u'test', True) -Help on class ExamplePythonTypes in module example - -class EExxaammpplleePPyytthhoonnTTyyppeess(__builtin__.object) - | Example 2 documentation - | - | Methods defined here: - | - | ____iinniitt____(...) - | x.__init__(...) initializes x; see help(type(x)) for signature - | - | ggeett__aarrrraayy(...) - | - | Signature : (example.ExamplePythonTypes) -> List[unicode[2]] - | Return a C++ array - | - | ggeett__ddiicctt(...) - | Signature : (example.ExamplePythonTypes) -> dict - | - | Return a Python dictionary - | - | ggeett__ddiicctt__22(...) - | - | Signature : (example.ExamplePythonTypes) -> Dict[unicode, unicode] - | Return a C++ dictionary - | - | ggeett__lliisstt(...) - | Signature : (example.ExamplePythonTypes) -> list - | - | Return a Python list - | - | ggeett__lliisstt__22(...) - | - | Signature : (example.ExamplePythonTypes) -> List[unicode] - | Return a C++ list - | - | ggeett__sseett(...) - | Signature : (example.ExamplePythonTypes) -> set - | - | Return a Python set - | - | ggeett__sseett22(...) - | Signature : (example.ExamplePythonTypes) -> set - | - | Return a C++ set - | - | ppaaiirr__ppaasssstthhrroouugghh(...) - | - | Signature : (example.ExamplePythonTypes, Tuple[bool, unicode]) -> Tuple[unicode, bool] - | Return a pair in reversed order - | - | pprriinntt__aarrrraayy(...) - | - | Signature : (example.ExamplePythonTypes, List[unicode[2]]) -> None - | Print entries of a C++ array - | - | pprriinntt__ddiicctt(...) - | - | Signature : (example.ExamplePythonTypes, dict) -> None - | Print entries of a Python dictionary - | - | pprriinntt__ddiicctt__22(...) - | - | Signature : (example.ExamplePythonTypes, Dict[unicode, unicode]) -> None - | Print entries of a C++ dictionary - | - | pprriinntt__lliisstt(...) - | - | Signature : (example.ExamplePythonTypes, list) -> None - | Print entries of a Python list - | - | pprriinntt__lliisstt__22(...) - | - | Signature : (example.ExamplePythonTypes, List[unicode]) -> None - | Print entries of a C++ list - | - | pprriinntt__sseett(...) - | - | Signature : (example.ExamplePythonTypes, set) -> None - | Print entries of a Python set - | - | pprriinntt__sseett__22(...) - | - | Signature : (example.ExamplePythonTypes, Set[unicode]) -> None - | Print entries of a C++ set - | - | tthhrrooww__eexxcceeppttiioonn(...) - | - | Signature : (example.ExamplePythonTypes) -> None - | Throw an exception - | - | ttuuppllee__ppaasssstthhrroouugghh(...) - | - | Signature : (example.ExamplePythonTypes, Tuple[bool, unicode, int]) -> Tuple[int, unicode, bool] - | Return a triple in reversed order - | - | ---------------------------------------------------------------------- - | Data and other attributes defined here: - | - | ____nneeww____ = - | T.__new__(S, ...) -> a new object with type S, a subtype of T - | - | nneeww__iinnssttaannccee = - | Signature : () -> example.ExamplePythonTypes - | - | Return an instance - -__name__(example) = example -__name__(example.ExamplePythonTypes) = ExamplePythonTypes -__module__(example.ExamplePythonTypes) = example -__name__(example.ExamplePythonTypes.get_set) = get_set -__module__(example.ExamplePythonTypes.get_set) = example -foo -bar -baz -boo -this is a str -this is a repr -Instances not destroyed: 1 -### ExamplePythonTypes @ 0x1045b80 destroyed -Instances not destroyed: 0 diff --git a/example/example-sequences-and-iterators.py b/example/example-sequences-and-iterators.py deleted file mode 100755 index 764a52767..000000000 --- a/example/example-sequences-and-iterators.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import sys -sys.path.append('.') - -from example import Sequence, StringMap - -s = Sequence(5) -print("s = " + str(s)) -print("len(s) = " + str(len(s))) -print("s[0], s[3] = %f %f" % (s[0], s[3])) -print('12.34 in s: ' + str(12.34 in s)) -s[0], s[3] = 12.34, 56.78 -print('12.34 in s: ' + str(12.34 in s)) -print("s[0], s[3] = %f %f" % (s[0], s[3])) -rev = reversed(s) -rev2 = s[::-1] -print("rev[0], rev[1], rev[2], rev[3], rev[4] = %f %f %f %f %f" % (rev[0], rev[1], rev[2], rev[3], rev[4])) - -for i in rev: - print(i, end=' ') -print('') -for i in rev2: - print(i, end=' ') -print('') -print(rev == rev2) -rev[0::2] = Sequence([2.0, 2.0, 2.0]) -for i in rev: - print(i, end=' ') -print('') - -m = StringMap({ 'hi': 'bye', 'black': 'white' }) -print(m['hi']) -print(len(m)) -print(m['black']) -try: - print(m['orange']) - print('Error: should have thrown exception') -except KeyError: - pass -m['orange'] = 'banana' -print(m['orange']) - -for k in m: - print("key = %s, value = %s" % (k, m[k])) - -for k,v in m.items(): - print("item: (%s, %s)" % (k,v)) - -from example import ConstructorStats -cstats = ConstructorStats.get(Sequence) -print("Instances not destroyed:", cstats.alive()) -s = None -print("Instances not destroyed:", cstats.alive()) -rev = None -print("Instances not destroyed:", cstats.alive()) -rev2 = None -print("Instances not destroyed:", cstats.alive()) -print("Constructor values:", cstats.values()) -print("Default constructions:", cstats.default_constructions) -print("Copy constructions:", cstats.copy_constructions) -print("Move constructions:", cstats.move_constructions >= 1) -print("Copy assignments:", cstats.copy_assignments) -print("Move assignments:", cstats.move_assignments) diff --git a/example/example-sequences-and-iterators.ref b/example/example-sequences-and-iterators.ref deleted file mode 100644 index d658fba15..000000000 --- a/example/example-sequences-and-iterators.ref +++ /dev/null @@ -1,41 +0,0 @@ -### Sequence @ 0x1535b00 created of size 5 -s = -len(s) = 5 -s[0], s[3] = 0.000000 0.000000 -12.34 in s: False -12.34 in s: True -s[0], s[3] = 12.340000 56.779999 -### Sequence @ 0x7fff22a45068 created of size 5 -### Sequence @ 0x1538b90 created via move constructor -### Sequence @ 0x7fff22a45068 destroyed -### Sequence @ 0x1538bf0 created of size 5 -rev[0], rev[1], rev[2], rev[3], rev[4] = 0.000000 56.779999 0.000000 0.000000 12.340000 -0.0 56.779998779296875 0.0 0.0 12.34000015258789 -0.0 56.779998779296875 0.0 0.0 12.34000015258789 -True -### Sequence @ 0x1b4d1f0 created of size 3 from std::vector -### Sequence @ 0x1b4d1f0 destroyed -2.0 56.779998779296875 2.0 0.0 2.0 -bye -2 -white -banana -key = orange, value = banana -key = hi, value = bye -key = black, value = white -item: (orange, banana) -item: (hi, bye) -item: (black, white) -Instances not destroyed: 3 -### Sequence @ 0x1535b00 destroyed -Instances not destroyed: 2 -### Sequence @ 0x1538b90 destroyed -Instances not destroyed: 1 -### Sequence @ 0x1538bf0 destroyed -Instances not destroyed: 0 -Constructor values: ['of size', '5', 'of size', '5', 'of size', '5', 'of size', '3', 'from std::vector'] -Default constructions: 0 -Copy constructions: 0 -Move constructions: True -Copy assignments: 0 -Move assignments: 0 diff --git a/example/example-smart-ptr.py b/example/example-smart-ptr.py deleted file mode 100755 index fe23e1131..000000000 --- a/example/example-smart-ptr.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import sys -sys.path.append('.') - -from example import MyObject1 -from example import MyObject2 -from example import MyObject3 - -from example import make_object_1 -from example import make_object_2 -from example import make_myobject1_1 -from example import make_myobject1_2 -from example import make_myobject2_1 -from example import make_myobject2_2 -from example import make_myobject3_1 -from example import make_myobject3_2 - -from example import print_object_1 -from example import print_object_2 -from example import print_object_3 -from example import print_object_4 - -from example import print_myobject1_1 -from example import print_myobject1_2 -from example import print_myobject1_3 -from example import print_myobject1_4 - -from example import print_myobject2_1 -from example import print_myobject2_2 -from example import print_myobject2_3 -from example import print_myobject2_4 - -from example import print_myobject3_1 -from example import print_myobject3_2 -from example import print_myobject3_3 -from example import print_myobject3_4 - -for o in [make_object_1(), make_object_2(), MyObject1(3)]: - print("Reference count = %i" % o.getRefCount()) - print_object_1(o) - print_object_2(o) - print_object_3(o) - print_object_4(o) - -for o in [make_myobject1_1(), make_myobject1_2(), MyObject1(6), 7]: - print(o) - if not isinstance(o, int): - print_object_1(o) - print_object_2(o) - print_object_3(o) - print_object_4(o) - print_myobject1_1(o) - print_myobject1_2(o) - print_myobject1_3(o) - print_myobject1_4(o) - -for o in [MyObject2(8), make_myobject2_1(), make_myobject2_2()]: - print(o) - print_myobject2_1(o) - print_myobject2_2(o) - print_myobject2_3(o) - print_myobject2_4(o) - -for o in [MyObject3(9), make_myobject3_1(), make_myobject3_2()]: - print(o) - print_myobject3_1(o) - print_myobject3_2(o) - print_myobject3_3(o) - print_myobject3_4(o) - -from example import ConstructorStats, cstats_ref, Object - -cstats = [ConstructorStats.get(Object), ConstructorStats.get(MyObject1), - ConstructorStats.get(MyObject2), ConstructorStats.get(MyObject3), - cstats_ref()] -print("Instances not destroyed:", [x.alive() for x in cstats]) -o = None -print("Instances not destroyed:", [x.alive() for x in cstats]) -print("Object value constructions:", [x.values() for x in cstats]) -print("Default constructions:", [x.default_constructions for x in cstats]) -print("Copy constructions:", [x.copy_constructions for x in cstats]) -#print("Move constructions:", [x.move_constructions >= 0 for x in cstats]) # Doesn't invoke any -print("Copy assignments:", [x.copy_assignments for x in cstats]) -print("Move assignments:", [x.move_assignments for x in cstats]) diff --git a/example/example-smart-ptr.ref b/example/example-smart-ptr.ref deleted file mode 100644 index 52ffa8bf1..000000000 --- a/example/example-smart-ptr.ref +++ /dev/null @@ -1,270 +0,0 @@ -### Object @ 0xdeffd0 created via default constructor -### MyObject1 @ 0xdeffd0 created MyObject1[1] -### ref @ 0x7f6a2e03c4a8 created from pointer 0xdeffd0 -### Object @ 0xe43f50 created via default constructor -### MyObject1 @ 0xe43f50 created MyObject1[2] -### ref @ 0x7fff136845d0 created from pointer 0xe43f50 -### ref @ 0x7f6a2c32aad8 created via copy constructor with pointer 0xe43f50 -### ref @ 0x7fff136845d0 destroyed -### Object @ 0xee8cf0 created via default constructor -### MyObject1 @ 0xee8cf0 created MyObject1[3] -### ref @ 0x7f6a2c32ab08 created from pointer 0xee8cf0 -Reference count = 1 -MyObject1[1] -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xdeffd0 -### ref @ 0x7fff136845a8 created via copy constructor with pointer 0xdeffd0 -MyObject1[1] -### ref @ 0x7fff136845a8 destroyed -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xdeffd0 -MyObject1[1] -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xdeffd0 -MyObject1[1] -### ref @ 0x7fff136845c8 destroyed -Reference count = 1 -MyObject1[2] -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xe43f50 -### ref @ 0x7fff136845a8 created via copy constructor with pointer 0xe43f50 -MyObject1[2] -### ref @ 0x7fff136845a8 destroyed -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xe43f50 -MyObject1[2] -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xe43f50 -MyObject1[2] -### ref @ 0x7fff136845c8 destroyed -Reference count = 1 -MyObject1[3] -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8cf0 -### ref @ 0x7fff136845a8 created via copy constructor with pointer 0xee8cf0 -MyObject1[3] -### ref @ 0x7fff136845a8 destroyed -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8cf0 -MyObject1[3] -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8cf0 -MyObject1[3] -### ref @ 0x7fff136845c8 destroyed -### MyObject1 @ 0xe43f50 destroyed -### Object @ 0xe43f50 destroyed -### ref @ 0x7f6a2c32aad8 destroyed -### MyObject1 @ 0xdeffd0 destroyed -### Object @ 0xdeffd0 destroyed -### ref @ 0x7f6a2e03c4a8 destroyed -### Object @ 0xee8310 created via default constructor -### MyObject1 @ 0xee8310 created MyObject1[4] -### ref @ 0x7f6a2e03c4a8 created from pointer 0xee8310 -### Object @ 0xee8470 created via default constructor -### MyObject1 @ 0xee8470 created MyObject1[5] -### ref @ 0x7fff136845d0 created from pointer 0xee8470 -### ref @ 0x7f6a2c32aad8 created via copy constructor with pointer 0xee8470 -### ref @ 0x7fff136845d0 destroyed -### Object @ 0xee95a0 created via default constructor -### MyObject1 @ 0xee95a0 created MyObject1[6] -### ref @ 0x7f6a2c32ab38 created from pointer 0xee95a0 -### MyObject1 @ 0xee8cf0 destroyed -### Object @ 0xee8cf0 destroyed -### ref @ 0x7f6a2c32ab08 destroyed - -MyObject1[4] -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310 -### ref @ 0x7fff136845a8 created via copy constructor with pointer 0xee8310 -MyObject1[4] -### ref @ 0x7fff136845a8 destroyed -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310 -MyObject1[4] -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310 -MyObject1[4] -### ref @ 0x7fff136845c8 destroyed -MyObject1[4] -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310 -### ref @ 0x7fff136845a8 created via copy constructor with pointer 0xee8310 -MyObject1[4] -### ref @ 0x7fff136845a8 destroyed -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310 -MyObject1[4] -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8310 -MyObject1[4] -### ref @ 0x7fff136845c8 destroyed - -MyObject1[5] -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470 -### ref @ 0x7fff136845a8 created via copy constructor with pointer 0xee8470 -MyObject1[5] -### ref @ 0x7fff136845a8 destroyed -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470 -MyObject1[5] -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470 -MyObject1[5] -### ref @ 0x7fff136845c8 destroyed -MyObject1[5] -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470 -### ref @ 0x7fff136845a8 created via copy constructor with pointer 0xee8470 -MyObject1[5] -### ref @ 0x7fff136845a8 destroyed -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470 -MyObject1[5] -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee8470 -MyObject1[5] -### ref @ 0x7fff136845c8 destroyed - -MyObject1[6] -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0 -### ref @ 0x7fff136845a8 created via copy constructor with pointer 0xee95a0 -MyObject1[6] -### ref @ 0x7fff136845a8 destroyed -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0 -MyObject1[6] -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0 -MyObject1[6] -### ref @ 0x7fff136845c8 destroyed -MyObject1[6] -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0 -### ref @ 0x7fff136845a8 created via copy constructor with pointer 0xee95a0 -MyObject1[6] -### ref @ 0x7fff136845a8 destroyed -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0 -MyObject1[6] -### ref @ 0x7fff136845c8 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee95a0 -MyObject1[6] -### ref @ 0x7fff136845c8 destroyed -7 -### Object @ 0xee97f0 created via default constructor -### MyObject1 @ 0xee97f0 created MyObject1[7] -### ref @ 0x7f6a2c32ab08 created from pointer 0xee97f0 -MyObject1[7] -### MyObject1 @ 0xee97f0 destroyed -### Object @ 0xee97f0 destroyed -### ref @ 0x7f6a2c32ab08 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### Object @ 0xee99e0 created via default constructor -### MyObject1 @ 0xee99e0 created MyObject1[7] -### ref @ 0x7f6a2c32ab08 created from pointer 0xee99e0 -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee99e0 -### ref @ 0x7fff136845a8 created via copy constructor with pointer 0xee99e0 -MyObject1[7] -### ref @ 0x7fff136845a8 destroyed -### ref @ 0x7fff136845c8 destroyed -### MyObject1 @ 0xee99e0 destroyed -### Object @ 0xee99e0 destroyed -### ref @ 0x7f6a2c32ab08 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### Object @ 0xee97f0 created via default constructor -### MyObject1 @ 0xee97f0 created MyObject1[7] -### ref @ 0x7f6a2c32ab08 created from pointer 0xee97f0 -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee97f0 -MyObject1[7] -### ref @ 0x7fff136845c8 destroyed -### MyObject1 @ 0xee97f0 destroyed -### Object @ 0xee97f0 destroyed -### ref @ 0x7f6a2c32ab08 destroyed -### ref @ 0x7fff136845c8 created via default constructor -### Object @ 0xee99e0 created via default constructor -### MyObject1 @ 0xee99e0 created MyObject1[7] -### ref @ 0x7f6a2c32ab08 created from pointer 0xee99e0 -### ref @ 0x7fff136845c8 assigned via copy assignment pointer 0xee99e0 -MyObject1[7] -### ref @ 0x7fff136845c8 destroyed -### MyObject1 @ 0xee99e0 destroyed -### Object @ 0xee99e0 destroyed -### ref @ 0x7f6a2c32ab08 destroyed -### MyObject1 @ 0xee95a0 destroyed -### Object @ 0xee95a0 destroyed -### ref @ 0x7f6a2c32ab38 destroyed -### MyObject1 @ 0xee8470 destroyed -### Object @ 0xee8470 destroyed -### ref @ 0x7f6a2c32aad8 destroyed -### MyObject1 @ 0xee8310 destroyed -### Object @ 0xee8310 destroyed -### ref @ 0x7f6a2e03c4a8 destroyed -### MyObject2 @ 0xe43f50 created MyObject2[8] -### MyObject2 @ 0xee95a0 created MyObject2[6] -### MyObject2 @ 0xee95d0 created MyObject2[7] - -MyObject2[8] -MyObject2[8] -MyObject2[8] -MyObject2[8] - -MyObject2[6] -MyObject2[6] -MyObject2[6] -MyObject2[6] - -MyObject2[7] -MyObject2[7] -MyObject2[7] -MyObject2[7] -### MyObject2 @ 0xee95a0 destroyed -### MyObject2 @ 0xe43f50 destroyed -### MyObject3 @ 0xee9ac0 created MyObject3[9] -### MyObject3 @ 0xe43f90 created MyObject3[8] -### MyObject3 @ 0xeea7d0 created MyObject3[9] -### MyObject2 @ 0xee95d0 destroyed - -MyObject3[9] -MyObject3[9] -MyObject3[9] -MyObject3[9] - -MyObject3[8] -MyObject3[8] -MyObject3[8] -MyObject3[8] - -MyObject3[9] -MyObject3[9] -MyObject3[9] -MyObject3[9] -### MyObject3 @ 0xe43f90 destroyed -### MyObject3 @ 0xee9ac0 destroyed -Instances not destroyed: [0, 0, 0, 1, 0] -### MyObject3 @ 0xeea7d0 destroyed -Instances not destroyed: [0, 0, 0, 0, 0] -Object value constructions: [[], ['MyObject1[1]', 'MyObject1[2]', 'MyObject1[3]', 'MyObject1[4]', 'MyObject1[5]', 'MyObject1[6]', 'MyObject1[7]', 'MyObject1[7]', 'MyObject1[7]', 'MyObject1[7]'], ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]'], ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]'], ['from pointer', 'from pointer', 'from pointer', 'from pointer', 'from pointer', 'from pointer', 'from pointer', 'from pointer', 'from pointer', 'from pointer']] -Default constructions: [10, 0, 0, 0, 30] -Copy constructions: [0, 0, 0, 0, 12] -Copy assignments: [0, 0, 0, 0, 30] -Move assignments: [0, 0, 0, 0, 0] diff --git a/example/example-stl-binder-vector.py b/example/example-stl-binder-vector.py deleted file mode 100644 index feae30708..000000000 --- a/example/example-stl-binder-vector.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function - -from example import VectorInt, El, VectorEl, VectorVectorEl, VectorBool - -v_int = VectorInt([0, 0]) -print(len(v_int)) - -print(bool(v_int)) - -v_int2 = VectorInt([0, 0]) -print(v_int == v_int2) - -v_int2[1] = 1 -print(v_int != v_int2) - -v_int2.append(2) -v_int2.append(3) -v_int2.insert(0, 1) -v_int2.insert(0, 2) -v_int2.insert(0, 3) -print(v_int2) - -v_int.append(99) -v_int2[2:-2] = v_int -print(v_int2) -del v_int2[1:3] -print(v_int2) -del v_int2[0] -print(v_int2) - -v_a = VectorEl() -v_a.append(El(1)) -v_a.append(El(2)) -print(v_a) - -vv_a = VectorVectorEl() -vv_a.append(v_a) -vv_b = vv_a[0] -print(vv_b) - -vv_c = VectorBool() -for i in range(10): - vv_c.append(i % 2 == 0) -for i in range(10): - if vv_c[i] != (i % 2 == 0): - print("Error!") -print(vv_c) diff --git a/example/example-stl-binder-vector.ref b/example/example-stl-binder-vector.ref deleted file mode 100644 index cc271f3a9..000000000 --- a/example/example-stl-binder-vector.ref +++ /dev/null @@ -1,11 +0,0 @@ -2 -True -True -True -VectorInt[3, 2, 1, 0, 1, 2, 3] -VectorInt[3, 2, 0, 0, 99, 2, 3] -VectorInt[3, 0, 99, 2, 3] -VectorInt[0, 99, 2, 3] -VectorEl[El{1}, El{2}] -VectorEl[El{1}, El{2}] -VectorBool[1, 0, 1, 0, 1, 0, 1, 0, 1, 0] diff --git a/example/example-virtual-functions.py b/example/example-virtual-functions.py deleted file mode 100644 index d67539b65..000000000 --- a/example/example-virtual-functions.py +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import sys -sys.path.append('.') - -from example import ExampleVirt, runExampleVirt, runExampleVirtVirtual, runExampleVirtBool -from example import A_Repeat, B_Repeat, C_Repeat, D_Repeat, A_Tpl, B_Tpl, C_Tpl, D_Tpl -from example import NCVirt, NonCopyable, Movable - - -class ExtendedExampleVirt(ExampleVirt): - def __init__(self, state): - super(ExtendedExampleVirt, self).__init__(state + 1) - self.data = "Hello world" - - def run(self, value): - print('ExtendedExampleVirt::run(%i), calling parent..' % value) - return super(ExtendedExampleVirt, self).run(value + 1) - - def run_bool(self): - print('ExtendedExampleVirt::run_bool()') - return False - - def pure_virtual(self): - print('ExtendedExampleVirt::pure_virtual(): %s' % self.data) - - -ex12 = ExampleVirt(10) -print(runExampleVirt(ex12, 20)) -try: - runExampleVirtVirtual(ex12) -except Exception as e: - print("Caught expected exception: " + str(e)) - -ex12p = ExtendedExampleVirt(10) -print(runExampleVirt(ex12p, 20)) -print(runExampleVirtBool(ex12p)) -runExampleVirtVirtual(ex12p) - -class VI_AR(A_Repeat): - def unlucky_number(self): - return 99 -class VI_AT(A_Tpl): - def unlucky_number(self): - return 999 - -class VI_CR(C_Repeat): - def lucky_number(self): - return C_Repeat.lucky_number(self) + 1.25 -class VI_CT(C_Tpl): - pass -class VI_CCR(VI_CR): - def lucky_number(self): - return VI_CR.lucky_number(self) * 10 -class VI_CCT(VI_CT): - def lucky_number(self): - return VI_CT.lucky_number(self) * 1000 - - -class VI_DR(D_Repeat): - def unlucky_number(self): - return 123 - def lucky_number(self): - return 42.0 -class VI_DT(D_Tpl): - def say_something(self, times): - print("VI_DT says:" + (' quack' * times)) - def unlucky_number(self): - return 1234 - def lucky_number(self): - return -4.25 - -classes = [ - # A_Repeat, A_Tpl, # abstract (they have a pure virtual unlucky_number) - VI_AR, VI_AT, - B_Repeat, B_Tpl, - C_Repeat, C_Tpl, - VI_CR, VI_CT, VI_CCR, VI_CCT, - D_Repeat, D_Tpl, VI_DR, VI_DT -] - -for cl in classes: - print("\n%s:" % cl.__name__) - obj = cl() - obj.say_something(3) - print("Unlucky = %d" % obj.unlucky_number()) - if hasattr(obj, "lucky_number"): - print("Lucky = %.2f" % obj.lucky_number()) - -class NCVirtExt(NCVirt): - def get_noncopyable(self, a, b): - # Constructs and returns a new instance: - nc = NonCopyable(a*a, b*b) - return nc - def get_movable(self, a, b): - # Return a referenced copy - self.movable = Movable(a, b) - return self.movable - -class NCVirtExt2(NCVirt): - def get_noncopyable(self, a, b): - # Keep a reference: this is going to throw an exception - self.nc = NonCopyable(a, b) - return self.nc - def get_movable(self, a, b): - # Return a new instance without storing it - return Movable(a, b) - -ncv1 = NCVirtExt() -print("2^2 * 3^2 =") -ncv1.print_nc(2, 3) -print("4 + 5 =") -ncv1.print_movable(4, 5) -ncv2 = NCVirtExt2() -print("7 + 7 =") -ncv2.print_movable(7, 7) -try: - ncv2.print_nc(9, 9) - print("Something's wrong: exception not raised!") -except RuntimeError as e: - # Don't print the exception message here because it differs under debug/non-debug mode - print("Caught expected exception") - -from example import ConstructorStats -del ex12 -del ex12p -del obj -del ncv1 -del ncv2 -cstats = [ConstructorStats.get(ExampleVirt), ConstructorStats.get(NonCopyable), ConstructorStats.get(Movable)] -print("Instances not destroyed:", [x.alive() for x in cstats]) -print("Constructor values:", [x.values() for x in cstats]) -print("Copy constructions:", [x.copy_constructions for x in cstats]) -print("Move constructions:", [cstats[i].move_constructions >= 1 for i in range(1, len(cstats))]) - diff --git a/example/example-virtual-functions.ref b/example/example-virtual-functions.ref deleted file mode 100644 index 5927e0d67..000000000 --- a/example/example-virtual-functions.ref +++ /dev/null @@ -1,106 +0,0 @@ -### ExampleVirt @ 0x2073a90 created 10 -Original implementation of ExampleVirt::run(state=10, value=20) -30 -Caught expected exception: Tried to call pure virtual function "ExampleVirt::pure_virtual" -### ExampleVirt @ 0x2076a00 created 11 -ExtendedExampleVirt::run(20), calling parent.. -Original implementation of ExampleVirt::run(state=11, value=21) -32 -ExtendedExampleVirt::run_bool() -False -ExtendedExampleVirt::pure_virtual(): Hello world - -VI_AR: -hihihi -Unlucky = 99 - -VI_AT: -hihihi -Unlucky = 999 - -B_Repeat: -B says hi 3 times -Unlucky = 13 -Lucky = 7.00 - -B_Tpl: -B says hi 3 times -Unlucky = 13 -Lucky = 7.00 - -C_Repeat: -B says hi 3 times -Unlucky = 4444 -Lucky = 888.00 - -C_Tpl: -B says hi 3 times -Unlucky = 4444 -Lucky = 888.00 - -VI_CR: -B says hi 3 times -Unlucky = 4444 -Lucky = 889.25 - -VI_CT: -B says hi 3 times -Unlucky = 4444 -Lucky = 888.00 - -VI_CCR: -B says hi 3 times -Unlucky = 4444 -Lucky = 8892.50 - -VI_CCT: -B says hi 3 times -Unlucky = 4444 -Lucky = 888000.00 - -D_Repeat: -B says hi 3 times -Unlucky = 4444 -Lucky = 888.00 - -D_Tpl: -B says hi 3 times -Unlucky = 4444 -Lucky = 888.00 - -VI_DR: -B says hi 3 times -Unlucky = 123 -Lucky = 42.00 - -VI_DT: -VI_DT says: quack quack quack -Unlucky = 1234 -Lucky = -4.25 -2^2 * 3^2 = -### NonCopyable @ 0x207df10 created 4 9 -### NonCopyable @ 0x7ffcfe866228 created via move constructor -### NonCopyable @ 0x207df10 destroyed -36 -### NonCopyable @ 0x7ffcfe866228 destroyed -4 + 5 = -### Movable @ 0x207e230 created 4 5 -### Movable @ 0x7ffcfe86624c created via copy constructor -9 -### Movable @ 0x7ffcfe86624c destroyed -7 + 7 = -### Movable @ 0x20259e0 created 7 7 -### Movable @ 0x7ffcfe86624c created via move constructor -### Movable @ 0x20259e0 destroyed -14 -### Movable @ 0x7ffcfe86624c destroyed -### NonCopyable @ 0x2025a00 created 9 9 -Caught expected exception -### ExampleVirt @ 0x2073a90 destroyed -### ExampleVirt @ 0x2076a00 destroyed -### Movable @ 0x207e230 destroyed -### NonCopyable @ 0x2025a00 destroyed -Instances not destroyed: [0, 0, 0] -Constructor values: [['10', '11'], ['4', '9', '9', '9'], ['4', '5', '7', '7']] -Copy constructions: [0, 0, 1] -Move constructions: [True, True] diff --git a/example/issues.py b/example/issues.py deleted file mode 100644 index facdafa8d..000000000 --- a/example/issues.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import sys -sys.path.append('.') - -from example.issues import print_cchar, print_char -from example.issues import DispatchIssue, dispatch_issue_go -from example.issues import Placeholder, return_vec_of_reference_wrapper -from example.issues import iterator_passthrough -from example.issues import ElementList, ElementA, print_element -from example.issues import expect_float, expect_int -from example.issues import A, call_f -from example.issues import StrIssue -from example.issues import NestA, NestB, NestC, print_NestA, print_NestB, print_NestC -import gc - -print_cchar("const char *") -print_char('c') - - -class PyClass1(DispatchIssue): - def dispatch(self): - print("Yay..") - - -class PyClass2(DispatchIssue): - def dispatch(self): - try: - super(PyClass2, self).dispatch() - except Exception as e: - print("Failed as expected: " + str(e)) - p = PyClass1() - dispatch_issue_go(p) - -b = PyClass2() -dispatch_issue_go(b) - -print(return_vec_of_reference_wrapper(Placeholder(4))) - -print(list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15])))) - -el = ElementList() -for i in range(10): - el.add(ElementA(i)) -gc.collect() -for i, v in enumerate(el.get()): - print("%i==%i, " % (i, v.value()), end='') -print() - -try: - print_element(None) -except Exception as e: - print("Failed as expected: " + str(e)) - -try: - print(expect_int(5.2)) -except Exception as e: - print("Failed as expected: " + str(e)) - -print(expect_float(12)) - -class B(A): - def __init__(self): - super(B, self).__init__() - - def f(self): - print("In python f()") - -print("C++ version") -a = A() -call_f(a) - -print("Python version") -b = B() -call_f(b) - -print(StrIssue(3)) -try: - print(StrIssue("no", "such", "constructor")) -except TypeError as e: - print("Failed as expected: " + str(e)) - -a = NestA() -b = NestB() -c = NestC() -a += 10 -b.a += 100 -c.b.a += 1000 -b -= 1 -c.b -= 3 -c *= 7 -print_NestA(a) -print_NestA(b.a) -print_NestA(c.b.a) -print_NestB(b) -print_NestB(c.b) -print_NestC(c) -abase = a.as_base() -print(abase.value) -a.as_base().value += 44 -print(abase.value) -print(c.b.a.as_base().value) -c.b.a.as_base().value += 44 -print(c.b.a.as_base().value) -del c -gc.collect() -del a # Should't delete while abase is still alive -gc.collect() -print(abase.value) -del abase -gc.collect() diff --git a/example/issues.ref b/example/issues.ref deleted file mode 100644 index 1d5d0fbc8..000000000 --- a/example/issues.ref +++ /dev/null @@ -1,55 +0,0 @@ -const char * -c -Failed as expected: Tried to call pure virtual function "Base::dispatch" -Yay.. -[Placeholder[1], Placeholder[2], Placeholder[3], Placeholder[4]] -[3, 5, 7, 9, 11, 13, 15] -0==0, 1==1, 2==2, 3==3, 4==4, 5==5, 6==6, 7==7, 8==8, 9==9, -Failed as expected: Incompatible function arguments. The following argument types are supported: - 1. (arg0: example.issues.ElementA) -> None - Invoked with: None -Failed as expected: Incompatible function arguments. The following argument types are supported: - 1. (arg0: int) -> int - Invoked with: 5.2 -12.0 -C++ version -A.f() -Python version -PyA.PyA() -PyA.f() -In python f() -StrIssue.__str__ called -StrIssue[3] -Failed as expected: Incompatible constructor arguments. The following argument types are supported: - 1. example.issues.StrIssue(arg0: int) - 2. example.issues.StrIssue() - Invoked with: no, such, constructor -### NestABase @ 0x15eb630 created via default constructor -### NestA @ 0x15eb630 created via default constructor -### NestABase @ 0x1704000 created via default constructor -### NestA @ 0x1704000 created via default constructor -### NestB @ 0x1704000 created via default constructor -### NestABase @ 0x1633110 created via default constructor -### NestA @ 0x1633110 created via default constructor -### NestB @ 0x1633110 created via default constructor -### NestC @ 0x1633110 created via default constructor -13 -103 -1003 -3 -1 -35 --2 -42 --2 -42 -### NestC @ 0x1633110 destroyed -### NestB @ 0x1633110 destroyed -### NestA @ 0x1633110 destroyed -### NestABase @ 0x1633110 destroyed -42 -### NestA @ 0x15eb630 destroyed -### NestABase @ 0x15eb630 destroyed -### NestB @ 0x1704000 destroyed -### NestA @ 0x1704000 destroyed -### NestABase @ 0x1704000 destroyed diff --git a/example/run_test.py b/example/run_test.py deleted file mode 100755 index 2785c8eaa..000000000 --- a/example/run_test.py +++ /dev/null @@ -1,67 +0,0 @@ -import sys -import os -import re -import subprocess -import difflib - -remove_unicode_marker = re.compile(r'u(\'[^\']*\')') -remove_long_marker = re.compile(r'([0-9])L') -remove_hex = re.compile(r'0x[0-9a-fA-F]+') -shorten_floats = re.compile(r'([1-9][0-9]*\.[0-9]{4})[0-9]*') - -def sanitize(lines): - lines = lines.split('\n') - for i in range(len(lines)): - line = lines[i] - if line.startswith(" |"): - line = "" - if line.startswith("### "): - # Constructor/destructor output. Useful for example, but unreliable across compilers; - # testing of proper construction/destruction occurs with ConstructorStats mechanism instead - line = "" - line = remove_unicode_marker.sub(r'\1', line) - line = remove_long_marker.sub(r'\1', line) - line = remove_hex.sub(r'0', line) - line = shorten_floats.sub(r'\1', line) - line = line.replace('__builtin__', 'builtins') - line = line.replace('example.', '') - line = line.replace('unicode', 'str') - line = line.replace('ExampleWithEnum.EMode', 'EMode') - line = line.replace('example.EMode', 'EMode') - line = line.replace('method of builtins.PyCapsule instance', '') - line = line.strip() - lines[i] = line - - return '\n'.join(sorted([l for l in lines if l != ""])) - -path = os.path.dirname(__file__) -if path != '': - os.chdir(path) - -if len(sys.argv) < 2: - print("Syntax: %s " % sys.argv[0]) - exit(0) - -name = sys.argv[1] -try: - output_bytes = subprocess.check_output([sys.executable, "-u", name + ".py"], - stderr=subprocess.STDOUT) -except subprocess.CalledProcessError as exc: - print('Test `{}` failed:\n{}\n'.format(name, '-' * 50)) - print(exc.output.decode()) - print('-' * 50) - sys.exit(1) - -output = sanitize(output_bytes.decode('utf-8')) -reference = sanitize(open(name + '.ref', 'r').read()) - -if output == reference: - print('Test "%s" succeeded.' % name) - exit(0) -else: - print('Test "%s" FAILED!' % name) - print('--- output') - print('+++ reference') - print(''.join(difflib.ndiff(output.splitlines(True), - reference.splitlines(True)))) - exit(-1) diff --git a/setup.py b/setup.py index 07465bb67..425e6c57a 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Setup script for PyPI; use CMakeFile.txt to build the example application +# Setup script for PyPI; use CMakeFile.txt to build extension modules from setuptools import setup from pybind11 import __version__ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 000000000..f4339295c --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,62 @@ +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) +endif() + +set(PYBIND11_TEST_FILES + test_buffers.cpp + test_callbacks.cpp + test_constants_and_functions.cpp + test_eval.cpp + test_exceptions.cpp + test_inheritance.cpp + test_issues.cpp + test_keep_alive.cpp + test_kwargs_and_defaults.cpp + test_methods_and_attributes.cpp + test_modules.cpp + test_numpy_dtypes.cpp + test_numpy_vectorize.cpp + test_opaque_types.cpp + test_operator_overloading.cpp + test_pickling.cpp + test_python_types.cpp + test_sequences_and_iterators.cpp + test_smart_ptr.cpp + test_stl_binders.cpp + test_virtual_functions.cpp +) + +# Check if Eigen is available +find_package(Eigen3 QUIET) + +if(EIGEN3_FOUND) + list(APPEND PYBIND11_TEST_FILES test_eigen.cpp) + message(STATUS "Building tests with Eigen v${EIGEN3_VERSION}") +else() + message(STATUS "Building tests WITHOUT Eigen") +endif() + +# Create the binding library +pybind11_add_module(pybind11_tests pybind11_tests.cpp ${PYBIND11_TEST_FILES}) +pybind11_enable_warnings(pybind11_tests) + +if(EIGEN3_FOUND) + target_include_directories(pybind11_tests PRIVATE ${EIGEN3_INCLUDE_DIR}) + target_compile_definitions(pybind11_tests PRIVATE -DPYBIND11_TEST_EIGEN) +endif() + +set(testdir ${PROJECT_SOURCE_DIR}/tests) + +# Always write the output file directly into the 'tests' directory (even on MSVC) +if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) + set_target_properties(pybind11_tests PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${testdir}) + foreach(config ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${config} config) + set_target_properties(pybind11_tests PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} ${testdir}) + endforeach() +endif() + +# A single command to compile and run the tests +add_custom_target(pytest COMMAND ${PYTHON_EXECUTABLE} -m pytest + DEPENDS pybind11_tests WORKING_DIRECTORY ${testdir}) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..5641392d5 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,204 @@ +"""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 os +import sys +import contextlib + +_unicode_marker = re.compile(r'u(\'[^\']*\')') +_long_marker = re.compile(r'([0-9])L') +_hexadecimal = re.compile(r'0x[0-9a-fA-F]+') + + +def _strip_and_dedent(s): + """For triple-quote strings""" + return textwrap.dedent(s.lstrip('\n').rstrip()) + + +def _split_and_sort(s): + """For output which does not require specific line order""" + return sorted(_strip_and_dedent(s).splitlines()) + + +def _make_explanation(a, b): + """Explanation for a failed assert -- the a and b arguments are List[str]""" + return ["--- actual / +++ expected"] + [line.strip('\n') for line in difflib.ndiff(a, b)] + + +class Output(object): + """Basic output post-processing and comparison""" + def __init__(self, string): + self.string = string + self.explanation = [] + + def __str__(self): + return self.string + + def __eq__(self, other): + # Ignore constructor/destructor output which is prefixed with "###" + a = [line for line in self.string.strip().splitlines() if not line.startswith("###")] + b = _strip_and_dedent(other).splitlines() + if a == b: + return True + else: + self.explanation = _make_explanation(a, b) + return False + + +class Unordered(Output): + """Custom comparison for output without strict line ordering""" + def __eq__(self, other): + a = _split_and_sort(self.string) + b = _split_and_sort(other) + if a == b: + return True + else: + self.explanation = _make_explanation(a, b) + return False + + +class Capture(object): + def __init__(self, capfd): + self.capfd = capfd + self.out = "" + + def _flush_stdout(self): + sys.stdout.flush() + os.fsync(sys.stdout.fileno()) # make sure C++ output is also read + return self.capfd.readouterr()[0] + + def __enter__(self): + self._flush_stdout() + return self + + def __exit__(self, *_): + self.out = self._flush_stdout() + + 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) + + +@pytest.fixture +def capture(capfd): + """Extended `capfd` with context manager and custom equality operators""" + return Capture(capfd) + + +class SanitizedString(object): + def __init__(self, sanitizer): + self.sanitizer = sanitizer + self.string = "" + self.explanation = [] + + def __call__(self, thing): + self.string = self.sanitizer(thing) + return self + + def __eq__(self, other): + a = self.string + b = _strip_and_dedent(other) + if a == b: + return True + else: + self.explanation = _make_explanation(a.splitlines(), b.splitlines()) + return False + + +def _sanitize_general(s): + s = s.strip() + s = s.replace("pybind11_tests.", "m.") + s = s.replace("unicode", "str") + s = _long_marker.sub(r"\1", s) + s = _unicode_marker.sub(r"\1", s) + return s + + +def _sanitize_docstring(thing): + s = thing.__doc__ + s = _sanitize_general(s) + return s + + +@pytest.fixture +def doc(): + """Sanitize docstrings and add custom failure explanation""" + return SanitizedString(_sanitize_docstring) + + +def _sanitize_message(thing): + s = str(thing) + s = _sanitize_general(s) + s = _hexadecimal.sub("0", s) + return s + + +@pytest.fixture +def msg(): + """Sanitize messages and add custom failure explanation""" + return SanitizedString(_sanitize_message) + + +# noinspection PyUnusedLocal +def pytest_assertrepr_compare(op, left, right): + """Hook to insert custom failure explanation""" + if hasattr(left, 'explanation'): + return left.explanation + + +@contextlib.contextmanager +def suppress(exception): + """Suppress the desired exception""" + try: + yield + except exception: + pass + + +def pytest_namespace(): + """Add import suppression and test requirements to `pytest` namespace""" + try: + import numpy as np + except ImportError: + np = None + try: + import scipy + except ImportError: + scipy = None + try: + from pybind11_tests import have_eigen + except ImportError: + have_eigen = False + + skipif = pytest.mark.skipif + return { + 'suppress': suppress, + 'requires_numpy': skipif(not np, reason="numpy is not installed"), + 'requires_scipy': skipif(not np, reason="scipy is not installed"), + 'requires_eigen_and_numpy': skipif(not have_eigen or not np, + reason="eigen and/or numpy are not installed"), + 'requires_eigen_and_scipy': skipif(not have_eigen or not scipy, + reason="eigen and/or scipy are not installed"), + } diff --git a/example/constructor-stats.h b/tests/constructor_stats.h similarity index 98% rename from example/constructor-stats.h rename to tests/constructor_stats.h index 0f505c140..757ebf90a 100644 --- a/example/constructor-stats.h +++ b/tests/constructor_stats.h @@ -1,6 +1,6 @@ #pragma once /* - example/constructor-stats.h -- framework for printing and tracking object + tests/constructor_stats.h -- framework for printing and tracking object instance lifetimes in example/test code. Copyright (c) 2016 Jason Rhinelander @@ -64,7 +64,7 @@ inspection/testing in python) by using the functions with `print_` replaced with */ -#include "example.h" +#include "pybind11_tests.h" #include #include #include @@ -117,9 +117,12 @@ public: _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; } diff --git a/example/object.h b/tests/object.h similarity index 99% rename from example/object.h rename to tests/object.h index 4e6fa6e61..99a6916c5 100644 --- a/example/object.h +++ b/tests/object.h @@ -2,7 +2,7 @@ #define __OBJECT_H #include -#include "constructor-stats.h" +#include "constructor_stats.h" /// Reference counted object base class class Object { diff --git a/example/example.cpp b/tests/pybind11_tests.cpp similarity index 87% rename from example/example.cpp rename to tests/pybind11_tests.cpp index bd6ac9b35..507ede828 100644 --- a/example/example.cpp +++ b/tests/pybind11_tests.cpp @@ -1,5 +1,5 @@ /* - example/example.cpp -- pybind example plugin + tests/pybind11_tests.cpp -- pybind example plugin Copyright (c) 2016 Wenzel Jakob @@ -7,8 +7,8 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" -#include "constructor-stats.h" +#include "pybind11_tests.h" +#include "constructor_stats.h" void init_ex_methods_and_attributes(py::module &); void init_ex_python_types(py::module &); @@ -49,8 +49,8 @@ void bind_ConstructorStats(py::module &m) { ; } -PYBIND11_PLUGIN(example) { - py::module m("example", "pybind example plugin"); +PYBIND11_PLUGIN(pybind11_tests) { + py::module m("pybind11_tests", "pybind example plugin"); bind_ConstructorStats(m); @@ -76,9 +76,12 @@ PYBIND11_PLUGIN(example) { init_ex_numpy_dtypes(m); init_issues(m); - #if defined(PYBIND11_TEST_EIGEN) - init_eigen(m); - #endif +#if defined(PYBIND11_TEST_EIGEN) + init_eigen(m); + m.attr("have_eigen") = py::cast(true); +#else + m.attr("have_eigen") = py::cast(false); +#endif return m.ptr(); } diff --git a/example/example.h b/tests/pybind11_tests.h similarity index 100% rename from example/example.h rename to tests/pybind11_tests.h diff --git a/example/example-buffers.cpp b/tests/test_buffers.cpp similarity index 97% rename from example/example-buffers.cpp rename to tests/test_buffers.cpp index fa3178b51..5a4dc67d6 100644 --- a/example/example-buffers.cpp +++ b/tests/test_buffers.cpp @@ -1,5 +1,5 @@ /* - example/example-buffers.cpp -- supporting Pythons' buffer protocol + tests/test_buffers.cpp -- supporting Pythons' buffer protocol Copyright (c) 2016 Wenzel Jakob @@ -7,8 +7,8 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" -#include "constructor-stats.h" +#include "pybind11_tests.h" +#include "constructor_stats.h" class Matrix { public: diff --git a/tests/test_buffers.py b/tests/test_buffers.py new file mode 100644 index 000000000..f0ea964d9 --- /dev/null +++ b/tests/test_buffers.py @@ -0,0 +1,57 @@ +import pytest +from pybind11_tests import Matrix, ConstructorStats + +with pytest.suppress(ImportError): + import numpy as np + + +@pytest.requires_numpy +def test_to_python(): + m = Matrix(5, 5) + + assert m[2, 3] == 0 + m[2, 3] = 4 + assert m[2, 3] == 4 + + m2 = np.array(m, copy=False) + assert m2.shape == (5, 5) + assert abs(m2).sum() == 4 + assert m2[2, 3] == 4 + m2[2, 3] = 5 + assert m2[2, 3] == 5 + + cstats = ConstructorStats.get(Matrix) + assert cstats.alive() == 1 + del m + assert cstats.alive() == 1 + del m2 # holds an m reference + assert cstats.alive() == 0 + assert cstats.values() == ["5x5 matrix"] + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Don't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + +@pytest.requires_numpy +def test_from_python(): + with pytest.raises(RuntimeError) as excinfo: + Matrix(np.array([1, 2, 3])) # trying to assign a 1D array + assert str(excinfo.value) == "Incompatible buffer format!" + + m3 = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) + m4 = Matrix(m3) + + for i in range(m4.rows()): + for j in range(m4.cols()): + assert m3[i, j] == m4[i, j] + + cstats = ConstructorStats.get(Matrix) + assert cstats.alive() == 1 + del m3, m4 + assert cstats.alive() == 0 + assert cstats.values() == ["2x3 matrix"] + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Don't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 diff --git a/example/example-callbacks.cpp b/tests/test_callbacks.cpp similarity index 96% rename from example/example-callbacks.cpp rename to tests/test_callbacks.cpp index a5a3b8338..80a0d0ead 100644 --- a/example/example-callbacks.cpp +++ b/tests/test_callbacks.cpp @@ -1,5 +1,5 @@ /* - example/example-callbacks.cpp -- callbacks + tests/test_callbacks.cpp -- callbacks Copyright (c) 2016 Wenzel Jakob @@ -7,8 +7,8 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" -#include "constructor-stats.h" +#include "pybind11_tests.h" +#include "constructor_stats.h" #include diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py new file mode 100644 index 000000000..3f70e87c4 --- /dev/null +++ b/tests/test_callbacks.py @@ -0,0 +1,130 @@ +import pytest + + +def test_inheritance(capture, msg): + from pybind11_tests import Pet, Dog, Rabbit, dog_bark, pet_print + + roger = Rabbit('Rabbit') + assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot" + with capture: + pet_print(roger) + assert capture == "Rabbit is a parrot" + + polly = Pet('Polly', 'parrot') + assert polly.name() + " is a " + polly.species() == "Polly is a parrot" + with capture: + pet_print(polly) + assert capture == "Polly is a parrot" + + molly = Dog('Molly') + assert molly.name() + " is a " + molly.species() == "Molly is a dog" + with capture: + pet_print(molly) + assert capture == "Molly is a dog" + + with capture: + dog_bark(molly) + assert capture == "Woof!" + + with pytest.raises(TypeError) as excinfo: + dog_bark(polly) + assert msg(excinfo.value) == """ + Incompatible function arguments. The following argument types are supported: + 1. (arg0: m.Dog) -> None + Invoked with: + """ + + +def test_callbacks(capture): + from functools import partial + from pybind11_tests import (test_callback1, test_callback2, test_callback3, + test_callback4, test_callback5) + + def func1(): + print('Callback function 1 called!') + + def func2(a, b, c, d): + print('Callback function 2 called : {}, {}, {}, {}'.format(a, b, c, d)) + return d + + def func3(a): + print('Callback function 3 called : {}'.format(a)) + + with capture: + assert test_callback1(func1) is False + assert capture == "Callback function 1 called!" + with capture: + assert test_callback2(func2) == 5 + assert capture == "Callback function 2 called : Hello, x, True, 5" + with capture: + assert test_callback1(partial(func2, "Hello", "from", "partial", "object")) is False + assert capture == "Callback function 2 called : Hello, from, partial, object" + with capture: + assert test_callback1(partial(func3, "Partial object with one argument")) is False + assert capture == "Callback function 3 called : Partial object with one argument" + with capture: + test_callback3(lambda i: i + 1) + assert capture == "func(43) = 44" + + f = test_callback4() + assert f(43) == 44 + f = test_callback5() + assert f(number=43) == 44 + + +def test_lambda_closure_cleanup(): + from pybind11_tests import test_cleanup, payload_cstats + + test_cleanup() + cstats = payload_cstats() + assert cstats.alive() == 0 + assert cstats.copy_constructions == 1 + assert cstats.move_constructions >= 1 + + +def test_cpp_function_roundtrip(capture): + """Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer""" + from pybind11_tests import dummy_function, dummy_function2, test_dummy_function, roundtrip + + with capture: + test_dummy_function(dummy_function) + assert capture == """ + argument matches dummy_function + eval(1) = 2 + """ + with capture: + test_dummy_function(roundtrip(dummy_function)) + assert capture == """ + roundtrip.. + argument matches dummy_function + eval(1) = 2 + """ + with capture: + assert roundtrip(None) is None + assert capture == "roundtrip (got None).." + with capture: + test_dummy_function(lambda x: x + 2) + assert capture == """ + could not convert to a function pointer. + eval(1) = 3 + """ + + with capture: + with pytest.raises(TypeError) as excinfo: + test_dummy_function(dummy_function2) + assert "Incompatible function arguments" in str(excinfo.value) + assert capture == "could not convert to a function pointer." + + with capture: + with pytest.raises(TypeError) as excinfo: + test_dummy_function(lambda x, y: x + y) + assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument", + "takes exactly 2 arguments")) + assert capture == "could not convert to a function pointer." + + +def test_function_signatures(doc): + from pybind11_tests import test_callback3, test_callback4 + + assert doc(test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> None" + assert doc(test_callback4) == "test_callback4() -> Callable[[int], int]" diff --git a/example/example-constants-and-functions.cpp b/tests/test_constants_and_functions.cpp similarity index 94% rename from example/example-constants-and-functions.cpp rename to tests/test_constants_and_functions.cpp index d7f8ad174..1977a0aef 100644 --- a/example/example-constants-and-functions.cpp +++ b/tests/test_constants_and_functions.cpp @@ -1,5 +1,5 @@ /* - example/example-constants-and-functions.cpp -- global constants and functions, enumerations, raw byte strings + tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw byte strings Copyright (c) 2016 Wenzel Jakob @@ -7,7 +7,7 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" +#include "pybind11_tests.h" enum EMyEnumeration { EFirstEntry = 1, diff --git a/tests/test_constants_and_functions.py b/tests/test_constants_and_functions.py new file mode 100644 index 000000000..119965bf0 --- /dev/null +++ b/tests/test_constants_and_functions.py @@ -0,0 +1,130 @@ +import pytest + + +def test_constants(): + from pybind11_tests import some_constant + + assert some_constant == 14 + + +def test_function_overloading(capture): + from pybind11_tests import EMyEnumeration, test_function + + with capture: + assert test_function() is False + assert test_function(7) == 3.5 + assert test_function(EMyEnumeration.EFirstEntry) is None + assert test_function(EMyEnumeration.ESecondEntry) is None + assert capture == """ + test_function() + test_function(7) + test_function(enum=1) + test_function(enum=2) + """ + + +def test_unscoped_enum(): + from pybind11_tests import EMyEnumeration, EFirstEntry + + assert str(EMyEnumeration.EFirstEntry) == "EMyEnumeration.EFirstEntry" + assert str(EMyEnumeration.ESecondEntry) == "EMyEnumeration.ESecondEntry" + assert str(EFirstEntry) == "EMyEnumeration.EFirstEntry" + + # no TypeError exception for unscoped enum ==/!= int comparisons + y = EMyEnumeration.ESecondEntry + assert y == 2 + assert y != 3 + + assert int(EMyEnumeration.ESecondEntry) == 2 + assert str(EMyEnumeration(2)) == "EMyEnumeration.ESecondEntry" + + +def test_scoped_enum(capture): + from pybind11_tests import ECMyEnum, test_ecenum + + with capture: + test_ecenum(ECMyEnum.Three) + assert capture == "test_ecenum(ECMyEnum::Three)" + z = ECMyEnum.Two + with capture: + test_ecenum(z) + assert capture == "test_ecenum(ECMyEnum::Two)" + + # expected TypeError exceptions for scoped enum ==/!= int comparisons + with pytest.raises(TypeError): + assert z == 2 + with pytest.raises(TypeError): + assert z != 3 + + +def test_implicit_conversion(capture): + from pybind11_tests import ExampleWithEnum + + assert str(ExampleWithEnum.EMode.EFirstMode) == "EMode.EFirstMode" + assert str(ExampleWithEnum.EFirstMode) == "EMode.EFirstMode" + + f = ExampleWithEnum.test_function + first = ExampleWithEnum.EFirstMode + second = ExampleWithEnum.ESecondMode + + with capture: + f(first) + assert capture == "ExampleWithEnum::test_function(enum=1)" + + with capture: + 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)) + assert capture == """ + ExampleWithEnum::test_function(enum=1) + ExampleWithEnum::test_function(enum=1) + ExampleWithEnum::test_function(enum=1) + ExampleWithEnum::test_function(enum=1) + ExampleWithEnum::test_function(enum=1) + ExampleWithEnum::test_function(enum=2) + ExampleWithEnum::test_function(enum=1) + ExampleWithEnum::test_function(enum=2) + ExampleWithEnum::test_function(enum=1) + ExampleWithEnum::test_function(enum=1) + ExampleWithEnum::test_function(enum=1) + ExampleWithEnum::test_function(enum=1) + ExampleWithEnum::test_function(enum=1) + ExampleWithEnum::test_function(enum=2) + ExampleWithEnum::test_function(enum=1) + ExampleWithEnum::test_function(enum=2) + """ + + with capture: + # noinspection PyDictCreation + x = {f(first): 1, f(second): 2} + x[f(first)] = 3 + x[f(second)] = 4 + assert capture == """ + ExampleWithEnum::test_function(enum=1) + ExampleWithEnum::test_function(enum=2) + ExampleWithEnum::test_function(enum=1) + ExampleWithEnum::test_function(enum=2) + """ + # Hashing test + assert str(x) == "{EMode.EFirstMode: 3, EMode.ESecondMode: 4}" + + +def test_bytes(capture): + from pybind11_tests import return_bytes, print_bytes + + with capture: + print_bytes(return_bytes()) + assert capture == """ + bytes[0]=1 + bytes[1]=0 + bytes[2]=2 + bytes[3]=0 + """ diff --git a/example/eigen.cpp b/tests/test_eigen.cpp similarity index 98% rename from example/eigen.cpp rename to tests/test_eigen.cpp index c88bee2bb..42bb969fb 100644 --- a/example/eigen.cpp +++ b/tests/test_eigen.cpp @@ -1,5 +1,5 @@ /* - example/eigen.cpp -- automatic conversion of Eigen types + tests/eigen.cpp -- automatic conversion of Eigen types Copyright (c) 2016 Wenzel Jakob @@ -7,7 +7,7 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" +#include "pybind11_tests.h" #include #include diff --git a/tests/test_eigen.py b/tests/test_eigen.py new file mode 100644 index 000000000..43cc2fb71 --- /dev/null +++ b/tests/test_eigen.py @@ -0,0 +1,136 @@ +import pytest + +with pytest.suppress(ImportError): + import numpy as np + + +ref = np.array([[ 0, 3, 0, 0, 0, 11], + [22, 0, 0, 0, 17, 11], + [ 7, 5, 0, 1, 0, 11], + [ 0, 0, 0, 0, 0, 11], + [ 0, 0, 14, 0, 8, 11]]) + + +def assert_equal_ref(mat): + np.testing.assert_array_equal(mat, ref) + + +def assert_sparse_equal_ref(sparse_mat): + assert_equal_ref(sparse_mat.todense()) + + +@pytest.requires_eigen_and_numpy +def test_fixed(): + from pybind11_tests import fixed_r, fixed_c, fixed_passthrough_r, fixed_passthrough_c + + assert_equal_ref(fixed_c()) + assert_equal_ref(fixed_r()) + assert_equal_ref(fixed_passthrough_r(fixed_r())) + assert_equal_ref(fixed_passthrough_c(fixed_c())) + assert_equal_ref(fixed_passthrough_r(fixed_c())) + assert_equal_ref(fixed_passthrough_c(fixed_r())) + + +@pytest.requires_eigen_and_numpy +def test_dense(): + from pybind11_tests import dense_r, dense_c, dense_passthrough_r, dense_passthrough_c + + assert_equal_ref(dense_r()) + assert_equal_ref(dense_c()) + assert_equal_ref(dense_passthrough_r(dense_r())) + assert_equal_ref(dense_passthrough_c(dense_c())) + assert_equal_ref(dense_passthrough_r(dense_c())) + assert_equal_ref(dense_passthrough_c(dense_r())) + + +@pytest.requires_eigen_and_numpy +def test_nonunit_stride_from_python(): + from pybind11_tests import double_row, double_col, double_mat_cm, double_mat_rm + + counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3)) + first_row = counting_mat[0, :] + first_col = counting_mat[:, 0] + assert np.array_equal(double_row(first_row), 2.0 * first_row) + assert np.array_equal(double_col(first_row), 2.0 * first_row) + assert np.array_equal(double_row(first_col), 2.0 * first_col) + assert np.array_equal(double_col(first_col), 2.0 * first_col) + + counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3)) + slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]] + for slice_idx, ref_mat in enumerate(slices): + assert np.array_equal(double_mat_cm(ref_mat), 2.0 * ref_mat) + assert np.array_equal(double_mat_rm(ref_mat), 2.0 * ref_mat) + + +@pytest.requires_eigen_and_numpy +def test_nonunit_stride_to_python(): + from pybind11_tests import diagonal, diagonal_1, diagonal_n, block + + assert np.all(diagonal(ref) == ref.diagonal()) + assert np.all(diagonal_1(ref) == ref.diagonal(1)) + for i in range(-5, 7): + assert np.all(diagonal_n(ref, i) == ref.diagonal(i)), "diagonal_n({})".format(i) + + assert np.all(block(ref, 2, 1, 3, 3) == ref[2:5, 1:4]) + assert np.all(block(ref, 1, 4, 4, 2) == ref[1:, 4:]) + assert np.all(block(ref, 1, 4, 3, 2) == ref[1:4, 4:]) + + +@pytest.requires_eigen_and_numpy +def test_eigen_ref_to_python(): + from pybind11_tests import cholesky1, cholesky2, cholesky3, cholesky4, cholesky5, cholesky6 + + chols = [cholesky1, cholesky2, cholesky3, cholesky4, cholesky5, cholesky6] + for i, chol in enumerate(chols, start=1): + mymat = chol(np.array([[1, 2, 4], [2, 13, 23], [4, 23, 77]])) + assert np.all(mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])), "cholesky{}".format(i) + + +@pytest.requires_eigen_and_numpy +def test_special_matrix_objects(): + from pybind11_tests import incr_diag, symmetric_upper, symmetric_lower + + assert np.all(incr_diag(7) == np.diag([1, 2, 3, 4, 5, 6, 7])) + + asymm = np.array([[ 1, 2, 3, 4], + [ 5, 6, 7, 8], + [ 9, 10, 11, 12], + [13, 14, 15, 16]]) + symm_lower = np.array(asymm) + symm_upper = np.array(asymm) + for i in range(4): + for j in range(i + 1, 4): + symm_lower[i, j] = symm_lower[j, i] + symm_upper[j, i] = symm_upper[i, j] + + assert np.all(symmetric_lower(asymm) == symm_lower) + assert np.all(symmetric_upper(asymm) == symm_upper) + + +@pytest.requires_eigen_and_numpy +def test_dense_signature(doc): + from pybind11_tests import double_col, double_row, double_mat_rm + + assert doc(double_col) == "double_col(arg0: numpy.ndarray[float32[m, 1]]) -> numpy.ndarray[float32[m, 1]]" + assert doc(double_row) == "double_row(arg0: numpy.ndarray[float32[1, n]]) -> numpy.ndarray[float32[1, n]]" + assert doc(double_mat_rm) == "double_mat_rm(arg0: numpy.ndarray[float32[m, n]]) -> numpy.ndarray[float32[m, n]]" + + +@pytest.requires_eigen_and_scipy +def test_sparse(): + from pybind11_tests import sparse_r, sparse_c, sparse_passthrough_r, sparse_passthrough_c + + assert_sparse_equal_ref(sparse_r()) + assert_sparse_equal_ref(sparse_c()) + assert_sparse_equal_ref(sparse_passthrough_r(sparse_r())) + assert_sparse_equal_ref(sparse_passthrough_c(sparse_c())) + assert_sparse_equal_ref(sparse_passthrough_r(sparse_c())) + assert_sparse_equal_ref(sparse_passthrough_c(sparse_r())) + + +@pytest.requires_eigen_and_scipy +def test_sparse_signature(doc): + from pybind11_tests import sparse_passthrough_r, sparse_passthrough_c + + assert doc(sparse_passthrough_r) == "sparse_passthrough_r(arg0: scipy.sparse.csr_matrix[float32]) -> scipy.sparse.csr_matrix[float32]" + assert doc(sparse_passthrough_c) == "sparse_passthrough_c(arg0: scipy.sparse.csc_matrix[float32]) -> scipy.sparse.csc_matrix[float32]" diff --git a/example/example-eval.cpp b/tests/test_eval.cpp similarity index 90% rename from example/example-eval.cpp rename to tests/test_eval.cpp index f6de893d4..21098ac75 100644 --- a/example/example-eval.cpp +++ b/tests/test_eval.cpp @@ -1,5 +1,5 @@ /* - example/example-eval.cpp -- Usage of eval() and eval_file() + tests/test_eval.cpp -- Usage of eval() and eval_file() Copyright (c) 2016 Klemens D. Morgenstern @@ -9,7 +9,7 @@ #include -#include "example.h" +#include "pybind11_tests.h" void example_eval() { py::module main_module = py::module::import("__main__"); @@ -59,9 +59,9 @@ void example_eval() { main_module.def("call_test2", [&](int value) {val_out = value;}); try { - result = py::eval_file("example-eval_call.py", main_namespace); + result = py::eval_file("test_eval_call.py", main_namespace); } catch (...) { - result = py::eval_file("example/example-eval_call.py", main_namespace); + result = py::eval_file("tests/test_eval_call.py", main_namespace); } if (val_out == 42 && result == py::none()) diff --git a/tests/test_eval.py b/tests/test_eval.py new file mode 100644 index 000000000..2d7611c80 --- /dev/null +++ b/tests/test_eval.py @@ -0,0 +1,22 @@ + + +def test_eval(capture): + from pybind11_tests import example_eval + + with capture: + example_eval() + assert capture == """ + eval_statements test + Hello World! + eval_statements passed + eval test + eval passed + eval_single_statement test + eval_single_statement passed + eval_file test + eval_file passed + eval failure test + eval failure test passed + eval_file failure test + eval_file failure test passed + """ diff --git a/tests/test_eval_call.py b/tests/test_eval_call.py new file mode 100644 index 000000000..b8a7603e9 --- /dev/null +++ b/tests/test_eval_call.py @@ -0,0 +1,4 @@ +# This file is called from 'test_eval.py' + +if 'call_test2' in globals(): + call_test2(y) diff --git a/example/example-custom-exceptions.cpp b/tests/test_exceptions.cpp similarity index 97% rename from example/example-custom-exceptions.cpp rename to tests/test_exceptions.cpp index 41d51d84f..492308faf 100644 --- a/example/example-custom-exceptions.cpp +++ b/tests/test_exceptions.cpp @@ -1,5 +1,5 @@ /* - example/example-custom-exceptions.cpp -- exception translation + tests/test_custom-exceptions.cpp -- exception translation Copyright (c) 2016 Pim Schellart @@ -7,7 +7,7 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" +#include "pybind11_tests.h" // A type that should be raised as an exeption in Python class MyException : public std::exception { diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py new file mode 100644 index 000000000..24f9769b4 --- /dev/null +++ b/tests/test_exceptions.py @@ -0,0 +1,31 @@ +import pytest + + +def test_custom(msg): + from pybind11_tests import (MyException, throws1, throws2, throws3, throws4, + throws_logic_error) + + # Can we catch a MyException?" + with pytest.raises(MyException) as excinfo: + throws1() + assert msg(excinfo.value) == "this error should go to a custom type" + + # Can we translate to standard Python exceptions? + with pytest.raises(RuntimeError) as excinfo: + throws2() + assert msg(excinfo.value) == "this error should go to a standard Python exception" + + # Can we handle unknown exceptions? + with pytest.raises(RuntimeError) as excinfo: + throws3() + assert msg(excinfo.value) == "Caught an unknown exception!" + + # Can we delegate to another handler by rethrowing? + with pytest.raises(MyException) as excinfo: + throws4() + assert msg(excinfo.value) == "this error is rethrown" + + # "Can we fall-through to the default handler?" + with pytest.raises(RuntimeError) as excinfo: + throws_logic_error() + assert msg(excinfo.value) == "this error should fall through to the standard handler" diff --git a/example/example-inheritance.cpp b/tests/test_inheritance.cpp similarity index 94% rename from example/example-inheritance.cpp rename to tests/test_inheritance.cpp index 082978b4e..b70ea77a1 100644 --- a/example/example-inheritance.cpp +++ b/tests/test_inheritance.cpp @@ -1,5 +1,5 @@ /* - example/example-inheritance.cpp -- inheritance, automatic upcasting for polymorphic types + tests/test_inheritance.cpp -- inheritance, automatic upcasting for polymorphic types Copyright (c) 2016 Wenzel Jakob @@ -7,7 +7,7 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" +#include "pybind11_tests.h" class Pet { public: diff --git a/tests/test_inheritance.py b/tests/test_inheritance.py new file mode 100644 index 000000000..a7a9778ca --- /dev/null +++ b/tests/test_inheritance.py @@ -0,0 +1,8 @@ + + +def test_automatic_upcasting(): + from pybind11_tests import return_class_1, return_class_2, return_none + + assert type(return_class_1()).__name__ == "DerivedClass1" + assert type(return_class_2()).__name__ == "DerivedClass2" + assert type(return_none()).__name__ == "NoneType" diff --git a/example/issues.cpp b/tests/test_issues.cpp similarity index 98% rename from example/issues.cpp rename to tests/test_issues.cpp index 7dfa9f5aa..085dff90c 100644 --- a/example/issues.cpp +++ b/tests/test_issues.cpp @@ -1,5 +1,5 @@ /* - example/issues.cpp -- collection of testcases for miscellaneous issues + tests/test_issues.cpp -- collection of testcases for miscellaneous issues Copyright (c) 2016 Wenzel Jakob @@ -7,8 +7,8 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" -#include "constructor-stats.h" +#include "pybind11_tests.h" +#include "constructor_stats.h" #include #include diff --git a/tests/test_issues.py b/tests/test_issues.py new file mode 100644 index 000000000..0ab2e3608 --- /dev/null +++ b/tests/test_issues.py @@ -0,0 +1,176 @@ +import pytest +import gc + + +def test_regressions(capture): + from pybind11_tests.issues import print_cchar, print_char + + with capture: + print_cchar("const char *") # #137: const char* isn't handled properly + assert capture == "const char *" + with capture: + print_char("c") # #150: char bindings broken + assert capture == "c" + + +def test_dispatch_issue(capture, msg): + """#159: virtual function dispatch has problems with similar-named functions""" + from pybind11_tests.issues import DispatchIssue, dispatch_issue_go + + class PyClass1(DispatchIssue): + def dispatch(self): + print("Yay..") + + class PyClass2(DispatchIssue): + def dispatch(self): + with pytest.raises(RuntimeError) as excinfo: + super(PyClass2, self).dispatch() + assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"' + + p = PyClass1() + dispatch_issue_go(p) + + b = PyClass2() + with capture: + dispatch_issue_go(b) + assert capture == "Yay.." + + +def test_reference_wrapper(): + """#171: Can't return reference wrappers (or STL data structures containing them)""" + from pybind11_tests.issues import Placeholder, return_vec_of_reference_wrapper + + assert str(return_vec_of_reference_wrapper(Placeholder(4))) == \ + "[Placeholder[1], Placeholder[2], Placeholder[3], Placeholder[4]]" + + +def test_iterator_passthrough(): + """#181: iterator passthrough did not compile""" + from pybind11_tests.issues import iterator_passthrough + + assert list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15]))) == [3, 5, 7, 9, 11, 13, 15] + + +def test_shared_ptr_gc(): + """// #187: issue involving std::shared_ptr<> return value policy & garbage collection""" + from pybind11_tests.issues import ElementList, ElementA + + el = ElementList() + for i in range(10): + el.add(ElementA(i)) + gc.collect() + for i, v in enumerate(el.get()): + assert i == v.value() + + +def test_no_id(capture, msg): + from pybind11_tests.issues import print_element, expect_float, expect_int + + with pytest.raises(TypeError) as excinfo: + print_element(None) + assert msg(excinfo.value) == """ + Incompatible function arguments. The following argument types are supported: + 1. (arg0: m.issues.ElementA) -> None + Invoked with: None + """ + + with pytest.raises(TypeError) as excinfo: + expect_int(5.2) + assert msg(excinfo.value) == """ + Incompatible function arguments. The following argument types are supported: + 1. (arg0: int) -> int + Invoked with: 5.2 + """ + assert expect_float(12) == 12 + + from pybind11_tests.issues import A, call_f + + class B(A): + def __init__(self): + super(B, self).__init__() + + def f(self): + print("In python f()") + + # C++ version + with capture: + a = A() + call_f(a) + assert capture == "A.f()" + + # Python version + with capture: + b = B() + call_f(b) + assert capture == """ + PyA.PyA() + PyA.f() + In python f() + """ + + +def test_str_issue(capture, msg): + """Issue #283: __str__ called on uninitialized instance when constructor arguments invalid""" + from pybind11_tests.issues import StrIssue + + with capture: + assert str(StrIssue(3)) == "StrIssue[3]" + assert capture == "StrIssue.__str__ called" + + with pytest.raises(TypeError) as excinfo: + str(StrIssue("no", "such", "constructor")) + assert msg(excinfo.value) == """ + Incompatible constructor arguments. The following argument types are supported: + 1. m.issues.StrIssue(arg0: int) + 2. m.issues.StrIssue() + Invoked with: no, such, constructor + """ + + +def test_nested(capture): + """ #328: first member in a class can't be used in operators""" + from pybind11_tests.issues import NestA, NestB, NestC, print_NestA, print_NestB, print_NestC + + a = NestA() + b = NestB() + c = NestC() + + a += 10 + b.a += 100 + c.b.a += 1000 + b -= 1 + c.b -= 3 + c *= 7 + + with capture: + print_NestA(a) + print_NestA(b.a) + print_NestA(c.b.a) + print_NestB(b) + print_NestB(c.b) + print_NestC(c) + assert capture == """ + 13 + 103 + 1003 + 3 + 1 + 35 + """ + + abase = a.as_base() + assert abase.value == -2 + a.as_base().value += 44 + assert abase.value == 42 + assert c.b.a.as_base().value == -2 + c.b.a.as_base().value += 44 + assert c.b.a.as_base().value == 42 + + del c + gc.collect() + del a # Should't delete while abase is still alive + gc.collect() + + assert abase.value == 42 + del abase, b + gc.collect() diff --git a/example/example-keep-alive.cpp b/tests/test_keep_alive.cpp similarity index 92% rename from example/example-keep-alive.cpp rename to tests/test_keep_alive.cpp index c2aeaeefa..25f852ea5 100644 --- a/example/example-keep-alive.cpp +++ b/tests/test_keep_alive.cpp @@ -1,5 +1,5 @@ /* - example/example-keep-alive.cpp -- keep_alive modifier (pybind11's version + tests/test_keep_alive.cpp -- keep_alive modifier (pybind11's version of Boost.Python's with_custodian_and_ward / with_custodian_and_ward_postcall) Copyright (c) 2016 Wenzel Jakob @@ -8,7 +8,7 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" +#include "pybind11_tests.h" class Child { public: diff --git a/tests/test_keep_alive.py b/tests/test_keep_alive.py new file mode 100644 index 000000000..c83d5d28b --- /dev/null +++ b/tests/test_keep_alive.py @@ -0,0 +1,98 @@ +import gc + + +def test_keep_alive_argument(capture): + from pybind11_tests import Parent, Child + + with capture: + p = Parent() + assert capture == "Allocating parent." + with capture: + p.addChild(Child()) + gc.collect() + assert capture == """ + Allocating child. + Releasing child. + """ + with capture: + del p + gc.collect() + assert capture == "Releasing parent." + + with capture: + p = Parent() + assert capture == "Allocating parent." + with capture: + p.addChildKeepAlive(Child()) + gc.collect() + assert capture == "Allocating child." + with capture: + del p + gc.collect() + assert capture == """ + Releasing parent. + Releasing child. + """ + + +def test_keep_alive_return_value(capture): + from pybind11_tests import Parent + + with capture: + p = Parent() + assert capture == "Allocating parent." + with capture: + p.returnChild() + gc.collect() + assert capture == """ + Allocating child. + Releasing child. + """ + with capture: + del p + gc.collect() + assert capture == "Releasing parent." + + with capture: + p = Parent() + assert capture == "Allocating parent." + with capture: + p.returnChildKeepAlive() + gc.collect() + assert capture == "Allocating child." + with capture: + del p + gc.collect() + assert capture == """ + Releasing parent. + Releasing child. + """ + + +def test_return_none(capture): + from pybind11_tests import Parent + + with capture: + p = Parent() + assert capture == "Allocating parent." + with capture: + p.returnNullChildKeepAliveChild() + gc.collect() + assert capture == "" + with capture: + del p + gc.collect() + assert capture == "Releasing parent." + + with capture: + p = Parent() + assert capture == "Allocating parent." + with capture: + p.returnNullChildKeepAliveParent() + gc.collect() + assert capture == "" + with capture: + del p + gc.collect() + assert capture == "Releasing parent." + diff --git a/example/example-arg-keywords-and-defaults.cpp b/tests/test_kwargs_and_defaults.cpp similarity index 94% rename from example/example-arg-keywords-and-defaults.cpp rename to tests/test_kwargs_and_defaults.cpp index 9c58605fc..281624615 100644 --- a/example/example-arg-keywords-and-defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -1,5 +1,5 @@ /* - example/example-arg-keywords-and-defaults.cpp -- keyword arguments and default values + tests/test_kwargs_and_defaults.cpp -- keyword arguments and default values Copyright (c) 2016 Wenzel Jakob @@ -7,7 +7,7 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" +#include "pybind11_tests.h" #include void kw_func(int x, int y) { std::cout << "kw_func(x=" << x << ", y=" << y << ")" << std::endl; } diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py new file mode 100644 index 000000000..0d785a426 --- /dev/null +++ b/tests/test_kwargs_and_defaults.py @@ -0,0 +1,93 @@ +import pytest +from pybind11_tests import (kw_func0, kw_func1, kw_func2, kw_func3, kw_func4, call_kw_func, + args_function, args_kwargs_function, kw_func_udl, kw_func_udl_z, + KWClass) + + +def test_function_signatures(doc): + assert doc(kw_func0) == "kw_func0(arg0: int, arg1: int) -> None" + assert doc(kw_func1) == "kw_func1(x: int, y: int) -> None" + assert doc(kw_func2) == "kw_func2(x: int=100, y: int=200) -> None" + assert doc(kw_func3) == "kw_func3(data: str='Hello world!') -> None" + assert doc(kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> None" + assert doc(kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> None" + assert doc(kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> None" + assert doc(args_function) == "args_function(*args) -> None" + assert doc(args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> None" + assert doc(KWClass.foo0) == "foo0(self: m.KWClass, arg0: int, arg1: float) -> None" + assert doc(KWClass.foo1) == "foo1(self: m.KWClass, x: int, y: float) -> None" + + +def test_named_arguments(capture, msg): + with capture: + kw_func1(5, 10) + assert capture == "kw_func(x=5, y=10)" + with capture: + kw_func1(5, y=10) + assert capture == "kw_func(x=5, y=10)" + with capture: + kw_func1(y=10, x=5) + assert capture == "kw_func(x=5, y=10)" + + with capture: + kw_func2() + assert capture == "kw_func(x=100, y=200)" + with capture: + kw_func2(5) + assert capture == "kw_func(x=5, y=200)" + with capture: + kw_func2(x=5) + assert capture == "kw_func(x=5, y=200)" + with capture: + kw_func2(y=10) + assert capture == "kw_func(x=100, y=10)" + with capture: + kw_func2(5, 10) + assert capture == "kw_func(x=5, y=10)" + with capture: + kw_func2(x=5, y=10) + assert capture == "kw_func(x=5, y=10)" + + with pytest.raises(TypeError) as excinfo: + # noinspection PyArgumentList + kw_func2(x=5, y=10, z=12) + assert msg(excinfo.value) == """ + Incompatible function arguments. The following argument types are supported: + 1. (x: int=100, y: int=200) -> None + Invoked with: + """ + + with capture: + kw_func4() + assert capture == "kw_func4: 13 17" + with capture: + kw_func4(myList=[1, 2, 3]) + assert capture == "kw_func4: 1 2 3" + + with capture: + kw_func_udl(x=5, y=10) + assert capture == "kw_func(x=5, y=10)" + with capture: + kw_func_udl_z(x=5) + assert capture == "kw_func(x=5, y=0)" + + +def test_arg_and_kwargs(capture): + with capture: + call_kw_func(kw_func2) + assert capture == "kw_func(x=1234, y=5678)" + with capture: + args_function('arg1_value', 'arg2_value', 3) + assert capture.unordered == """ + got argument: arg1_value + got argument: arg2_value + got argument: 3 + """ + with capture: + args_kwargs_function('arg1_value', 'arg2_value', arg3='arg3_value', arg4=4) + assert capture.unordered == """ + got argument: arg1_value + got argument: arg2_value + got keyword argument: arg3 -> arg3_value + got keyword argument: arg4 -> 4 + """ diff --git a/example/example-methods-and-attributes.cpp b/tests/test_methods_and_attributes.cpp similarity index 96% rename from example/example-methods-and-attributes.cpp rename to tests/test_methods_and_attributes.cpp index 9056e3cb4..9317d780d 100644 --- a/example/example-methods-and-attributes.cpp +++ b/tests/test_methods_and_attributes.cpp @@ -1,5 +1,5 @@ /* - example/example-methods-and-attributes.cpp -- constructors, deconstructors, attribute access, + tests/test_methods_and_attributes.cpp -- constructors, deconstructors, attribute access, __str__, argument and return value conventions Copyright (c) 2016 Wenzel Jakob @@ -8,8 +8,8 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" -#include "constructor-stats.h" +#include "pybind11_tests.h" +#include "constructor_stats.h" class ExampleMandA { public: diff --git a/tests/test_methods_and_attributes.py b/tests/test_methods_and_attributes.py new file mode 100644 index 000000000..9340e6fb9 --- /dev/null +++ b/tests/test_methods_and_attributes.py @@ -0,0 +1,46 @@ +from pybind11_tests import ExampleMandA, ConstructorStats + + +def test_methods_and_attributes(): + instance1 = ExampleMandA() + instance2 = ExampleMandA(32) + + instance1.add1(instance2) + instance1.add2(instance2) + instance1.add3(instance2) + instance1.add4(instance2) + instance1.add5(instance2) + instance1.add6(32) + instance1.add7(32) + instance1.add8(32) + instance1.add9(32) + instance1.add10(32) + + assert str(instance1) == "ExampleMandA[value=320]" + assert str(instance2) == "ExampleMandA[value=32]" + assert str(instance1.self1()) == "ExampleMandA[value=320]" + assert str(instance1.self2()) == "ExampleMandA[value=320]" + assert str(instance1.self3()) == "ExampleMandA[value=320]" + assert str(instance1.self4()) == "ExampleMandA[value=320]" + assert str(instance1.self5()) == "ExampleMandA[value=320]" + + assert instance1.internal1() == 320 + assert instance1.internal2() == 320 + assert instance1.internal3() == 320 + assert instance1.internal4() == 320 + assert instance1.internal5() == 320 + + assert instance1.value == 320 + instance1.value = 100 + assert str(instance1) == "ExampleMandA[value=100]" + + cstats = ConstructorStats.get(ExampleMandA) + assert cstats.alive() == 2 + del instance1, instance2 + assert cstats.alive() == 0 + assert cstats.values() == ["32"] + assert cstats.default_constructions == 1 + assert cstats.copy_constructions == 3 + assert cstats.move_constructions >= 1 + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 diff --git a/example/example-modules.cpp b/tests/test_modules.cpp similarity index 93% rename from example/example-modules.cpp rename to tests/test_modules.cpp index bd25af17f..3d96df616 100644 --- a/example/example-modules.cpp +++ b/tests/test_modules.cpp @@ -1,5 +1,5 @@ /* - example/example-modules.cpp -- nested modules, importing modules, and + tests/test_modules.cpp -- nested modules, importing modules, and internal references Copyright (c) 2016 Wenzel Jakob @@ -8,8 +8,8 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" -#include "constructor-stats.h" +#include "pybind11_tests.h" +#include "constructor_stats.h" void submodule_func() { std::cout << "submodule_func()" << std::endl; diff --git a/tests/test_modules.py b/tests/test_modules.py new file mode 100644 index 000000000..3deb02e3b --- /dev/null +++ b/tests/test_modules.py @@ -0,0 +1,56 @@ + +def test_nested_modules(capture): + import pybind11_tests + from pybind11_tests.submodule import submodule_func + + assert pybind11_tests.__name__ == "pybind11_tests" + assert pybind11_tests.submodule.__name__ == "pybind11_tests.submodule" + + with capture: + submodule_func() + assert capture == "submodule_func()" + + +def test_reference_internal(): + from pybind11_tests import ConstructorStats + from pybind11_tests.submodule import A, B + + b = B() + assert str(b.get_a1()) == "A[1]" + assert str(b.a1) == "A[1]" + assert str(b.get_a2()) == "A[2]" + assert str(b.a2) == "A[2]" + + b.a1 = A(42) + b.a2 = A(43) + assert str(b.get_a1()) == "A[42]" + assert str(b.a1) == "A[42]" + assert str(b.get_a2()) == "A[43]" + assert str(b.a2) == "A[43]" + + astats, bstats = ConstructorStats.get(A), ConstructorStats.get(B) + assert astats.alive() == 2 + assert bstats.alive() == 1 + del b + assert astats.alive() == 0 + assert bstats.alive() == 0 + assert astats.values() == ['1', '2', '42', '43'] + assert bstats.values() == [] + assert astats.default_constructions == 0 + assert bstats.default_constructions == 1 + assert astats.copy_constructions == 0 + assert bstats.copy_constructions == 0 + # assert astats.move_constructions >= 0 # Don't invoke any + # assert bstats.move_constructions >= 0 # Don't invoke any + assert astats.copy_assignments == 2 + assert bstats.copy_assignments == 0 + assert astats.move_assignments == 0 + assert bstats.move_assignments == 0 + + +def test_importing(): + from pybind11_tests import OD + from collections import OrderedDict + + assert OD is OrderedDict + assert str(OD([(1, 'a'), (2, 'b')])) == "OrderedDict([(1, 'a'), (2, 'b')])" diff --git a/example/example-numpy-dtypes.cpp b/tests/test_numpy_dtypes.cpp similarity index 98% rename from example/example-numpy-dtypes.cpp rename to tests/test_numpy_dtypes.cpp index e5292bba0..9afd342b2 100644 --- a/example/example-numpy-dtypes.cpp +++ b/tests/test_numpy_dtypes.cpp @@ -1,5 +1,5 @@ /* - example/example-numpy-dtypes.cpp -- Structured and compound NumPy dtypes + tests/test_numpy_dtypes.cpp -- Structured and compound NumPy dtypes Copyright (c) 2016 Ivan Smirnov @@ -7,11 +7,9 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" +#include "pybind11_tests.h" #include -#include -#include #ifdef __GNUC__ #define PYBIND11_PACKED(cls) cls __attribute__((__packed__)) diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py new file mode 100644 index 000000000..783f6ad25 --- /dev/null +++ b/tests/test_numpy_dtypes.py @@ -0,0 +1,169 @@ +import pytest +with pytest.suppress(ImportError): + import numpy as np + + +def assert_equal(actual, expected_data, expected_dtype): + np.testing.assert_equal(actual, np.array(expected_data, dtype=expected_dtype)) + +simple_dtype = np.dtype({'names': ['x', 'y', 'z'], + 'formats': ['?', 'u4', 'f4'], + 'offsets': [0, 4, 8]}) +packed_dtype = np.dtype([('x', '?'), ('y', 'u4'), ('z', 'f4')]) + + +@pytest.requires_numpy +def test_format_descriptors(capture): + from pybind11_tests import get_format_unbound, print_format_descriptors + + with pytest.raises(RuntimeError) as excinfo: + get_format_unbound() + assert 'unsupported buffer format' in str(excinfo.value) + + with capture: + print_format_descriptors() + assert capture == """ + T{=?:x:3x=I:y:=f:z:} + T{=?:x:=I:y:=f:z:} + T{=T{=?:x:3x=I:y:=f:z:}:a:=T{=?:x:=I:y:=f:z:}:b:} + T{=?:x:3x=I:y:=f:z:12x} + T{8x=T{=?:x:3x=I:y:=f:z:12x}:a:8x} + T{=3s:a:=3s:b:} + """ + + +@pytest.requires_numpy +def test_dtype(capture): + from pybind11_tests import print_dtypes, test_dtype_ctors, test_dtype_methods + + with capture: + print_dtypes() + assert capture == """ + {'names':['x','y','z'], 'formats':['?',' simple_dtype.itemsize + assert_equal(arr, elements, simple_dtype) + assert_equal(arr, elements, packed_dtype) + + arr = create_rec_partial_nested(3) + assert str(arr.dtype) == "{'names':['a'], 'formats':[{'names':['x','y','z'], 'formats':['?',' partial_dtype.itemsize + np.testing.assert_equal(arr['a'], create_rec_partial(3)) + + +@pytest.requires_numpy +def test_array_constructors(): + from pybind11_tests import test_array_ctors + + data = np.arange(1, 7, dtype='int32') + for i in range(8): + np.testing.assert_array_equal(test_array_ctors(10 + i), data.reshape((3, 2))) + np.testing.assert_array_equal(test_array_ctors(20 + i), data.reshape((3, 2))) + for i in range(5): + np.testing.assert_array_equal(test_array_ctors(30 + i), data) + np.testing.assert_array_equal(test_array_ctors(40 + i), data) + + +@pytest.requires_numpy +def test_string_array(capture): + from pybind11_tests import create_string_array, print_string_array + + arr = create_string_array(True) + assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]" + with capture: + print_string_array(arr) + assert capture == """ + a='',b='' + a='a',b='a' + a='ab',b='ab' + a='abc',b='abc' + """ + dtype = arr.dtype + assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc'] + assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc'] + arr = create_string_array(False) + assert dtype == arr.dtype + + +@pytest.requires_numpy +def test_signature(doc): + from pybind11_tests import create_rec_nested + + assert doc(create_rec_nested) == "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]" diff --git a/example/example-numpy-vectorize.cpp b/tests/test_numpy_vectorize.cpp similarity index 85% rename from example/example-numpy-vectorize.cpp rename to tests/test_numpy_vectorize.cpp index 8780d28ff..a36b7d013 100644 --- a/example/example-numpy-vectorize.cpp +++ b/tests/test_numpy_vectorize.cpp @@ -1,5 +1,5 @@ /* - example/example-numpy-vectorize.cpp -- auto-vectorize functions over NumPy array + tests/test_numpy_vectorize.cpp -- auto-vectorize functions over NumPy array arguments Copyright (c) 2016 Wenzel Jakob @@ -8,7 +8,7 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" +#include "pybind11_tests.h" #include double my_func(int x, float y, double z) { @@ -35,7 +35,7 @@ void init_ex_numpy_vectorize(py::module &m) { m.def("vectorized_func3", py::vectorize(my_func3)); /// Numpy function which only accepts specific data types - m.def("selective_func", [](py::array_t) { std::cout << "Int branch taken. "<< std::endl; }); - m.def("selective_func", [](py::array_t) { std::cout << "Float branch taken. "<< std::endl; }); - m.def("selective_func", [](py::array_t, py::array::c_style>) { std::cout << "Complex float branch taken. "<< std::endl; }); + m.def("selective_func", [](py::array_t) { std::cout << "Int branch taken." << std::endl; }); + m.def("selective_func", [](py::array_t) { std::cout << "Float branch taken." << std::endl; }); + m.def("selective_func", [](py::array_t, py::array::c_style>) { std::cout << "Complex float branch taken." << std::endl; }); } diff --git a/tests/test_numpy_vectorize.py b/tests/test_numpy_vectorize.py new file mode 100644 index 000000000..6fcf80814 --- /dev/null +++ b/tests/test_numpy_vectorize.py @@ -0,0 +1,80 @@ +import pytest + +with pytest.suppress(ImportError): + import numpy as np + + +@pytest.requires_numpy +def test_vectorize(capture): + from pybind11_tests import vectorized_func, vectorized_func2, vectorized_func3 + + assert np.isclose(vectorized_func3(np.array(3 + 7j)), [6 + 14j]) + + for f in [vectorized_func, vectorized_func2]: + with capture: + assert np.isclose(f(1, 2, 3), 6) + assert capture == "my_func(x:int=1, y:float=2, z:float=3)" + with capture: + assert np.isclose(f(np.array(1), np.array(2), 3), 6) + assert capture == "my_func(x:int=1, y:float=2, z:float=3)" + with capture: + assert np.allclose(f(np.array([1, 3]), np.array([2, 4]), 3), [6, 36]) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=3) + my_func(x:int=3, y:float=4, z:float=3) + """ + with capture: + a, b, c = np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3 + assert np.allclose(f(a, b, c), a * b * c) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=3) + my_func(x:int=3, y:float=4, z:float=3) + my_func(x:int=5, y:float=6, z:float=3) + my_func(x:int=7, y:float=8, z:float=3) + my_func(x:int=9, y:float=10, z:float=3) + my_func(x:int=11, y:float=12, z:float=3) + """ + with capture: + a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2 + assert np.allclose(f(a, b, c), a * b * c) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=2) + my_func(x:int=2, y:float=3, z:float=2) + my_func(x:int=3, y:float=4, z:float=2) + my_func(x:int=4, y:float=2, z:float=2) + my_func(x:int=5, y:float=3, z:float=2) + my_func(x:int=6, y:float=4, z:float=2) + """ + with capture: + a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2 + assert np.allclose(f(a, b, c), a * b * c) + assert capture == """ + my_func(x:int=1, y:float=2, z:float=2) + my_func(x:int=2, y:float=2, z:float=2) + my_func(x:int=3, y:float=2, z:float=2) + my_func(x:int=4, y:float=3, z:float=2) + my_func(x:int=5, y:float=3, z:float=2) + my_func(x:int=6, y:float=3, z:float=2) + """ + + +@pytest.requires_numpy +def test_type_selection(capture): + from pybind11_tests import selective_func + + with capture: + selective_func(np.array([1], dtype=np.int32)) + selective_func(np.array([1.0], dtype=np.float32)) + selective_func(np.array([1.0j], dtype=np.complex64)) + assert capture == """ + Int branch taken. + Float branch taken. + Complex float branch taken. + """ + + +@pytest.requires_numpy +def test_docs(doc): + from pybind11_tests import vectorized_func + + assert doc(vectorized_func) == "vectorized_func(arg0: numpy.ndarray[int], arg1: numpy.ndarray[float], arg2: numpy.ndarray[float]) -> object" diff --git a/example/example-opaque-types.cpp b/tests/test_opaque_types.cpp similarity index 89% rename from example/example-opaque-types.cpp rename to tests/test_opaque_types.cpp index 2c24f3546..0ede5e328 100644 --- a/example/example-opaque-types.cpp +++ b/tests/test_opaque_types.cpp @@ -1,5 +1,5 @@ /* - example/example-opaque-types.cpp -- opaque types, passing void pointers + tests/test_opaque_types.cpp -- opaque types, passing void pointers Copyright (c) 2016 Wenzel Jakob @@ -7,7 +7,7 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" +#include "pybind11_tests.h" #include #include @@ -50,9 +50,9 @@ void init_ex_opaque_types(py::module &m) { }); m.def("return_void_ptr", []() { return (void *) 0x1234; }); - m.def("print_void_ptr", [](void *ptr) { std::cout << "Got void ptr : 0x" << std::hex << (uint64_t) ptr << std::endl; }); + m.def("print_void_ptr", [](void *ptr) { std::cout << "Got void ptr : 0x" << std::hex << (uint64_t) ptr << std::dec << std::endl; }); m.def("return_null_str", []() { return (char *) nullptr; }); - m.def("print_null_str", [](char *ptr) { std::cout << "Got null str : 0x" << std::hex << (uint64_t) ptr << std::endl; }); + m.def("print_null_str", [](char *ptr) { std::cout << "Got null str : 0x" << std::hex << (uint64_t) ptr << std::dec << std::endl; }); m.def("return_unique_ptr", []() -> std::unique_ptr { StringList *result = new StringList(); diff --git a/tests/test_opaque_types.py b/tests/test_opaque_types.py new file mode 100644 index 000000000..5c2ca9248 --- /dev/null +++ b/tests/test_opaque_types.py @@ -0,0 +1,64 @@ +import pytest + + +def test_string_list(capture): + from pybind11_tests import StringList, ClassWithSTLVecProperty, print_opaque_list + + l = StringList() + l.push_back("Element 1") + l.push_back("Element 2") + with capture: + print_opaque_list(l) + assert capture == "Opaque list: [Element 1, Element 2]" + assert l.back() == "Element 2" + + for i, k in enumerate(l, start=1): + assert k == "Element {}".format(i) + l.pop_back() + with capture: + print_opaque_list(l) + assert capture == "Opaque list: [Element 1]" + + cvp = ClassWithSTLVecProperty() + with capture: + print_opaque_list(cvp.stringList) + assert capture == "Opaque list: []" + + cvp.stringList = l + cvp.stringList.push_back("Element 3") + with capture: + print_opaque_list(cvp.stringList) + assert capture == "Opaque list: [Element 1, Element 3]" + + +def test_pointers(capture, msg): + from pybind11_tests import (return_void_ptr, print_void_ptr, ExampleMandA, + print_opaque_list, return_null_str, print_null_str, + return_unique_ptr, ConstructorStats) + + with capture: + print_void_ptr(return_void_ptr()) + assert capture == "Got void ptr : 0x1234" + with capture: + print_void_ptr(ExampleMandA()) # Should also work for other C++ types + assert "Got void ptr" in capture + assert ConstructorStats.get(ExampleMandA).alive() == 0 + + with pytest.raises(TypeError) as excinfo: + print_void_ptr([1, 2, 3]) # This should not work + assert msg(excinfo.value) == """ + Incompatible function arguments. The following argument types are supported: + 1. (arg0: capsule) -> None + Invoked with: [1, 2, 3] + """ + + assert return_null_str() is None + with capture: + print_null_str(return_null_str()) + assert capture == "Got null str : 0x0" + + ptr = return_unique_ptr() + assert "StringList" in repr(ptr) + with capture: + print_opaque_list(ptr) + assert capture == "Opaque list: [some value]" diff --git a/example/example-operator-overloading.cpp b/tests/test_operator_overloading.cpp similarity index 95% rename from example/example-operator-overloading.cpp rename to tests/test_operator_overloading.cpp index f6b9967bc..b84a5b845 100644 --- a/example/example-operator-overloading.cpp +++ b/tests/test_operator_overloading.cpp @@ -1,5 +1,5 @@ /* - example/example-operator-overloading.cpp -- operator overloading + tests/test_operator_overloading.cpp -- operator overloading Copyright (c) 2016 Wenzel Jakob @@ -7,8 +7,8 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" -#include "constructor-stats.h" +#include "pybind11_tests.h" +#include "constructor_stats.h" #include class Vector2 { diff --git a/tests/test_operator_overloading.py b/tests/test_operator_overloading.py new file mode 100644 index 000000000..e0d42391e --- /dev/null +++ b/tests/test_operator_overloading.py @@ -0,0 +1,41 @@ + +def test_operator_overloading(): + from pybind11_tests import Vector2, Vector, ConstructorStats + + v1 = Vector2(1, 2) + v2 = Vector(3, -1) + assert str(v1) == "[1.000000, 2.000000]" + assert str(v2) == "[3.000000, -1.000000]" + + assert str(v1 + v2) == "[4.000000, 1.000000]" + assert str(v1 - v2) == "[-2.000000, 3.000000]" + assert str(v1 - 8) == "[-7.000000, -6.000000]" + assert str(v1 + 8) == "[9.000000, 10.000000]" + assert str(v1 * 8) == "[8.000000, 16.000000]" + assert str(v1 / 8) == "[0.125000, 0.250000]" + assert str(8 - v1) == "[7.000000, 6.000000]" + assert str(8 + v1) == "[9.000000, 10.000000]" + assert str(8 * v1) == "[8.000000, 16.000000]" + assert str(8 / v1) == "[8.000000, 4.000000]" + + v1 += v2 + v1 *= 2 + assert str(v1) == "[8.000000, 2.000000]" + + cstats = ConstructorStats.get(Vector2) + assert cstats.alive() == 2 + del v1 + assert cstats.alive() == 1 + del v2 + assert cstats.alive() == 0 + assert cstats.values() == ['[1.000000, 2.000000]', '[3.000000, -1.000000]', + '[4.000000, 1.000000]', '[-2.000000, 3.000000]', + '[-7.000000, -6.000000]', '[9.000000, 10.000000]', + '[8.000000, 16.000000]', '[0.125000, 0.250000]', + '[7.000000, 6.000000]', '[9.000000, 10.000000]', + '[8.000000, 16.000000]', '[8.000000, 4.000000]'] + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + assert cstats.move_constructions >= 10 + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 diff --git a/example/example-pickling.cpp b/tests/test_pickling.cpp similarity index 95% rename from example/example-pickling.cpp rename to tests/test_pickling.cpp index b89f78a3e..4a4845256 100644 --- a/example/example-pickling.cpp +++ b/tests/test_pickling.cpp @@ -1,5 +1,5 @@ /* - example/example-pickling.cpp -- pickle support + tests/test_pickling.cpp -- pickle support Copyright (c) 2016 Wenzel Jakob @@ -7,7 +7,7 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" +#include "pybind11_tests.h" class Pickleable { public: diff --git a/tests/test_pickling.py b/tests/test_pickling.py new file mode 100644 index 000000000..f6e4c04fe --- /dev/null +++ b/tests/test_pickling.py @@ -0,0 +1,18 @@ +try: + import cPickle as pickle # Use cPickle on Python 2.7 +except ImportError: + import pickle + +from pybind11_tests import Pickleable + + +def test_roundtrip(): + p = Pickleable("test_value") + p.setExtra1(15) + p.setExtra2(48) + + data = pickle.dumps(p, 2) # Must use pickle protocol >= 2 + p2 = pickle.loads(data) + assert p2.value() == p.value() + assert p2.extra1() == p.extra1() + assert p2.extra2() == p.extra2() diff --git a/example/example-python-types.cpp b/tests/test_python_types.cpp similarity index 98% rename from example/example-python-types.cpp rename to tests/test_python_types.cpp index 55066a811..39e43eb63 100644 --- a/example/example-python-types.cpp +++ b/tests/test_python_types.cpp @@ -1,5 +1,5 @@ /* - example/example-python-types.cpp2 -- singleton design pattern, static functions and + tests/test_python_types.cpp -- singleton design pattern, static functions and variables, passing and interacting with Python types Copyright (c) 2016 Wenzel Jakob @@ -8,8 +8,8 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" -#include "constructor-stats.h" +#include "pybind11_tests.h" +#include "constructor_stats.h" #include #ifdef _WIN32 diff --git a/tests/test_python_types.py b/tests/test_python_types.py new file mode 100644 index 000000000..3738d41c8 --- /dev/null +++ b/tests/test_python_types.py @@ -0,0 +1,220 @@ +import pytest + +from pybind11_tests import ExamplePythonTypes, ConstructorStats + + +def test_static(): + ExamplePythonTypes.value = 15 + assert ExamplePythonTypes.value == 15 + assert ExamplePythonTypes.value2 == 5 + + with pytest.raises(AttributeError) as excinfo: + ExamplePythonTypes.value2 = 15 + assert str(excinfo.value) == "can't set attribute" + + +def test_instance(capture): + with pytest.raises(TypeError) as excinfo: + ExamplePythonTypes() + assert str(excinfo.value) == "pybind11_tests.ExamplePythonTypes: No constructor defined!" + + instance = ExamplePythonTypes.new_instance() + + with capture: + dict_result = instance.get_dict() + dict_result['key2'] = 'value2' + instance.print_dict(dict_result) + assert capture.unordered == """ + key: key, value=value + key: key2, value=value2 + """ + with capture: + dict_result = instance.get_dict_2() + dict_result['key2'] = 'value2' + instance.print_dict_2(dict_result) + assert capture.unordered == """ + key: key, value=value + key: key2, value=value2 + """ + with capture: + set_result = instance.get_set() + set_result.add('key3') + instance.print_set(set_result) + assert capture.unordered == """ + key: key1 + key: key2 + key: key3 + """ + with capture: + set_result = instance.get_set2() + set_result.add('key3') + instance.print_set_2(set_result) + assert capture.unordered == """ + key: key1 + key: key2 + key: key3 + """ + with capture: + list_result = instance.get_list() + list_result.append('value2') + instance.print_list(list_result) + assert capture.unordered == """ + Entry at positon 0: value + list item 0: overwritten + list item 1: value2 + """ + with capture: + list_result = instance.get_list_2() + list_result.append('value2') + instance.print_list_2(list_result) + assert capture.unordered == """ + list item 0: value + list item 1: value2 + """ + array_result = instance.get_array() + assert array_result == ['array entry 1', 'array entry 2'] + with capture: + instance.print_array(array_result) + assert capture.unordered == """ + array item 0: array entry 1 + array item 1: array entry 2 + """ + with pytest.raises(RuntimeError) as excinfo: + instance.throw_exception() + assert str(excinfo.value) == "This exception was intentionally thrown." + + assert instance.pair_passthrough((True, "test")) == ("test", True) + assert instance.tuple_passthrough((True, "test", 5)) == (5, "test", True) + + assert instance.get_bytes_from_string().decode() == "foo" + assert instance.get_bytes_from_str().decode() == "bar" + assert instance.get_str_from_string().encode().decode() == "baz" + assert instance.get_str_from_bytes().encode().decode() == "boo" + + class A(object): + def __str__(self): + return "this is a str" + + def __repr__(self): + return "this is a repr" + + with capture: + instance.test_print(A()) + assert capture == """ + this is a str + this is a repr + """ + + cstats = ConstructorStats.get(ExamplePythonTypes) + assert cstats.alive() == 1 + del instance + assert cstats.alive() == 0 + + +def test_docs(doc): + assert doc(ExamplePythonTypes) == "Example 2 documentation" + assert doc(ExamplePythonTypes.get_dict) == """ + get_dict(self: m.ExamplePythonTypes) -> dict + + Return a Python dictionary + """ + assert doc(ExamplePythonTypes.get_dict_2) == """ + get_dict_2(self: m.ExamplePythonTypes) -> Dict[str, str] + + Return a C++ dictionary + """ + assert doc(ExamplePythonTypes.get_list) == """ + get_list(self: m.ExamplePythonTypes) -> list + + Return a Python list + """ + assert doc(ExamplePythonTypes.get_list_2) == """ + get_list_2(self: m.ExamplePythonTypes) -> List[str] + + Return a C++ list + """ + assert doc(ExamplePythonTypes.get_dict) == """ + get_dict(self: m.ExamplePythonTypes) -> dict + + Return a Python dictionary + """ + assert doc(ExamplePythonTypes.get_set) == """ + get_set(self: m.ExamplePythonTypes) -> set + + Return a Python set + """ + assert doc(ExamplePythonTypes.get_set2) == """ + get_set2(self: m.ExamplePythonTypes) -> Set[str] + + Return a C++ set + """ + assert doc(ExamplePythonTypes.get_array) == """ + get_array(self: m.ExamplePythonTypes) -> List[str[2]] + + Return a C++ array + """ + assert doc(ExamplePythonTypes.print_dict) == """ + print_dict(self: m.ExamplePythonTypes, arg0: dict) -> None + + Print entries of a Python dictionary + """ + assert doc(ExamplePythonTypes.print_dict_2) == """ + print_dict_2(self: m.ExamplePythonTypes, arg0: Dict[str, str]) -> None + + Print entries of a C++ dictionary + """ + assert doc(ExamplePythonTypes.print_set) == """ + print_set(self: m.ExamplePythonTypes, arg0: set) -> None + + Print entries of a Python set + """ + assert doc(ExamplePythonTypes.print_set_2) == """ + print_set_2(self: m.ExamplePythonTypes, arg0: Set[str]) -> None + + Print entries of a C++ set + """ + assert doc(ExamplePythonTypes.print_list) == """ + print_list(self: m.ExamplePythonTypes, arg0: list) -> None + + Print entries of a Python list + """ + assert doc(ExamplePythonTypes.print_list_2) == """ + print_list_2(self: m.ExamplePythonTypes, arg0: List[str]) -> None + + Print entries of a C++ list + """ + assert doc(ExamplePythonTypes.print_array) == """ + print_array(self: m.ExamplePythonTypes, arg0: List[str[2]]) -> None + + Print entries of a C++ array + """ + assert doc(ExamplePythonTypes.pair_passthrough) == """ + pair_passthrough(self: m.ExamplePythonTypes, arg0: Tuple[bool, str]) -> Tuple[str, bool] + + Return a pair in reversed order + """ + assert doc(ExamplePythonTypes.tuple_passthrough) == """ + tuple_passthrough(self: m.ExamplePythonTypes, arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool] + + Return a triple in reversed order + """ + assert doc(ExamplePythonTypes.throw_exception) == """ + throw_exception(self: m.ExamplePythonTypes) -> None + + Throw an exception + """ + assert doc(ExamplePythonTypes.new_instance) == """ + new_instance() -> m.ExamplePythonTypes + + Return an instance + """ + + +def test_module(): + import pybind11_tests + + assert pybind11_tests.__name__ == "pybind11_tests" + assert ExamplePythonTypes.__name__ == "ExamplePythonTypes" + assert ExamplePythonTypes.__module__ == "pybind11_tests" + assert ExamplePythonTypes.get_set.__name__ == "get_set" + assert ExamplePythonTypes.get_set.__module__ == "pybind11_tests" diff --git a/example/example-sequences-and-iterators.cpp b/tests/test_sequences_and_iterators.cpp similarity index 97% rename from example/example-sequences-and-iterators.cpp rename to tests/test_sequences_and_iterators.cpp index 791a92926..a92c6bf62 100644 --- a/example/example-sequences-and-iterators.cpp +++ b/tests/test_sequences_and_iterators.cpp @@ -1,5 +1,5 @@ /* - example/example-sequences-and-iterators.cpp -- supporting Pythons' sequence protocol, iterators, + tests/test_sequences_and_iterators.cpp -- supporting Pythons' sequence protocol, iterators, etc. Copyright (c) 2016 Wenzel Jakob @@ -8,8 +8,8 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" -#include "constructor-stats.h" +#include "pybind11_tests.h" +#include "constructor_stats.h" #include #include diff --git a/tests/test_sequences_and_iterators.py b/tests/test_sequences_and_iterators.py new file mode 100644 index 000000000..a35dc584b --- /dev/null +++ b/tests/test_sequences_and_iterators.py @@ -0,0 +1,78 @@ +import pytest + + +def isclose(a, b, rel_tol=1e-05, abs_tol=0.0): + """Like to 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_sequence(): + from pybind11_tests import Sequence, ConstructorStats + + cstats = ConstructorStats.get(Sequence) + + s = Sequence(5) + assert cstats.values() == ['of size', '5'] + + assert "Sequence" in repr(s) + assert len(s) == 5 + assert s[0] == 0 and s[3] == 0 + assert 12.34 not in s + s[0], s[3] = 12.34, 56.78 + assert 12.34 in s + assert isclose(s[0], 12.34) and isclose(s[3], 56.78) + + rev = reversed(s) + assert cstats.values() == ['of size', '5'] + + rev2 = s[::-1] + assert cstats.values() == ['of size', '5'] + + expected = [0, 56.78, 0, 0, 12.34] + assert allclose(rev, expected) + assert allclose(rev2, expected) + assert rev == rev2 + + rev[0::2] = Sequence([2.0, 2.0, 2.0]) + assert cstats.values() == ['of size', '3', 'from std::vector'] + + assert allclose(rev, [2, 56.78, 2, 0, 2]) + + assert cstats.alive() == 3 + del s + assert cstats.alive() == 2 + del rev + assert cstats.alive() == 1 + del rev2 + assert cstats.alive() == 0 + + assert cstats.values() == [] + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + assert cstats.move_constructions >= 1 + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + +def test_map_iterator(): + from pybind11_tests import StringMap + + m = StringMap({'hi': 'bye', 'black': 'white'}) + assert m['hi'] == 'bye' + assert len(m) == 2 + assert m['black'] == 'white' + + with pytest.raises(KeyError): + assert m['orange'] + m['orange'] = 'banana' + assert m['orange'] == 'banana' + + expected = {'hi': 'bye', 'black': 'white', 'orange': 'banana'} + for k in m: + assert m[k] == expected[k] + for k, v in m.items(): + assert v == expected[k] diff --git a/example/example-smart-ptr.cpp b/tests/test_smart_ptr.cpp similarity index 98% rename from example/example-smart-ptr.cpp rename to tests/test_smart_ptr.cpp index c4dd2c8d8..46c83b374 100644 --- a/example/example-smart-ptr.cpp +++ b/tests/test_smart_ptr.cpp @@ -1,5 +1,5 @@ /* - example/example-smart-ptr.cpp -- binding classes with custom reference counting, + tests/test_smart_ptr.cpp -- binding classes with custom reference counting, implicit conversions between types Copyright (c) 2016 Wenzel Jakob @@ -8,7 +8,7 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" +#include "pybind11_tests.h" #include "object.h" /// Custom object with builtin reference counting (see 'object.h' for the implementation) diff --git a/tests/test_smart_ptr.py b/tests/test_smart_ptr.py new file mode 100644 index 000000000..ffc407db5 --- /dev/null +++ b/tests/test_smart_ptr.py @@ -0,0 +1,115 @@ +from pybind11_tests import ConstructorStats + + +def test_smart_ptr(capture): + # Object1 + from pybind11_tests import (MyObject1, make_object_1, make_object_2, + print_object_1, print_object_2, print_object_3, print_object_4) + + for i, o in enumerate([make_object_1(), make_object_2(), MyObject1(3)], start=1): + assert o.getRefCount() == 1 + with capture: + print_object_1(o) + print_object_2(o) + print_object_3(o) + print_object_4(o) + assert capture == "MyObject1[{i}]\n".format(i=i) * 4 + + from pybind11_tests import (make_myobject1_1, make_myobject1_2, + print_myobject1_1, print_myobject1_2, + print_myobject1_3, print_myobject1_4) + + for i, o in enumerate([make_myobject1_1(), make_myobject1_2(), MyObject1(6), 7], start=4): + print(o) + with capture: + if not isinstance(o, int): + print_object_1(o) + print_object_2(o) + print_object_3(o) + print_object_4(o) + print_myobject1_1(o) + print_myobject1_2(o) + print_myobject1_3(o) + print_myobject1_4(o) + assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8) + + cstats = ConstructorStats.get(MyObject1) + assert cstats.alive() == 0 + expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4 + assert cstats.values() == expected_values + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + # Object2 + from pybind11_tests import (MyObject2, make_myobject2_1, make_myobject2_2, + make_myobject3_1, make_myobject3_2, + print_myobject2_1, print_myobject2_2, + print_myobject2_3, print_myobject2_4) + + for i, o in zip([8, 6, 7], [MyObject2(8), make_myobject2_1(), make_myobject2_2()]): + print(o) + with capture: + print_myobject2_1(o) + print_myobject2_2(o) + print_myobject2_3(o) + print_myobject2_4(o) + assert capture == "MyObject2[{i}]\n".format(i=i) * 4 + + cstats = ConstructorStats.get(MyObject2) + assert cstats.alive() == 1 + o = None + assert cstats.alive() == 0 + assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]'] + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + # Object3 + from pybind11_tests import (MyObject3, print_myobject3_1, print_myobject3_2, + print_myobject3_3, print_myobject3_4) + + for i, o in zip([9, 8, 9], [MyObject3(9), make_myobject3_1(), make_myobject3_2()]): + print(o) + with capture: + print_myobject3_1(o) + print_myobject3_2(o) + print_myobject3_3(o) + print_myobject3_4(o) + assert capture == "MyObject3[{i}]\n".format(i=i) * 4 + + cstats = ConstructorStats.get(MyObject3) + assert cstats.alive() == 1 + o = None + assert cstats.alive() == 0 + assert cstats.values() == ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]'] + assert cstats.default_constructions == 0 + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + # Object and ref + from pybind11_tests import Object, cstats_ref + + cstats = ConstructorStats.get(Object) + assert cstats.alive() == 0 + assert cstats.values() == [] + assert cstats.default_constructions == 10 + assert cstats.copy_constructions == 0 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 0 + assert cstats.move_assignments == 0 + + cstats = cstats_ref() + assert cstats.alive() == 0 + assert cstats.values() == ['from pointer'] * 10 + assert cstats.default_constructions == 30 + assert cstats.copy_constructions == 12 + # assert cstats.move_constructions >= 0 # Doesn't invoke any + assert cstats.copy_assignments == 30 + assert cstats.move_assignments == 0 diff --git a/example/example-stl-binder-vector.cpp b/tests/test_stl_binders.cpp similarity index 87% rename from example/example-stl-binder-vector.cpp rename to tests/test_stl_binders.cpp index d02ed09f7..e2a44e19e 100644 --- a/example/example-stl-binder-vector.cpp +++ b/tests/test_stl_binders.cpp @@ -1,5 +1,5 @@ /* - example/example-stl-binder-vector.cpp -- Usage of stl_binders functions + tests/test_stl_binders.cpp -- Usage of stl_binders functions Copyright (c) 2016 Sergey Lyskov @@ -7,7 +7,7 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" +#include "pybind11_tests.h" #include diff --git a/tests/test_stl_binders.py b/tests/test_stl_binders.py new file mode 100644 index 000000000..2aaaf3aa2 --- /dev/null +++ b/tests/test_stl_binders.py @@ -0,0 +1,53 @@ + + +def test_vector_int(): + from pybind11_tests import VectorInt + + v_int = VectorInt([0, 0]) + assert len(v_int) == 2 + assert bool(v_int) is True + + v_int2 = VectorInt([0, 0]) + assert v_int == v_int2 + v_int2[1] = 1 + assert v_int != v_int2 + + v_int2.append(2) + v_int2.append(3) + v_int2.insert(0, 1) + v_int2.insert(0, 2) + v_int2.insert(0, 3) + assert str(v_int2) == "VectorInt[3, 2, 1, 0, 1, 2, 3]" + + v_int.append(99) + v_int2[2:-2] = v_int + assert v_int2 == VectorInt([3, 2, 0, 0, 99, 2, 3]) + del v_int2[1:3] + assert v_int2 == VectorInt([3, 0, 99, 2, 3]) + del v_int2[0] + assert v_int2 == VectorInt([0, 99, 2, 3]) + + +def test_vector_custom(): + from pybind11_tests import El, VectorEl, VectorVectorEl + + v_a = VectorEl() + v_a.append(El(1)) + v_a.append(El(2)) + assert str(v_a) == "VectorEl[El{1}, El{2}]" + + vv_a = VectorVectorEl() + vv_a.append(v_a) + vv_b = vv_a[0] + assert str(vv_b) == "VectorEl[El{1}, El{2}]" + + +def test_vector_bool(): + from pybind11_tests import VectorBool + + vv_c = VectorBool() + for i in range(10): + vv_c.append(i % 2 == 0) + for i in range(10): + assert vv_c[i] == (i % 2 == 0) + assert str(vv_c) == "VectorBool[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]" diff --git a/example/example-virtual-functions.cpp b/tests/test_virtual_functions.cpp similarity index 98% rename from example/example-virtual-functions.cpp rename to tests/test_virtual_functions.cpp index b24925f5a..6ea7c2cfd 100644 --- a/example/example-virtual-functions.cpp +++ b/tests/test_virtual_functions.cpp @@ -1,5 +1,5 @@ /* - example/example-virtual-functions.cpp -- overriding virtual functions from Python + tests/test_virtual_functions.cpp -- overriding virtual functions from Python Copyright (c) 2016 Wenzel Jakob @@ -7,8 +7,8 @@ BSD-style license that can be found in the LICENSE file. */ -#include "example.h" -#include "constructor-stats.h" +#include "pybind11_tests.h" +#include "constructor_stats.h" #include /* This is an example class that we'll want to be able to extend from Python */ diff --git a/tests/test_virtual_functions.py b/tests/test_virtual_functions.py new file mode 100644 index 000000000..f2efb6bed --- /dev/null +++ b/tests/test_virtual_functions.py @@ -0,0 +1,227 @@ +import pytest +from pybind11_tests import ConstructorStats + + +def test_override(capture, msg): + from pybind11_tests import (ExampleVirt, runExampleVirt, runExampleVirtVirtual, + runExampleVirtBool) + + class ExtendedExampleVirt(ExampleVirt): + def __init__(self, state): + super(ExtendedExampleVirt, self).__init__(state + 1) + self.data = "Hello world" + + def run(self, value): + print('ExtendedExampleVirt::run(%i), calling parent..' % value) + return super(ExtendedExampleVirt, self).run(value + 1) + + def run_bool(self): + print('ExtendedExampleVirt::run_bool()') + return False + + def pure_virtual(self): + print('ExtendedExampleVirt::pure_virtual(): %s' % self.data) + + ex12 = ExampleVirt(10) + with capture: + assert runExampleVirt(ex12, 20) == 30 + assert capture == "Original implementation of ExampleVirt::run(state=10, value=20)" + + with pytest.raises(RuntimeError) as excinfo: + runExampleVirtVirtual(ex12) + assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"' + + ex12p = ExtendedExampleVirt(10) + with capture: + assert runExampleVirt(ex12p, 20) == 32 + assert capture == """ + ExtendedExampleVirt::run(20), calling parent.. + Original implementation of ExampleVirt::run(state=11, value=21) + """ + with capture: + assert runExampleVirtBool(ex12p) is False + assert capture == "ExtendedExampleVirt::run_bool()" + with capture: + runExampleVirtVirtual(ex12p) + assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world" + + cstats = ConstructorStats.get(ExampleVirt) + assert cstats.alive() == 2 + del ex12, ex12p + assert cstats.alive() == 0 + assert cstats.values() == ['10', '11'] + assert cstats.copy_constructions == 0 + assert cstats.move_constructions >= 0 + + +def test_inheriting_repeat(capture): + from pybind11_tests import A_Repeat, B_Repeat, C_Repeat, D_Repeat, A_Tpl, B_Tpl, C_Tpl, D_Tpl + + class VI_AR(A_Repeat): + def unlucky_number(self): + return 99 + + class VI_AT(A_Tpl): + def unlucky_number(self): + return 999 + + obj = VI_AR() + with capture: + obj.say_something(3) + assert capture == "hihihi" + assert obj.unlucky_number() == 99 + + obj = VI_AT() + with capture: + obj.say_something(3) + assert capture == "hihihi" + assert obj.unlucky_number() == 999 + + for obj in [B_Repeat(), B_Tpl()]: + with capture: + obj.say_something(3) + assert capture == "B says hi 3 times" + assert obj.unlucky_number() == 13 + assert obj.lucky_number() == 7.0 + + for obj in [C_Repeat(), C_Tpl()]: + with capture: + obj.say_something(3) + assert capture == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 888.0 + + class VI_CR(C_Repeat): + def lucky_number(self): + return C_Repeat.lucky_number(self) + 1.25 + + obj = VI_CR() + with capture: + obj.say_something(3) + assert capture == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 889.25 + + class VI_CT(C_Tpl): + pass + + obj = VI_CT() + with capture: + obj.say_something(3) + assert capture == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 888.0 + + class VI_CCR(VI_CR): + def lucky_number(self): + return VI_CR.lucky_number(self) * 10 + + obj = VI_CCR() + with capture: + obj.say_something(3) + assert capture == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 8892.5 + + class VI_CCT(VI_CT): + def lucky_number(self): + return VI_CT.lucky_number(self) * 1000 + + obj = VI_CCT() + with capture: + obj.say_something(3) + assert capture == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 888000.0 + + class VI_DR(D_Repeat): + def unlucky_number(self): + return 123 + + def lucky_number(self): + return 42.0 + + for obj in [D_Repeat(), D_Tpl()]: + with capture: + obj.say_something(3) + assert capture == "B says hi 3 times" + assert obj.unlucky_number() == 4444 + assert obj.lucky_number() == 888.0 + + obj = VI_DR() + with capture: + obj.say_something(3) + assert capture == "B says hi 3 times" + assert obj.unlucky_number() == 123 + assert obj.lucky_number() == 42.0 + + class VI_DT(D_Tpl): + def say_something(self, times): + print("VI_DT says:" + (' quack' * times)) + + def unlucky_number(self): + return 1234 + + def lucky_number(self): + return -4.25 + + obj = VI_DT() + with capture: + obj.say_something(3) + assert capture == "VI_DT says: quack quack quack" + assert obj.unlucky_number() == 1234 + assert obj.lucky_number() == -4.25 + + +def test_move_support(capture, msg): + from pybind11_tests import NCVirt, NonCopyable, Movable + + class NCVirtExt(NCVirt): + def get_noncopyable(self, a, b): + # Constructs and returns a new instance: + nc = NonCopyable(a*a, b*b) + return nc + + def get_movable(self, a, b): + # Return a referenced copy + self.movable = Movable(a, b) + return self.movable + + class NCVirtExt2(NCVirt): + def get_noncopyable(self, a, b): + # Keep a reference: this is going to throw an exception + self.nc = NonCopyable(a, b) + return self.nc + + def get_movable(self, a, b): + # Return a new instance without storing it + return Movable(a, b) + + ncv1 = NCVirtExt() + with capture: + ncv1.print_nc(2, 3) + assert capture == "36" + with capture: + ncv1.print_movable(4, 5) + assert capture == "9" + ncv2 = NCVirtExt2() + with capture: + ncv2.print_movable(7, 7) + assert capture == "14" + # Don't check the exception message here because it differs under debug/non-debug mode + with pytest.raises(RuntimeError): + ncv2.print_nc(9, 9) + + nc_stats = ConstructorStats.get(NonCopyable) + mv_stats = ConstructorStats.get(Movable) + assert nc_stats.alive() == 1 + assert mv_stats.alive() == 1 + del ncv1, ncv2 + assert nc_stats.alive() == 0 + assert mv_stats.alive() == 0 + assert nc_stats.values() == ['4', '9', '9', '9'] + assert mv_stats.values() == ['4', '5', '7', '7'] + assert nc_stats.copy_constructions == 0 + assert mv_stats.copy_constructions == 1 + assert nc_stats.move_constructions >= 0 + assert mv_stats.move_constructions >= 0 From 665e8804f3854480479b92fcb8958a6ca366929d Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Fri, 12 Aug 2016 22:28:31 +0200 Subject: [PATCH 2/8] Simplify tests by replacing output capture with asserts where possible The C++ part of the test code is modified to achieve this. As a result, this kind of test: ```python with capture: kw_func1(5, y=10) assert capture == "kw_func(x=5, y=10)" ``` can be replaced with a simple: `assert kw_func1(5, y=10) == "x=5, y=10"` --- tests/test_callbacks.cpp | 35 ++++----- tests/test_callbacks.py | 99 ++++++++------------------ tests/test_constants_and_functions.cpp | 31 ++++---- tests/test_constants_and_functions.py | 94 +++++++----------------- tests/test_inheritance.cpp | 12 ++-- tests/test_issues.cpp | 19 ++--- tests/test_issues.py | 48 +++++-------- tests/test_kwargs_and_defaults.cpp | 11 +-- tests/test_kwargs_and_defaults.py | 74 +++++++------------ tests/test_modules.cpp | 4 +- tests/test_modules.py | 6 +- tests/test_numpy_dtypes.cpp | 58 +++++++++------ tests/test_numpy_dtypes.py | 94 +++++++++++------------- tests/test_numpy_vectorize.cpp | 6 +- tests/test_numpy_vectorize.py | 14 ++-- tests/test_opaque_types.cpp | 12 ++-- tests/test_opaque_types.py | 44 ++++-------- tests/test_virtual_functions.py | 2 +- 18 files changed, 258 insertions(+), 405 deletions(-) diff --git a/tests/test_callbacks.cpp b/tests/test_callbacks.cpp index 80a0d0ead..270ff5ccd 100644 --- a/tests/test_callbacks.cpp +++ b/tests/test_callbacks.cpp @@ -12,18 +12,16 @@ #include -bool test_callback1(py::object func) { - func(); - return false; +py::object test_callback1(py::object func) { + return func(); } -int test_callback2(py::object func) { - py::object result = func("Hello", 'x', true, 5); - return result.cast(); +py::tuple test_callback2(py::object func) { + return func("Hello", 'x', true, 5); } -void test_callback3(const std::function &func) { - cout << "func(43) = " << func(43)<< std::endl; +std::string test_callback3(const std::function &func) { + return "func(43) = " + std::to_string(func(43)); } std::function test_callback4() { @@ -37,27 +35,24 @@ py::cpp_function test_callback5() { int dummy_function(int i) { return i + 1; } int dummy_function2(int i, int j) { return i + j; } -std::function roundtrip(std::function f) { - if (!f) - std::cout << "roundtrip (got None).." << std::endl; - else - std::cout << "roundtrip.." << std::endl; +std::function roundtrip(std::function f, bool expect_none = false) { + if (expect_none && f) { + throw std::runtime_error("Expected None to be converted to empty std::function"); + } return f; } -void test_dummy_function(const std::function &f) { +std::string test_dummy_function(const std::function &f) { using fn_type = int (*)(int); auto result = f.target(); if (!result) { - std::cout << "could not convert to a function pointer." << std::endl; auto r = f(1); - std::cout << "eval(1) = " << r << std::endl; + return "can't convert to function pointer: eval(1) = " + std::to_string(r); } else if (*result == dummy_function) { - std::cout << "argument matches dummy_function" << std::endl; auto r = (*result)(1); - std::cout << "eval(1) = " << r << std::endl; + return "matches dummy_function: eval(1) = " + std::to_string(r); } else { - std::cout << "argument does NOT match dummy_function. This should never happen!" << std::endl; + return "argument does NOT match dummy_function. This should never happen!"; } } @@ -96,7 +91,7 @@ void init_ex_callbacks(py::module &m) { /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */ m.def("dummy_function", &dummy_function); m.def("dummy_function2", &dummy_function2); - m.def("roundtrip", &roundtrip); + m.def("roundtrip", &roundtrip, py::arg("f"), py::arg("expect_none")=false); m.def("test_dummy_function", &test_dummy_function); // Export the payload constructor statistics for testing purposes: m.def("payload_cstats", &ConstructorStats::get); diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py index 3f70e87c4..83bc01635 100644 --- a/tests/test_callbacks.py +++ b/tests/test_callbacks.py @@ -1,70 +1,51 @@ import pytest -def test_inheritance(capture, msg): - from pybind11_tests import Pet, Dog, Rabbit, dog_bark, pet_print +def test_inheritance(msg): + from pybind11_tests import Pet, Dog, Rabbit, dog_bark, pet_name_species roger = Rabbit('Rabbit') assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot" - with capture: - pet_print(roger) - assert capture == "Rabbit is a parrot" + assert pet_name_species(roger) == "Rabbit is a parrot" polly = Pet('Polly', 'parrot') assert polly.name() + " is a " + polly.species() == "Polly is a parrot" - with capture: - pet_print(polly) - assert capture == "Polly is a parrot" + assert pet_name_species(polly) == "Polly is a parrot" molly = Dog('Molly') assert molly.name() + " is a " + molly.species() == "Molly is a dog" - with capture: - pet_print(molly) - assert capture == "Molly is a dog" + assert pet_name_species(molly) == "Molly is a dog" - with capture: - dog_bark(molly) - assert capture == "Woof!" + assert dog_bark(molly) == "Woof!" with pytest.raises(TypeError) as excinfo: dog_bark(polly) assert msg(excinfo.value) == """ Incompatible function arguments. The following argument types are supported: - 1. (arg0: m.Dog) -> None + 1. (arg0: m.Dog) -> str Invoked with: """ -def test_callbacks(capture): +def test_callbacks(): from functools import partial from pybind11_tests import (test_callback1, test_callback2, test_callback3, test_callback4, test_callback5) def func1(): - print('Callback function 1 called!') + return "func1" def func2(a, b, c, d): - print('Callback function 2 called : {}, {}, {}, {}'.format(a, b, c, d)) - return d + return "func2", a, b, c, d def func3(a): - print('Callback function 3 called : {}'.format(a)) + return "func3({})".format(a) - with capture: - assert test_callback1(func1) is False - assert capture == "Callback function 1 called!" - with capture: - assert test_callback2(func2) == 5 - assert capture == "Callback function 2 called : Hello, x, True, 5" - with capture: - assert test_callback1(partial(func2, "Hello", "from", "partial", "object")) is False - assert capture == "Callback function 2 called : Hello, from, partial, object" - with capture: - assert test_callback1(partial(func3, "Partial object with one argument")) is False - assert capture == "Callback function 3 called : Partial object with one argument" - with capture: - test_callback3(lambda i: i + 1) - assert capture == "func(43) = 44" + assert test_callback1(func1) == "func1" + assert test_callback2(func2) == ("func2", "Hello", "x", True, 5) + assert test_callback1(partial(func2, 1, 2, 3, 4)) == ("func2", 1, 2, 3, 4) + assert test_callback1(partial(func3, "partial")) == "func3(partial)" + assert test_callback3(lambda i: i + 1) == "func(43) = 44" f = test_callback4() assert f(43) == 44 @@ -82,49 +63,27 @@ def test_lambda_closure_cleanup(): assert cstats.move_constructions >= 1 -def test_cpp_function_roundtrip(capture): +def test_cpp_function_roundtrip(): """Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer""" from pybind11_tests import dummy_function, dummy_function2, test_dummy_function, roundtrip - with capture: - test_dummy_function(dummy_function) - assert capture == """ - argument matches dummy_function - eval(1) = 2 - """ - with capture: - test_dummy_function(roundtrip(dummy_function)) - assert capture == """ - roundtrip.. - argument matches dummy_function - eval(1) = 2 - """ - with capture: - assert roundtrip(None) is None - assert capture == "roundtrip (got None).." - with capture: - test_dummy_function(lambda x: x + 2) - assert capture == """ - could not convert to a function pointer. - eval(1) = 3 - """ + assert test_dummy_function(dummy_function) == "matches dummy_function: eval(1) = 2" + assert test_dummy_function(roundtrip(dummy_function)) == "matches dummy_function: eval(1) = 2" + assert roundtrip(None, expect_none=True) is None + assert test_dummy_function(lambda x: x + 2) == "can't convert to function pointer: eval(1) = 3" - with capture: - with pytest.raises(TypeError) as excinfo: - test_dummy_function(dummy_function2) - assert "Incompatible function arguments" in str(excinfo.value) - assert capture == "could not convert to a function pointer." + with pytest.raises(TypeError) as excinfo: + test_dummy_function(dummy_function2) + assert "Incompatible function arguments" in str(excinfo.value) - with capture: - with pytest.raises(TypeError) as excinfo: - test_dummy_function(lambda x, y: x + y) - assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument", - "takes exactly 2 arguments")) - assert capture == "could not convert to a function pointer." + with pytest.raises(TypeError) as excinfo: + test_dummy_function(lambda x, y: x + y) + assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument", + "takes exactly 2 arguments")) def test_function_signatures(doc): from pybind11_tests import test_callback3, test_callback4 - assert doc(test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> None" + assert doc(test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str" assert doc(test_callback4) == "test_callback4() -> Callable[[int], int]" diff --git a/tests/test_constants_and_functions.cpp b/tests/test_constants_and_functions.cpp index 1977a0aef..077fa7884 100644 --- a/tests/test_constants_and_functions.cpp +++ b/tests/test_constants_and_functions.cpp @@ -27,27 +27,24 @@ public: }; static EMode test_function(EMode mode) { - std::cout << "ExampleWithEnum::test_function(enum=" << mode << ")" << std::endl; return mode; } }; -bool test_function1() { - std::cout << "test_function()" << std::endl; - return false; +std::string test_function1() { + return "test_function()"; } -void test_function2(EMyEnumeration k) { - std::cout << "test_function(enum=" << k << ")" << std::endl; +std::string test_function2(EMyEnumeration k) { + return "test_function(enum=" + std::to_string(k) + ")"; } -float test_function3(int i) { - std::cout << "test_function(" << i << ")" << std::endl; - return (float) i / 2.f; +std::string test_function3(int i) { + return "test_function(" + std::to_string(i) + ")"; } -void test_ecenum(ECMyEnum z) { - std::cout << "test_ecenum(ECMyEnum::" << (z == ECMyEnum::Two ? "Two" : "Three") << ")" << std::endl; +std::string test_ecenum(ECMyEnum z) { + return "test_ecenum(ECMyEnum::" + std::string(z == ECMyEnum::Two ? "Two" : "Three") + ")"; } py::bytes return_bytes() { @@ -55,10 +52,14 @@ py::bytes return_bytes() { return std::string(data, 4); } -void print_bytes(py::bytes bytes) { - std::string value = (std::string) bytes; - for (size_t i = 0; i < value.length(); ++i) - std::cout << "bytes[" << i << "]=" << (int) value[i] << std::endl; +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; } void init_ex_constants_and_functions(py::module &m) { diff --git a/tests/test_constants_and_functions.py b/tests/test_constants_and_functions.py index 119965bf0..8295ef6f9 100644 --- a/tests/test_constants_and_functions.py +++ b/tests/test_constants_and_functions.py @@ -7,20 +7,13 @@ def test_constants(): assert some_constant == 14 -def test_function_overloading(capture): +def test_function_overloading(): from pybind11_tests import EMyEnumeration, test_function - with capture: - assert test_function() is False - assert test_function(7) == 3.5 - assert test_function(EMyEnumeration.EFirstEntry) is None - assert test_function(EMyEnumeration.ESecondEntry) is None - assert capture == """ - test_function() - test_function(7) - test_function(enum=1) - test_function(enum=2) - """ + assert test_function() == "test_function()" + assert test_function(7) == "test_function(7)" + assert test_function(EMyEnumeration.EFirstEntry) == "test_function(enum=1)" + assert test_function(EMyEnumeration.ESecondEntry) == "test_function(enum=2)" def test_unscoped_enum(): @@ -39,16 +32,12 @@ def test_unscoped_enum(): assert str(EMyEnumeration(2)) == "EMyEnumeration.ESecondEntry" -def test_scoped_enum(capture): +def test_scoped_enum(): from pybind11_tests import ECMyEnum, test_ecenum - with capture: - test_ecenum(ECMyEnum.Three) - assert capture == "test_ecenum(ECMyEnum::Three)" + assert test_ecenum(ECMyEnum.Three) == "test_ecenum(ECMyEnum::Three)" z = ECMyEnum.Two - with capture: - test_ecenum(z) - assert capture == "test_ecenum(ECMyEnum::Two)" + assert test_ecenum(z) == "test_ecenum(ECMyEnum::Two)" # expected TypeError exceptions for scoped enum ==/!= int comparisons with pytest.raises(TypeError): @@ -57,7 +46,7 @@ def test_scoped_enum(capture): assert z != 3 -def test_implicit_conversion(capture): +def test_implicit_conversion(): from pybind11_tests import ExampleWithEnum assert str(ExampleWithEnum.EMode.EFirstMode) == "EMode.EFirstMode" @@ -67,64 +56,29 @@ def test_implicit_conversion(capture): first = ExampleWithEnum.EFirstMode second = ExampleWithEnum.ESecondMode - with capture: - f(first) - assert capture == "ExampleWithEnum::test_function(enum=1)" + assert f(first) == 1 - with capture: - assert f(first) == f(first) - assert not f(first) != f(first) + 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) != 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(first)) + assert not f(first) != int(f(first)) - assert f(first) != int(f(second)) - assert not f(first) == int(f(second)) - assert capture == """ - ExampleWithEnum::test_function(enum=1) - ExampleWithEnum::test_function(enum=1) - ExampleWithEnum::test_function(enum=1) - ExampleWithEnum::test_function(enum=1) - ExampleWithEnum::test_function(enum=1) - ExampleWithEnum::test_function(enum=2) - ExampleWithEnum::test_function(enum=1) - ExampleWithEnum::test_function(enum=2) - ExampleWithEnum::test_function(enum=1) - ExampleWithEnum::test_function(enum=1) - ExampleWithEnum::test_function(enum=1) - ExampleWithEnum::test_function(enum=1) - ExampleWithEnum::test_function(enum=1) - ExampleWithEnum::test_function(enum=2) - ExampleWithEnum::test_function(enum=1) - ExampleWithEnum::test_function(enum=2) - """ + assert f(first) != int(f(second)) + assert not f(first) == int(f(second)) - with capture: - # noinspection PyDictCreation - x = {f(first): 1, f(second): 2} - x[f(first)] = 3 - x[f(second)] = 4 - assert capture == """ - ExampleWithEnum::test_function(enum=1) - ExampleWithEnum::test_function(enum=2) - ExampleWithEnum::test_function(enum=1) - ExampleWithEnum::test_function(enum=2) - """ + # 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_bytes(capture): +def test_bytes(): from pybind11_tests import return_bytes, print_bytes - with capture: - print_bytes(return_bytes()) - assert capture == """ - bytes[0]=1 - bytes[1]=0 - bytes[2]=2 - bytes[3]=0 - """ + assert print_bytes(return_bytes()) == "bytes[1 0 2 0]" diff --git a/tests/test_inheritance.cpp b/tests/test_inheritance.cpp index b70ea77a1..2997ccece 100644 --- a/tests/test_inheritance.cpp +++ b/tests/test_inheritance.cpp @@ -23,7 +23,7 @@ private: class Dog : public Pet { public: Dog(const std::string &name) : Pet(name, "dog") {} - void bark() const { std::cout << "Woof!" << std::endl; } + std::string bark() const { return "Woof!"; } }; class Rabbit : public Pet { @@ -31,12 +31,12 @@ public: Rabbit(const std::string &name) : Pet(name, "parrot") {} }; -void pet_print(const Pet &pet) { - std::cout << pet.name() + " is a " + pet.species() << std::endl; +std::string pet_name_species(const Pet &pet) { + return pet.name() + " is a " + pet.species(); } -void dog_bark(const Dog &dog) { - dog.bark(); +std::string dog_bark(const Dog &dog) { + return dog.bark(); } @@ -59,7 +59,7 @@ void init_ex_inheritance(py::module &m) { py::class_(m, "Rabbit", py::base()) .def(py::init()); - m.def("pet_print", pet_print); + m.def("pet_name_species", pet_name_species); m.def("dog_bark", dog_bark); py::class_(m, "BaseClass").def(py::init<>()); diff --git a/tests/test_issues.cpp b/tests/test_issues.cpp index 085dff90c..a0d1fd5e8 100644 --- a/tests/test_issues.cpp +++ b/tests/test_issues.cpp @@ -34,19 +34,20 @@ void init_issues(py::module &m) { #endif // #137: const char* isn't handled properly - m2.def("print_cchar", [](const char *string) { std::cout << string << std::endl; }); + m2.def("print_cchar", [](const char *s) { return std::string(s); }); // #150: char bindings broken - m2.def("print_char", [](char c) { std::cout << c << std::endl; }); + m2.def("print_char", [](char c) { return std::string(1, c); }); // #159: virtual function dispatch has problems with similar-named functions - struct Base { virtual void dispatch(void) const { + struct Base { virtual std::string dispatch() const { /* for some reason MSVC2015 can't compile this if the function is pure virtual */ + return {}; }; }; struct DispatchIssue : Base { - virtual void dispatch(void) const { - PYBIND11_OVERLOAD_PURE(void, Base, dispatch, /* no arguments */); + virtual std::string dispatch() const { + PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */); } }; @@ -54,7 +55,7 @@ void init_issues(py::module &m) { .def(py::init<>()) .def("dispatch", &Base::dispatch); - m2.def("dispatch_issue_go", [](const Base * b) { b->dispatch(); }); + m2.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); }); struct Placeholder { int i; Placeholder(int i) : i(i) { } }; @@ -171,7 +172,7 @@ void init_issues(py::module &m) { .def("as_base", [](NestA &a) -> NestABase& { return (NestABase&) a; }, py::return_value_policy::reference_internal); py::class_(m2, "NestB").def(py::init<>()).def(py::self -= int()).def_readwrite("a", &NestB::a); py::class_(m2, "NestC").def(py::init<>()).def(py::self *= int()).def_readwrite("b", &NestC::b); - m2.def("print_NestA", [](const NestA &a) { std::cout << a.value << std::endl; }); - m2.def("print_NestB", [](const NestB &b) { std::cout << b.value << std::endl; }); - m2.def("print_NestC", [](const NestC &c) { std::cout << c.value << std::endl; }); + m2.def("get_NestA", [](const NestA &a) { return a.value; }); + m2.def("get_NestB", [](const NestB &b) { return b.value; }); + m2.def("get_NestC", [](const NestC &c) { return c.value; }); } diff --git a/tests/test_issues.py b/tests/test_issues.py index 0ab2e3608..f76813964 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -2,24 +2,22 @@ import pytest import gc -def test_regressions(capture): +def test_regressions(): from pybind11_tests.issues import print_cchar, print_char - with capture: - print_cchar("const char *") # #137: const char* isn't handled properly - assert capture == "const char *" - with capture: - print_char("c") # #150: char bindings broken - assert capture == "c" + # #137: const char* isn't handled properly + assert print_cchar("const char *") == "const char *" + # #150: char bindings broken + assert print_char("c") == "c" -def test_dispatch_issue(capture, msg): +def test_dispatch_issue(msg): """#159: virtual function dispatch has problems with similar-named functions""" from pybind11_tests.issues import DispatchIssue, dispatch_issue_go class PyClass1(DispatchIssue): def dispatch(self): - print("Yay..") + return "Yay.." class PyClass2(DispatchIssue): def dispatch(self): @@ -28,12 +26,10 @@ def test_dispatch_issue(capture, msg): assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"' p = PyClass1() - dispatch_issue_go(p) + return dispatch_issue_go(p) b = PyClass2() - with capture: - dispatch_issue_go(b) - assert capture == "Yay.." + assert dispatch_issue_go(b) == "Yay.." def test_reference_wrapper(): @@ -127,36 +123,26 @@ def test_str_issue(capture, msg): """ -def test_nested(capture): +def test_nested(): """ #328: first member in a class can't be used in operators""" - from pybind11_tests.issues import NestA, NestB, NestC, print_NestA, print_NestB, print_NestC + from pybind11_tests.issues import NestA, NestB, NestC, get_NestA, get_NestB, get_NestC a = NestA() b = NestB() c = NestC() a += 10 + assert get_NestA(a) == 13 b.a += 100 + assert get_NestA(b.a) == 103 c.b.a += 1000 + assert get_NestA(c.b.a) == 1003 b -= 1 + assert get_NestB(b) == 3 c.b -= 3 + assert get_NestB(c.b) == 1 c *= 7 - - with capture: - print_NestA(a) - print_NestA(b.a) - print_NestA(c.b.a) - print_NestB(b) - print_NestB(c.b) - print_NestC(c) - assert capture == """ - 13 - 103 - 1003 - 3 - 1 - 35 - """ + assert get_NestC(c) == 35 abase = a.as_base() assert abase.value == -2 diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 281624615..3fefc798d 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -10,13 +10,14 @@ #include "pybind11_tests.h" #include -void kw_func(int x, int y) { std::cout << "kw_func(x=" << x << ", y=" << y << ")" << std::endl; } +std::string kw_func(int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); } -void kw_func4(const std::vector &entries) { - std::cout << "kw_func4: "; +std::string kw_func4(const std::vector &entries) { + std::string ret = "{"; for (int i : entries) - std::cout << i << " "; - std::cout << endl; + ret += std::to_string(i) + " "; + ret.back() = '}'; + return ret; } py::object call_kw_func(py::function f) { diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index 0d785a426..735722dec 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -5,77 +5,51 @@ from pybind11_tests import (kw_func0, kw_func1, kw_func2, kw_func3, kw_func4, ca def test_function_signatures(doc): - assert doc(kw_func0) == "kw_func0(arg0: int, arg1: int) -> None" - assert doc(kw_func1) == "kw_func1(x: int, y: int) -> None" - assert doc(kw_func2) == "kw_func2(x: int=100, y: int=200) -> None" + assert doc(kw_func0) == "kw_func0(arg0: int, arg1: int) -> str" + assert doc(kw_func1) == "kw_func1(x: int, y: int) -> str" + assert doc(kw_func2) == "kw_func2(x: int=100, y: int=200) -> str" assert doc(kw_func3) == "kw_func3(data: str='Hello world!') -> None" - assert doc(kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> None" - assert doc(kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> None" - assert doc(kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> None" + assert doc(kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> str" + assert doc(kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> str" + assert doc(kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> str" assert doc(args_function) == "args_function(*args) -> None" assert doc(args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> None" assert doc(KWClass.foo0) == "foo0(self: m.KWClass, arg0: int, arg1: float) -> None" assert doc(KWClass.foo1) == "foo1(self: m.KWClass, x: int, y: float) -> None" -def test_named_arguments(capture, msg): - with capture: - kw_func1(5, 10) - assert capture == "kw_func(x=5, y=10)" - with capture: - kw_func1(5, y=10) - assert capture == "kw_func(x=5, y=10)" - with capture: - kw_func1(y=10, x=5) - assert capture == "kw_func(x=5, y=10)" +def test_named_arguments(msg): + assert kw_func0(5, 10) == "x=5, y=10" - with capture: - kw_func2() - assert capture == "kw_func(x=100, y=200)" - with capture: - kw_func2(5) - assert capture == "kw_func(x=5, y=200)" - with capture: - kw_func2(x=5) - assert capture == "kw_func(x=5, y=200)" - with capture: - kw_func2(y=10) - assert capture == "kw_func(x=100, y=10)" - with capture: - kw_func2(5, 10) - assert capture == "kw_func(x=5, y=10)" - with capture: - kw_func2(x=5, y=10) - assert capture == "kw_func(x=5, y=10)" + assert kw_func1(5, 10) == "x=5, y=10" + assert kw_func1(5, y=10) == "x=5, y=10" + assert kw_func1(y=10, x=5) == "x=5, y=10" + + assert kw_func2() == "x=100, y=200" + assert kw_func2(5) == "x=5, y=200" + assert kw_func2(x=5) == "x=5, y=200" + assert kw_func2(y=10) == "x=100, y=10" + assert kw_func2(5, 10) == "x=5, y=10" + assert kw_func2(x=5, y=10) == "x=5, y=10" with pytest.raises(TypeError) as excinfo: # noinspection PyArgumentList kw_func2(x=5, y=10, z=12) assert msg(excinfo.value) == """ Incompatible function arguments. The following argument types are supported: - 1. (x: int=100, y: int=200) -> None + 1. (x: int=100, y: int=200) -> str Invoked with: """ - with capture: - kw_func4() - assert capture == "kw_func4: 13 17" - with capture: - kw_func4(myList=[1, 2, 3]) - assert capture == "kw_func4: 1 2 3" + assert kw_func4() == "{13 17}" + assert kw_func4(myList=[1, 2, 3]) == "{1 2 3}" - with capture: - kw_func_udl(x=5, y=10) - assert capture == "kw_func(x=5, y=10)" - with capture: - kw_func_udl_z(x=5) - assert capture == "kw_func(x=5, y=0)" + assert kw_func_udl(x=5, y=10) == "x=5, y=10" + assert kw_func_udl_z(x=5) == "x=5, y=0" def test_arg_and_kwargs(capture): - with capture: - call_kw_func(kw_func2) - assert capture == "kw_func(x=1234, y=5678)" + assert call_kw_func(kw_func2) == "x=1234, y=5678" with capture: args_function('arg1_value', 'arg2_value', 3) assert capture.unordered == """ diff --git a/tests/test_modules.cpp b/tests/test_modules.cpp index 3d96df616..b77dacce0 100644 --- a/tests/test_modules.cpp +++ b/tests/test_modules.cpp @@ -11,8 +11,8 @@ #include "pybind11_tests.h" #include "constructor_stats.h" -void submodule_func() { - std::cout << "submodule_func()" << std::endl; +std::string submodule_func() { + return "submodule_func()"; } class A { diff --git a/tests/test_modules.py b/tests/test_modules.py index 3deb02e3b..fe72f190a 100644 --- a/tests/test_modules.py +++ b/tests/test_modules.py @@ -1,14 +1,12 @@ -def test_nested_modules(capture): +def test_nested_modules(): import pybind11_tests from pybind11_tests.submodule import submodule_func assert pybind11_tests.__name__ == "pybind11_tests" assert pybind11_tests.submodule.__name__ == "pybind11_tests.submodule" - with capture: - submodule_func() - assert capture == "submodule_func()" + assert submodule_func() == "submodule_func()" def test_reference_internal(): diff --git a/tests/test_numpy_dtypes.cpp b/tests/test_numpy_dtypes.cpp index 9afd342b2..b4266d0f3 100644 --- a/tests/test_numpy_dtypes.cpp +++ b/tests/test_numpy_dtypes.cpp @@ -8,7 +8,6 @@ */ #include "pybind11_tests.h" - #include #ifdef __GNUC__ @@ -139,29 +138,48 @@ py::array_t create_string_array(bool non_empty) { } template -void print_recarray(py::array_t arr) { - auto req = arr.request(); - auto ptr = static_cast(req.ptr); - for (size_t i = 0; i < req.size; i++) - std::cout << ptr[i] << std::endl; +py::list print_recarray(py::array_t arr) { + const auto req = arr.request(); + const auto ptr = static_cast(req.ptr); + auto l = py::list(); + for (size_t i = 0; i < req.size; i++) { + std::stringstream ss; + ss << ptr[i]; + l.append(py::str(ss.str())); + } + return l; } -void print_format_descriptors() { - std::cout << py::format_descriptor::format() << std::endl; - std::cout << py::format_descriptor::format() << std::endl; - std::cout << py::format_descriptor::format() << std::endl; - std::cout << py::format_descriptor::format() << std::endl; - std::cout << py::format_descriptor::format() << std::endl; - std::cout << py::format_descriptor::format() << std::endl; +py::list print_format_descriptors() { + const auto fmts = { + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format(), + py::format_descriptor::format() + }; + auto l = py::list(); + for (const auto &fmt : fmts) { + l.append(py::cast(fmt)); + } + return l; } -void print_dtypes() { - std::cout << (std::string) py::dtype::of().str() << std::endl; - std::cout << (std::string) py::dtype::of().str() << std::endl; - std::cout << (std::string) py::dtype::of().str() << std::endl; - std::cout << (std::string) py::dtype::of().str() << std::endl; - std::cout << (std::string) py::dtype::of().str() << std::endl; - std::cout << (std::string) py::dtype::of().str() << std::endl; +py::list print_dtypes() { + const auto dtypes = { + py::dtype::of().str(), + py::dtype::of().str(), + py::dtype::of().str(), + py::dtype::of().str(), + py::dtype::of().str(), + py::dtype::of().str() + }; + auto l = py::list(); + for (const auto &s : dtypes) { + l.append(s); + } + return l; } py::array_t test_array_ctors(int i) { diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py index 783f6ad25..73da34644 100644 --- a/tests/test_numpy_dtypes.py +++ b/tests/test_numpy_dtypes.py @@ -13,39 +13,35 @@ packed_dtype = np.dtype([('x', '?'), ('y', 'u4'), ('z', 'f4')]) @pytest.requires_numpy -def test_format_descriptors(capture): +def test_format_descriptors(): from pybind11_tests import get_format_unbound, print_format_descriptors with pytest.raises(RuntimeError) as excinfo: get_format_unbound() assert 'unsupported buffer format' in str(excinfo.value) - with capture: - print_format_descriptors() - assert capture == """ - T{=?:x:3x=I:y:=f:z:} - T{=?:x:=I:y:=f:z:} - T{=T{=?:x:3x=I:y:=f:z:}:a:=T{=?:x:=I:y:=f:z:}:b:} - T{=?:x:3x=I:y:=f:z:12x} - T{8x=T{=?:x:3x=I:y:=f:z:12x}:a:8x} - T{=3s:a:=3s:b:} - """ + assert print_format_descriptors() == [ + "T{=?:x:3x=I:y:=f:z:}", + "T{=?:x:=I:y:=f:z:}", + "T{=T{=?:x:3x=I:y:=f:z:}:a:=T{=?:x:=I:y:=f:z:}:b:}", + "T{=?:x:3x=I:y:=f:z:12x}", + "T{8x=T{=?:x:3x=I:y:=f:z:12x}:a:8x}", + "T{=3s:a:=3s:b:}" + ] @pytest.requires_numpy -def test_dtype(capture): +def test_dtype(): from pybind11_tests import print_dtypes, test_dtype_ctors, test_dtype_methods - with capture: - print_dtypes() - assert capture == """ - {'names':['x','y','z'], 'formats':['?',') { std::cout << "Int branch taken." << std::endl; }); - m.def("selective_func", [](py::array_t) { std::cout << "Float branch taken." << std::endl; }); - m.def("selective_func", [](py::array_t, py::array::c_style>) { std::cout << "Complex float branch taken." << std::endl; }); + m.def("selective_func", [](py::array_t) { return "Int branch taken."; }); + m.def("selective_func", [](py::array_t) { return "Float branch taken."; }); + m.def("selective_func", [](py::array_t, py::array::c_style>) { return "Complex float branch taken."; }); } diff --git a/tests/test_numpy_vectorize.py b/tests/test_numpy_vectorize.py index 6fcf80814..73da819a4 100644 --- a/tests/test_numpy_vectorize.py +++ b/tests/test_numpy_vectorize.py @@ -59,18 +59,12 @@ def test_vectorize(capture): @pytest.requires_numpy -def test_type_selection(capture): +def test_type_selection(): from pybind11_tests import selective_func - with capture: - selective_func(np.array([1], dtype=np.int32)) - selective_func(np.array([1.0], dtype=np.float32)) - selective_func(np.array([1.0j], dtype=np.complex64)) - assert capture == """ - Int branch taken. - Float branch taken. - Complex float branch taken. - """ + assert selective_func(np.array([1], dtype=np.int32)) == "Int branch taken." + assert selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken." + assert selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken." @pytest.requires_numpy diff --git a/tests/test_opaque_types.cpp b/tests/test_opaque_types.cpp index 0ede5e328..901f05e13 100644 --- a/tests/test_opaque_types.cpp +++ b/tests/test_opaque_types.cpp @@ -38,21 +38,21 @@ void init_ex_opaque_types(py::module &m) { .def_readwrite("stringList", &ClassWithSTLVecProperty::stringList); m.def("print_opaque_list", [](const StringList &l) { - std::cout << "Opaque list: ["; + std::string ret = "Opaque list: ["; bool first = true; for (auto entry : l) { if (!first) - std::cout << ", "; - std::cout << entry; + ret += ", "; + ret += entry; first = false; } - std::cout << "]" << std::endl; + return ret + "]"; }); m.def("return_void_ptr", []() { return (void *) 0x1234; }); - m.def("print_void_ptr", [](void *ptr) { std::cout << "Got void ptr : 0x" << std::hex << (uint64_t) ptr << std::dec << std::endl; }); + m.def("get_void_ptr_value", [](void *ptr) { return reinterpret_cast(ptr); }); m.def("return_null_str", []() { return (char *) nullptr; }); - m.def("print_null_str", [](char *ptr) { std::cout << "Got null str : 0x" << std::hex << (uint64_t) ptr << std::dec << std::endl; }); + m.def("get_null_str_value", [](char *ptr) { return reinterpret_cast(ptr); }); m.def("return_unique_ptr", []() -> std::unique_ptr { StringList *result = new StringList(); diff --git a/tests/test_opaque_types.py b/tests/test_opaque_types.py index 5c2ca9248..943686383 100644 --- a/tests/test_opaque_types.py +++ b/tests/test_opaque_types.py @@ -1,64 +1,48 @@ import pytest -def test_string_list(capture): +def test_string_list(): from pybind11_tests import StringList, ClassWithSTLVecProperty, print_opaque_list l = StringList() l.push_back("Element 1") l.push_back("Element 2") - with capture: - print_opaque_list(l) - assert capture == "Opaque list: [Element 1, Element 2]" + assert print_opaque_list(l) == "Opaque list: [Element 1, Element 2]" assert l.back() == "Element 2" for i, k in enumerate(l, start=1): assert k == "Element {}".format(i) l.pop_back() - with capture: - print_opaque_list(l) - assert capture == "Opaque list: [Element 1]" + assert print_opaque_list(l) == "Opaque list: [Element 1]" cvp = ClassWithSTLVecProperty() - with capture: - print_opaque_list(cvp.stringList) - assert capture == "Opaque list: []" + assert print_opaque_list(cvp.stringList) == "Opaque list: []" cvp.stringList = l cvp.stringList.push_back("Element 3") - with capture: - print_opaque_list(cvp.stringList) - assert capture == "Opaque list: [Element 1, Element 3]" + assert print_opaque_list(cvp.stringList) == "Opaque list: [Element 1, Element 3]" -def test_pointers(capture, msg): - from pybind11_tests import (return_void_ptr, print_void_ptr, ExampleMandA, - print_opaque_list, return_null_str, print_null_str, +def test_pointers(msg): + from pybind11_tests import (return_void_ptr, get_void_ptr_value, ExampleMandA, + print_opaque_list, return_null_str, get_null_str_value, return_unique_ptr, ConstructorStats) - with capture: - print_void_ptr(return_void_ptr()) - assert capture == "Got void ptr : 0x1234" - with capture: - print_void_ptr(ExampleMandA()) # Should also work for other C++ types - assert "Got void ptr" in capture + assert get_void_ptr_value(return_void_ptr()) == 0x1234 + assert get_void_ptr_value(ExampleMandA()) # Should also work for other C++ types assert ConstructorStats.get(ExampleMandA).alive() == 0 with pytest.raises(TypeError) as excinfo: - print_void_ptr([1, 2, 3]) # This should not work + get_void_ptr_value([1, 2, 3]) # This should not work assert msg(excinfo.value) == """ Incompatible function arguments. The following argument types are supported: - 1. (arg0: capsule) -> None + 1. (arg0: capsule) -> int Invoked with: [1, 2, 3] """ assert return_null_str() is None - with capture: - print_null_str(return_null_str()) - assert capture == "Got null str : 0x0" + assert get_null_str_value(return_null_str()) is not None ptr = return_unique_ptr() assert "StringList" in repr(ptr) - with capture: - print_opaque_list(ptr) - assert capture == "Opaque list: [some value]" + assert print_opaque_list(ptr) == "Opaque list: [some value]" diff --git a/tests/test_virtual_functions.py b/tests/test_virtual_functions.py index f2efb6bed..27b0222af 100644 --- a/tests/test_virtual_functions.py +++ b/tests/test_virtual_functions.py @@ -173,7 +173,7 @@ def test_inheriting_repeat(capture): assert obj.lucky_number() == -4.25 -def test_move_support(capture, msg): +def test_move_support(capture): from pybind11_tests import NCVirt, NonCopyable, Movable class NCVirtExt(NCVirt): From 382db5b2e750acac62de0f707fe36d952461b074 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Sat, 13 Aug 2016 00:37:50 +0200 Subject: [PATCH 3/8] Move inheritance tests into the proper file --- tests/test_callbacks.py | 26 -------------------------- tests/test_inheritance.py | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py index 83bc01635..d6e72f333 100644 --- a/tests/test_callbacks.py +++ b/tests/test_callbacks.py @@ -1,32 +1,6 @@ import pytest -def test_inheritance(msg): - from pybind11_tests import Pet, Dog, Rabbit, dog_bark, pet_name_species - - roger = Rabbit('Rabbit') - assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot" - assert pet_name_species(roger) == "Rabbit is a parrot" - - polly = Pet('Polly', 'parrot') - assert polly.name() + " is a " + polly.species() == "Polly is a parrot" - assert pet_name_species(polly) == "Polly is a parrot" - - molly = Dog('Molly') - assert molly.name() + " is a " + molly.species() == "Molly is a dog" - assert pet_name_species(molly) == "Molly is a dog" - - assert dog_bark(molly) == "Woof!" - - with pytest.raises(TypeError) as excinfo: - dog_bark(polly) - assert msg(excinfo.value) == """ - Incompatible function arguments. The following argument types are supported: - 1. (arg0: m.Dog) -> str - Invoked with: - """ - - def test_callbacks(): from functools import partial from pybind11_tests import (test_callback1, test_callback2, test_callback3, diff --git a/tests/test_inheritance.py b/tests/test_inheritance.py index a7a9778ca..b55490cf6 100644 --- a/tests/test_inheritance.py +++ b/tests/test_inheritance.py @@ -1,3 +1,30 @@ +import pytest + + +def test_inheritance(msg): + from pybind11_tests import Pet, Dog, Rabbit, dog_bark, pet_name_species + + roger = Rabbit('Rabbit') + assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot" + assert pet_name_species(roger) == "Rabbit is a parrot" + + polly = Pet('Polly', 'parrot') + assert polly.name() + " is a " + polly.species() == "Polly is a parrot" + assert pet_name_species(polly) == "Polly is a parrot" + + molly = Dog('Molly') + assert molly.name() + " is a " + molly.species() == "Molly is a dog" + assert pet_name_species(molly) == "Molly is a dog" + + assert dog_bark(molly) == "Woof!" + + with pytest.raises(TypeError) as excinfo: + dog_bark(polly) + assert msg(excinfo.value) == """ + Incompatible function arguments. The following argument types are supported: + 1. (arg0: m.Dog) -> str + Invoked with: + """ def test_automatic_upcasting(): From a9a37b4e31966629dfe0b07f6d8fc8066ebe479a Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Sat, 13 Aug 2016 00:57:24 +0200 Subject: [PATCH 4/8] Move enum tests into a new file There are more enum tests than 'constants and functions'. --- tests/CMakeLists.txt | 1 + tests/pybind11_tests.cpp | 2 + tests/test_constants_and_functions.cpp | 46 ++--------------- tests/test_constants_and_functions.py | 69 ++------------------------ tests/test_enum.cpp | 57 +++++++++++++++++++++ tests/test_enum.py | 63 +++++++++++++++++++++++ 6 files changed, 131 insertions(+), 107 deletions(-) create mode 100644 tests/test_enum.cpp create mode 100644 tests/test_enum.py diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f4339295c..d4db9032a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,6 +7,7 @@ set(PYBIND11_TEST_FILES test_buffers.cpp test_callbacks.cpp test_constants_and_functions.cpp + test_enum.cpp test_eval.cpp test_exceptions.cpp test_inheritance.cpp diff --git a/tests/pybind11_tests.cpp b/tests/pybind11_tests.cpp index 507ede828..80ecf0fb0 100644 --- a/tests/pybind11_tests.cpp +++ b/tests/pybind11_tests.cpp @@ -30,6 +30,7 @@ void init_ex_stl_binder_vector(py::module &); void init_ex_eval(py::module &); void init_ex_custom_exceptions(py::module &); void init_ex_numpy_dtypes(py::module &); +void init_ex_enum(py::module &); void init_issues(py::module &); #if defined(PYBIND11_TEST_EIGEN) @@ -74,6 +75,7 @@ PYBIND11_PLUGIN(pybind11_tests) { init_ex_eval(m); init_ex_custom_exceptions(m); init_ex_numpy_dtypes(m); + init_ex_enum(m); init_issues(m); #if defined(PYBIND11_TEST_EIGEN) diff --git a/tests/test_constants_and_functions.cpp b/tests/test_constants_and_functions.cpp index 077fa7884..03f417790 100644 --- a/tests/test_constants_and_functions.cpp +++ b/tests/test_constants_and_functions.cpp @@ -9,33 +9,13 @@ #include "pybind11_tests.h" -enum EMyEnumeration { - EFirstEntry = 1, - ESecondEntry -}; - -enum class ECMyEnum { - Two = 2, - Three -}; - -class ExampleWithEnum { -public: - enum EMode { - EFirstMode = 1, - ESecondMode - }; - - static EMode test_function(EMode mode) { - return mode; - } -}; +enum MyEnum { EFirstEntry = 1, ESecondEntry }; std::string test_function1() { return "test_function()"; } -std::string test_function2(EMyEnumeration k) { +std::string test_function2(MyEnum k) { return "test_function(enum=" + std::to_string(k) + ")"; } @@ -43,10 +23,6 @@ std::string test_function3(int i) { return "test_function(" + std::to_string(i) + ")"; } -std::string test_ecenum(ECMyEnum z) { - return "test_ecenum(ECMyEnum::" + std::string(z == ECMyEnum::Two ? "Two" : "Three") + ")"; -} - py::bytes return_bytes() { const char *data = "\x01\x00\x02\x00"; return std::string(data, 4); @@ -63,29 +39,17 @@ std::string print_bytes(py::bytes bytes) { } void init_ex_constants_and_functions(py::module &m) { + m.attr("some_constant") = py::int_(14); + m.def("test_function", &test_function1); m.def("test_function", &test_function2); m.def("test_function", &test_function3); - m.def("test_ecenum", &test_ecenum); - m.attr("some_constant") = py::int_(14); - py::enum_(m, "EMyEnumeration") + py::enum_(m, "MyEnum") .value("EFirstEntry", EFirstEntry) .value("ESecondEntry", ESecondEntry) .export_values(); - py::enum_(m, "ECMyEnum") - .value("Two", ECMyEnum::Two) - .value("Three", ECMyEnum::Three) - ; - - py::class_ exenum_class(m, "ExampleWithEnum"); - exenum_class.def_static("test_function", &ExampleWithEnum::test_function); - py::enum_(exenum_class, "EMode") - .value("EFirstMode", ExampleWithEnum::EFirstMode) - .value("ESecondMode", ExampleWithEnum::ESecondMode) - .export_values(); - m.def("return_bytes", &return_bytes); m.def("print_bytes", &print_bytes); } diff --git a/tests/test_constants_and_functions.py b/tests/test_constants_and_functions.py index 8295ef6f9..2c6321e05 100644 --- a/tests/test_constants_and_functions.py +++ b/tests/test_constants_and_functions.py @@ -1,4 +1,3 @@ -import pytest def test_constants(): @@ -8,74 +7,12 @@ def test_constants(): def test_function_overloading(): - from pybind11_tests import EMyEnumeration, test_function + from pybind11_tests import MyEnum, test_function assert test_function() == "test_function()" assert test_function(7) == "test_function(7)" - assert test_function(EMyEnumeration.EFirstEntry) == "test_function(enum=1)" - assert test_function(EMyEnumeration.ESecondEntry) == "test_function(enum=2)" - - -def test_unscoped_enum(): - from pybind11_tests import EMyEnumeration, EFirstEntry - - assert str(EMyEnumeration.EFirstEntry) == "EMyEnumeration.EFirstEntry" - assert str(EMyEnumeration.ESecondEntry) == "EMyEnumeration.ESecondEntry" - assert str(EFirstEntry) == "EMyEnumeration.EFirstEntry" - - # no TypeError exception for unscoped enum ==/!= int comparisons - y = EMyEnumeration.ESecondEntry - assert y == 2 - assert y != 3 - - assert int(EMyEnumeration.ESecondEntry) == 2 - assert str(EMyEnumeration(2)) == "EMyEnumeration.ESecondEntry" - - -def test_scoped_enum(): - from pybind11_tests import ECMyEnum, test_ecenum - - assert test_ecenum(ECMyEnum.Three) == "test_ecenum(ECMyEnum::Three)" - z = ECMyEnum.Two - assert test_ecenum(z) == "test_ecenum(ECMyEnum::Two)" - - # expected TypeError exceptions for scoped enum ==/!= int comparisons - with pytest.raises(TypeError): - assert z == 2 - with pytest.raises(TypeError): - assert z != 3 - - -def test_implicit_conversion(): - from pybind11_tests import ExampleWithEnum - - assert str(ExampleWithEnum.EMode.EFirstMode) == "EMode.EFirstMode" - assert str(ExampleWithEnum.EFirstMode) == "EMode.EFirstMode" - - f = ExampleWithEnum.test_function - first = ExampleWithEnum.EFirstMode - second = ExampleWithEnum.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}" + assert test_function(MyEnum.EFirstEntry) == "test_function(enum=1)" + assert test_function(MyEnum.ESecondEntry) == "test_function(enum=2)" def test_bytes(): diff --git a/tests/test_enum.cpp b/tests/test_enum.cpp new file mode 100644 index 000000000..e4b2594c5 --- /dev/null +++ b/tests/test_enum.cpp @@ -0,0 +1,57 @@ +/* + tests/test_enums.cpp -- enumerations + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#include "pybind11_tests.h" + +enum UnscopedEnum { + EOne = 1, + ETwo +}; + +enum class ScopedEnum { + Two = 2, + Three +}; + +class ClassWithUnscopedEnum { +public: + enum EMode { + EFirstMode = 1, + ESecondMode + }; + + static EMode test_function(EMode mode) { + return mode; + } +}; + +std::string test_scoped_enum(ScopedEnum z) { + return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three"); +} + +void init_ex_enum(py::module &m) { + m.def("test_scoped_enum", &test_scoped_enum); + + py::enum_(m, "UnscopedEnum") + .value("EOne", EOne) + .value("ETwo", ETwo) + .export_values(); + + py::enum_(m, "ScopedEnum") + .value("Two", ScopedEnum::Two) + .value("Three", ScopedEnum::Three) + ; + + py::class_ exenum_class(m, "ClassWithUnscopedEnum"); + exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function); + py::enum_(exenum_class, "EMode") + .value("EFirstMode", ClassWithUnscopedEnum::EFirstMode) + .value("ESecondMode", ClassWithUnscopedEnum::ESecondMode) + .export_values(); +} diff --git a/tests/test_enum.py b/tests/test_enum.py new file mode 100644 index 000000000..efabae7f7 --- /dev/null +++ b/tests/test_enum.py @@ -0,0 +1,63 @@ +import pytest + + +def test_unscoped_enum(): + from pybind11_tests import UnscopedEnum, EOne + + assert str(UnscopedEnum.EOne) == "UnscopedEnum.EOne" + assert str(UnscopedEnum.ETwo) == "UnscopedEnum.ETwo" + assert str(EOne) == "UnscopedEnum.EOne" + + # no TypeError exception for unscoped enum ==/!= int comparisons + y = UnscopedEnum.ETwo + assert y == 2 + assert y != 3 + + assert int(UnscopedEnum.ETwo) == 2 + assert str(UnscopedEnum(2)) == "UnscopedEnum.ETwo" + + +def test_scoped_enum(): + from pybind11_tests import ScopedEnum, test_scoped_enum + + assert test_scoped_enum(ScopedEnum.Three) == "ScopedEnum::Three" + z = ScopedEnum.Two + assert test_scoped_enum(z) == "ScopedEnum::Two" + + # expected TypeError exceptions for scoped enum ==/!= int comparisons + with pytest.raises(TypeError): + assert z == 2 + with pytest.raises(TypeError): + assert z != 3 + + +def test_implicit_conversion(): + from pybind11_tests import ClassWithUnscopedEnum + + assert str(ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode" + assert str(ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode" + + f = ClassWithUnscopedEnum.test_function + first = ClassWithUnscopedEnum.EFirstMode + second = ClassWithUnscopedEnum.ESecondMode + + assert f(first) == 1 + + assert f(first) == f(first) + assert not f(first) != f(first) + + assert f(first) != f(second) + assert not f(first) == f(second) + + assert f(first) == int(f(first)) + assert not f(first) != int(f(first)) + + assert f(first) != int(f(second)) + assert not f(first) == int(f(second)) + + # noinspection PyDictCreation + x = {f(first): 1, f(second): 2} + x[f(first)] = 3 + x[f(second)] = 4 + # Hashing test + assert str(x) == "{EMode.EFirstMode: 3, EMode.ESecondMode: 4}" From 18319d5598e874168b00048bf093721a8755c611 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Sat, 13 Aug 2016 02:44:56 +0200 Subject: [PATCH 5/8] Automatically install pytest from CMake Pytest is a development dependency but we can make it painless by automating the install using CMake. --- .travis.yml | 4 ++-- tests/CMakeLists.txt | 27 ++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index e74a25066..8ce8f2b6f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,7 +39,7 @@ matrix: install: - > docker exec --tty "$containerid" apt-get -y --no-install-recommends install - python2.7-dev python-scipy libeigen3-dev + python2.7-dev python-pip python-setuptools python-scipy libeigen3-dev cmake make g++ - compiler: gcc-6 services: docker @@ -48,7 +48,7 @@ matrix: install: - > docker exec --tty "$containerid" apt-get -y --no-install-recommends install - python3.5-dev python3-scipy libeigen3-dev + python3.5-dev python3-pip python3-setuptools python3-scipy libeigen3-dev cmake make g++ # Documentation build: - os: linux diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d4db9032a..dbf64c46b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -58,6 +58,31 @@ if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) endforeach() endif() +# Make sure pytest is found or try to install it if it's not found +macro(pybind11_execute_python) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -m ${ARGN} OUTPUT_QUIET ERROR_QUIET + RESULT_VARIABLE pybind11_execute_python_error) +endmacro() + +if(NOT PYBIND11_PYTEST_FOUND) + pybind11_execute_python(pytest --version --noconftest) + if(pybind11_execute_python_error) + message(STATUS "Installing pytest using pip") + pybind11_execute_python(pip install pytest) + if(pybind11_execute_python_error) + message(STATUS "Installing pytest using pip --user (fallback)") + pybind11_execute_python(pip install --user pytest) + endif() + + pybind11_execute_python(pytest --version --noconftest) + if(pybind11_execute_python_error) + message(FATAL_ERROR "Running the tests requires pytest. Please install it manually.") + endif() + endif() + + set(PYBIND11_PYTEST_FOUND TRUE CACHE INTERAL "") +endif() + # A single command to compile and run the tests -add_custom_target(pytest COMMAND ${PYTHON_EXECUTABLE} -m pytest +add_custom_target(pytest COMMAND ${PYTHON_EXECUTABLE} -m pytest -rws DEPENDS pybind11_tests WORKING_DIRECTORY ${testdir}) From ec0d38ef252a2755e41ac7343f9ed524cdc5eb39 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Sat, 13 Aug 2016 03:09:52 +0200 Subject: [PATCH 6/8] Update the docs to reflect the new test structure Test compilation instructions for Windows were changed to use the `cmake --build` command line invocation which should be easier than manually setting up using the CMake GUI and Visual Studio. --- docs/advanced.rst | 36 +++++++++++++++++----------------- docs/basics.rst | 50 +++++++++++++++++++++++------------------------ 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/docs/advanced.rst b/docs/advanced.rst index 2b78c7e80..e3bf6c777 100644 --- a/docs/advanced.rst +++ b/docs/advanced.rst @@ -102,7 +102,7 @@ C++ side, or to perform other types of customization. .. seealso:: - The file :file:`example/example-operator-overloading.cpp` contains a + The file :file:`tests/test_operator_overloading.cpp` contains a complete example that demonstrates how to work with overloaded operators in more detail. @@ -203,14 +203,14 @@ The following interactive session shows how to call them from Python. 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 Example 5. + 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:`example/example-callbacks.cpp` contains a complete example + The file :file:`tests/test_callbacks.cpp` contains a complete example that demonstrates how to work with callbacks and anonymous functions in more detail. @@ -354,7 +354,7 @@ Please take a look at the :ref:`macro_notes` before using this feature. .. seealso:: - The file :file:`example/example-virtual-functions.cpp` contains a complete + The file :file:`tests/test_virtual_functions.cpp` contains a complete example that demonstrates how to override virtual functions using pybind11 in more detail. @@ -472,7 +472,7 @@ can now create a python class that inherits from ``Dog``: .. seealso:: - See the file :file:`example-virtual-functions.cpp` for complete examples + See the file :file:`tests/test_virtual_functions.cpp` for complete examples using both the duplication and templated trampoline approaches. .. _macro_notes: @@ -556,7 +556,7 @@ out of the box with just the core :file:`pybind11/pybind11.h` header. .. seealso:: - The file :file:`example/example-python-types.cpp` contains a complete + The file :file:`tests/test_python_types.cpp` contains a complete example that demonstrates how to pass STL data types in more detail. Binding sequence data types, iterators, the slicing protocol, etc. @@ -566,7 +566,7 @@ Please refer to the supplemental example for details. .. seealso:: - The file :file:`example/example-sequences-and-iterators.cpp` contains a + 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. @@ -690,7 +690,7 @@ container: .. seealso:: - The file :file:`example/example-keep-alive.cpp` contains a complete example + The file :file:`tests/test_keep_alive.cpp` contains a complete example that demonstrates using :class:`keep_alive` in more detail. Implicit type conversions @@ -892,7 +892,7 @@ Please take a look at the :ref:`macro_notes` before using this feature. .. seealso:: - The file :file:`example/example-smart-ptr.cpp` contains a complete example + 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. @@ -1005,7 +1005,7 @@ a first shot at handling the exception). Inside the translator, ``std::rethrow_exception`` should be used within a try block to re-throw the exception. A catch clause can then use ``PyErr_SetString`` to set a Python exception as demonstrated -in :file:`example-custom-exceptions.cpp``. +in :file:`tests/test_exceptions.cpp`. This example also demonstrates how to create custom exception types with ``py::exception``. @@ -1143,7 +1143,7 @@ Please take a look at the :ref:`macro_notes` before using this feature. .. seealso:: - The file :file:`example/example-opaque-types.cpp` contains a complete + 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. @@ -1198,7 +1198,7 @@ with NumPy and SciPy. .. seealso:: - The file :file:`example/eigen.cpp` contains a complete example that + 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. Buffer protocol @@ -1326,7 +1326,7 @@ limitations), refer to the section on :ref:`eigen`. .. seealso:: - The file :file:`example/example-buffers.cpp` contains a complete example + 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 @@ -1493,7 +1493,7 @@ simply using ``vectorize``). .. seealso:: - The file :file:`example/example-numpy-vectorize.cpp` contains a complete + The file :file:`tests/test_numpy_vectorize.cpp` contains a complete example that demonstrates using :func:`vectorize` in more detail. Functions taking Python objects as arguments @@ -1557,9 +1557,9 @@ with other parameters. .. seealso:: - The file :file:`example/example-python-types.cpp` contains a complete + The file :file:`tests/test_python_types.cpp` contains a complete example that demonstrates passing native Python types in more detail. The - file :file:`example/example-arg-keywords-and-defaults.cpp` discusses usage + file :file:`tests/test_kwargs_and_defaults.cpp` discusses usage of ``args`` and ``kwargs``. Default arguments revisited @@ -1633,7 +1633,7 @@ Such functions can also be created using pybind11: /// Binding code m.def("generic", &generic); -(See ``example/example-arg-keywords-and-defaults.cpp``). The class ``py::args`` +(See ``tests/test_kwargs_and_defaults.cpp``). The class ``py::args`` derives from ``py::list`` and ``py::kwargs`` derives from ``py::dict`` Note that the ``kwargs`` argument is invalid if no keyword arguments were actually provided. Please refer to the other examples for details on how to iterate @@ -1783,7 +1783,7 @@ memory corruption and/or segmentation faults. .. seealso:: - The file :file:`example/example-pickling.cpp` contains a complete example + The file :file:`tests/test_pickling.cpp` contains a complete example that demonstrates how to pickle and unpickle types using pybind11 in more detail. diff --git a/docs/basics.rst b/docs/basics.rst index 1f40f198d..394c22beb 100644 --- a/docs/basics.rst +++ b/docs/basics.rst @@ -5,7 +5,7 @@ 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 examples, which also double as test cases. +included set of test cases. Compiling the test cases @@ -22,44 +22,42 @@ After installing the prerequisites, run .. code-block:: bash - cmake . - make -j 4 + mkdir build + cd build + cmake .. + make pytest -j 4 -followed by - -.. code-block:: bash - - make test +The last line will both compile and run the tests. Windows ------- -On Windows, use the `CMake GUI`_ to create a Visual Studio project. Note that -only the 2015 release and newer versions are supported since pybind11 relies on -various C++11 language features that break older versions of Visual Studio. -After running CMake, open the created :file:`pybind11.sln` file and perform a -release build, which will will produce a file named -:file:`Release\\example.pyd`. Copy this file to the :file:`example` directory -and run :file:`example\\run_test.py` using the targeted Python version. +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. -.. _`CMake GUI`: https://cmake.org/runningcmake +To compile and run the tests: + +.. code-block:: batch + + mkdir build + cd build + cmake .. + cmake --build . --config Release --target pytest + +This will create a Visual Studio project, compile and run the target, all from the +command line. .. Note:: - When all tests fail, make sure that - - 1. The Python binary and the testcases are compiled for the same processor - type and bitness (i.e. either **i386** or **x86_64**) - - 2. The Python binary used to run :file:`example\\run_test.py` matches the - Python version specified in the CMake GUI. This is controlled via - the ``PYTHON_EXECUTABLE`` ``PYTHON_INCLUDE_DIR``, and - ``PYTHON_LIBRARY`` variables. + 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:`example` directory, + the tutorial and look at the test cases in the :file:`tests` directory, which exercise all features of pybind11. Creating bindings for a simple function From 3b44daedf67f7b2800a9b7c7c4d45a35584c679d Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Thu, 18 Aug 2016 16:55:26 +0200 Subject: [PATCH 7/8] Rewrite eval tests to allow for simple asserts Most of the test code is left in C++ since this is the intended use case for the eval functions. --- tests/test_eval.cpp | 132 +++++++++++++++++----------------------- tests/test_eval.py | 33 +++++----- tests/test_eval_call.py | 2 +- 3 files changed, 71 insertions(+), 96 deletions(-) diff --git a/tests/test_eval.cpp b/tests/test_eval.cpp index 21098ac75..6b16e7c7b 100644 --- a/tests/test_eval.cpp +++ b/tests/test_eval.cpp @@ -11,92 +11,70 @@ #include #include "pybind11_tests.h" -void example_eval() { - py::module main_module = py::module::import("__main__"); - py::object main_namespace = main_module.attr("__dict__"); +void init_ex_eval(py::module & m) { + auto global = py::dict(py::module::import("__main__").attr("__dict__")); - bool ok = false; + m.def("test_eval_statements", [global]() { + auto local = py::dict(); + local["call_test"] = py::cpp_function([&]() -> int { + return 42; + }); - main_module.def("call_test", [&]() -> int { - ok = true; - return 42; + auto result = py::eval( + "print('Hello World!');\n" + "x = call_test();", + global, local + ); + auto x = local["x"].cast(); + + return result == py::none() && x == 42; }); - cout << "eval_statements test" << endl; + 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; + }); - auto result = py::eval( - "print('Hello World!');\n" - "x = call_test();", main_namespace); + m.def("test_eval_single_statement", []() { + auto local = py::dict(); + local["call_test"] = py::cpp_function([&]() -> int { + return 42; + }); - if (ok && result == py::none()) - cout << "eval_statements passed" << endl; - else - cout << "eval_statements failed" << endl; + auto result = py::eval("x = call_test()", py::dict(), local); + auto x = local["x"].cast(); + return result == py::none() && x == 42; + }); - cout << "eval test" << endl; + m.def("test_eval_file", [global](py::str filename) { + auto local = py::dict(); + local["y"] = py::int_(43); - py::object val = py::eval("x", main_namespace); + int val_out; + local["call_test2"] = py::cpp_function([&](int value) { val_out = value; }); - if (val.cast() == 42) - cout << "eval passed" << endl; - else - cout << "eval failed" << endl; + auto result = py::eval_file(filename, global, local); + return val_out == 43 && result == py::none(); + }); - ok = false; - cout << "eval_single_statement test" << endl; + m.def("test_eval_failure", []() { + try { + py::eval("nonsense code ..."); + } catch (py::error_already_set &) { + PyErr_Clear(); + return true; + } + return false; + }); - py::eval( - "y = call_test();", main_namespace); - - if (ok) - cout << "eval_single_statement passed" << endl; - else - cout << "eval_single_statement failed" << endl; - - cout << "eval_file test" << endl; - - int val_out; - main_module.def("call_test2", [&](int value) {val_out = value;}); - - try { - result = py::eval_file("test_eval_call.py", main_namespace); - } catch (...) { - result = py::eval_file("tests/test_eval_call.py", main_namespace); - } - - if (val_out == 42 && result == py::none()) - cout << "eval_file passed" << endl; - else - cout << "eval_file failed" << endl; - - ok = false; - cout << "eval failure test" << endl; - try { - py::eval("nonsense code ..."); - } catch (py::error_already_set &) { - PyErr_Clear(); - ok = true; - } - - if (ok) - cout << "eval failure test passed" << endl; - else - cout << "eval failure test failed" << endl; - - ok = false; - cout << "eval_file failure test" << endl; - try { - py::eval_file("nonexisting file"); - } catch (std::exception &) { - ok = true; - } - - if (ok) - cout << "eval_file failure test passed" << endl; - else - cout << "eval_file failure test failed" << endl; -} - -void init_ex_eval(py::module & m) { - m.def("example_eval", &example_eval); + m.def("test_eval_file_failure", []() { + try { + py::eval_file("non-existing file"); + } catch (std::exception &) { + return true; + } + return false; + }); } diff --git a/tests/test_eval.py b/tests/test_eval.py index 2d7611c80..8715dbadb 100644 --- a/tests/test_eval.py +++ b/tests/test_eval.py @@ -1,22 +1,19 @@ +import os -def test_eval(capture): - from pybind11_tests import example_eval +def test_evals(capture): + from pybind11_tests import (test_eval_statements, test_eval, test_eval_single_statement, + test_eval_file, test_eval_failure, test_eval_file_failure) with capture: - example_eval() - assert capture == """ - eval_statements test - Hello World! - eval_statements passed - eval test - eval passed - eval_single_statement test - eval_single_statement passed - eval_file test - eval_file passed - eval failure test - eval failure test passed - eval_file failure test - eval_file failure test passed - """ + assert test_eval_statements() + assert capture == "Hello World!" + + assert test_eval() + assert test_eval_single_statement() + + filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py") + assert test_eval_file(filename) + + assert test_eval_failure() + assert test_eval_file_failure() diff --git a/tests/test_eval_call.py b/tests/test_eval_call.py index b8a7603e9..a3349e281 100644 --- a/tests/test_eval_call.py +++ b/tests/test_eval_call.py @@ -1,4 +1,4 @@ # This file is called from 'test_eval.py' -if 'call_test2' in globals(): +if 'call_test2' in locals(): call_test2(y) From 99dbdc16e555c7fd28ad8b972bc18bc3ac67a8df Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Fri, 19 Aug 2016 13:45:36 +0200 Subject: [PATCH 8/8] Simplify more tests by replacing capture with assert --- tests/test_issues.cpp | 7 +--- tests/test_issues.py | 12 +++--- tests/test_kwargs_and_defaults.cpp | 14 ++----- tests/test_kwargs_and_defaults.py | 28 +++++--------- tests/test_virtual_functions.cpp | 28 +++++++------- tests/test_virtual_functions.py | 62 ++++++++---------------------- 6 files changed, 53 insertions(+), 98 deletions(-) diff --git a/tests/test_issues.cpp b/tests/test_issues.cpp index a0d1fd5e8..5f680ebdd 100644 --- a/tests/test_issues.cpp +++ b/tests/test_issues.cpp @@ -111,7 +111,7 @@ void init_issues(py::module &m) { }); // (no id): should not be able to pass 'None' to a reference argument - m2.def("print_element", [](ElementA &el) { std::cout << el.value() << std::endl; }); + m2.def("get_element", [](ElementA &el) { return el.value(); }); // (no id): don't cast doubles to ints m2.def("expect_float", [](float f) { return f; }); @@ -160,10 +160,7 @@ void init_issues(py::module &m) { py::class_ si(m2, "StrIssue"); si .def(py::init()) .def(py::init<>()) - .def("__str__", [](const StrIssue &si) { - std::cout << "StrIssue.__str__ called" << std::endl; - return "StrIssue[" + std::to_string(si.value()) + "]"; - }) + .def("__str__", [](const StrIssue &si) { return "StrIssue[" + std::to_string(si.value()) + "]"; }) ; // Issue #328: first member in a class can't be used in operators diff --git a/tests/test_issues.py b/tests/test_issues.py index f76813964..38a5324fa 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -60,13 +60,13 @@ def test_shared_ptr_gc(): def test_no_id(capture, msg): - from pybind11_tests.issues import print_element, expect_float, expect_int + from pybind11_tests.issues import get_element, expect_float, expect_int with pytest.raises(TypeError) as excinfo: - print_element(None) + get_element(None) assert msg(excinfo.value) == """ Incompatible function arguments. The following argument types are supported: - 1. (arg0: m.issues.ElementA) -> None + 1. (arg0: m.issues.ElementA) -> int Invoked with: None """ @@ -105,13 +105,11 @@ def test_no_id(capture, msg): """ -def test_str_issue(capture, msg): +def test_str_issue(msg): """Issue #283: __str__ called on uninitialized instance when constructor arguments invalid""" from pybind11_tests.issues import StrIssue - with capture: - assert str(StrIssue(3)) == "StrIssue[3]" - assert capture == "StrIssue.__str__ called" + assert str(StrIssue(3)) == "StrIssue[3]" with pytest.raises(TypeError) as excinfo: str(StrIssue("no", "such", "constructor")) diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 3fefc798d..349b7ea9a 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -27,18 +27,12 @@ py::object call_kw_func(py::function f) { return f(*args, **kwargs); } -void args_function(py::args args) { - for (size_t it=0; it " << item.second << std::endl; - } +py::tuple args_kwargs_function(py::args args, py::kwargs kwargs) { + return py::make_tuple(args, kwargs); } struct KWClass { diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index 735722dec..14d9c5ab8 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -12,8 +12,8 @@ def test_function_signatures(doc): assert doc(kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> str" assert doc(kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> str" assert doc(kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> str" - assert doc(args_function) == "args_function(*args) -> None" - assert doc(args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> None" + assert doc(args_function) == "args_function(*args) -> tuple" + assert doc(args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple" assert doc(KWClass.foo0) == "foo0(self: m.KWClass, arg0: int, arg1: float) -> None" assert doc(KWClass.foo1) == "foo1(self: m.KWClass, x: int, y: float) -> None" @@ -48,20 +48,12 @@ def test_named_arguments(msg): assert kw_func_udl_z(x=5) == "x=5, y=0" -def test_arg_and_kwargs(capture): +def test_arg_and_kwargs(): assert call_kw_func(kw_func2) == "x=1234, y=5678" - with capture: - args_function('arg1_value', 'arg2_value', 3) - assert capture.unordered == """ - got argument: arg1_value - got argument: arg2_value - got argument: 3 - """ - with capture: - args_kwargs_function('arg1_value', 'arg2_value', arg3='arg3_value', arg4=4) - assert capture.unordered == """ - got argument: arg1_value - got argument: arg2_value - got keyword argument: arg3 -> arg3_value - got keyword argument: arg4 -> 4 - """ + + args = 'arg1_value', 'arg2_value', 3 + assert args_function(*args) == args + + args = 'a1', 'a2' + kwargs = dict(arg3='a3', arg4=4) + assert args_kwargs_function(*args, **kwargs) == (args, kwargs) diff --git a/tests/test_virtual_functions.cpp b/tests/test_virtual_functions.cpp index 6ea7c2cfd..1e2f0edd7 100644 --- a/tests/test_virtual_functions.cpp +++ b/tests/test_virtual_functions.cpp @@ -91,7 +91,7 @@ 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); } - int get_value() const { return value; } + std::string get_value() const { return std::to_string(value); } ~Movable() { print_destroyed(this); } private: int value; @@ -102,8 +102,8 @@ public: virtual NonCopyable get_noncopyable(int a, int b) { return NonCopyable(a, b); } virtual Movable get_movable(int a, int b) = 0; - void print_nc(int a, int b) { std::cout << get_noncopyable(a, b).get_value() << std::endl; } - void print_movable(int a, int b) { std::cout << get_movable(a, b).get_value() << std::endl; } + 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 { virtual NonCopyable get_noncopyable(int a, int b) { @@ -138,9 +138,11 @@ class A_Repeat { #define A_METHODS \ public: \ virtual int unlucky_number() = 0; \ - virtual void say_something(unsigned times) { \ - for (unsigned i = 0; i < times; i++) std::cout << "hi"; \ - std::cout << std::endl; \ + virtual std::string say_something(unsigned times) { \ + std::string s = ""; \ + for (unsigned i = 0; i < times; ++i) \ + s += "hi"; \ + return s; \ } A_METHODS }; @@ -148,8 +150,8 @@ class B_Repeat : public A_Repeat { #define B_METHODS \ public: \ int unlucky_number() override { return 13; } \ - void say_something(unsigned times) override { \ - std::cout << "B says hi " << times << " times" << std::endl; \ + 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 @@ -178,27 +180,27 @@ class PyA_Repeat : public A_Repeat { public: using A_Repeat::A_Repeat; int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, A_Repeat, unlucky_number, ); } - void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, A_Repeat, say_something, times); } + 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, ); } - void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, B_Repeat, say_something, times); } + 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, ); } - void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, C_Repeat, say_something, times); } + 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, ); } - void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, D_Repeat, say_something, times); } + 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, ); } }; @@ -221,7 +223,7 @@ class PyA_Tpl : public Base { public: using Base::Base; // Inherit constructors int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, Base, unlucky_number, ); } - void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, Base, say_something, times); } + std::string say_something(unsigned times) override { PYBIND11_OVERLOAD(std::string, Base, say_something, times); } }; template class PyB_Tpl : public PyA_Tpl { diff --git a/tests/test_virtual_functions.py b/tests/test_virtual_functions.py index 27b0222af..1388b1ae2 100644 --- a/tests/test_virtual_functions.py +++ b/tests/test_virtual_functions.py @@ -54,7 +54,7 @@ def test_override(capture, msg): assert cstats.move_constructions >= 0 -def test_inheriting_repeat(capture): +def test_inheriting_repeat(): from pybind11_tests import A_Repeat, B_Repeat, C_Repeat, D_Repeat, A_Tpl, B_Tpl, C_Tpl, D_Tpl class VI_AR(A_Repeat): @@ -66,28 +66,20 @@ def test_inheriting_repeat(capture): return 999 obj = VI_AR() - with capture: - obj.say_something(3) - assert capture == "hihihi" + assert obj.say_something(3) == "hihihi" assert obj.unlucky_number() == 99 obj = VI_AT() - with capture: - obj.say_something(3) - assert capture == "hihihi" + assert obj.say_something(3) == "hihihi" assert obj.unlucky_number() == 999 for obj in [B_Repeat(), B_Tpl()]: - with capture: - obj.say_something(3) - assert capture == "B says hi 3 times" + assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 13 assert obj.lucky_number() == 7.0 for obj in [C_Repeat(), C_Tpl()]: - with capture: - obj.say_something(3) - assert capture == "B says hi 3 times" + assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 4444 assert obj.lucky_number() == 888.0 @@ -96,9 +88,7 @@ def test_inheriting_repeat(capture): return C_Repeat.lucky_number(self) + 1.25 obj = VI_CR() - with capture: - obj.say_something(3) - assert capture == "B says hi 3 times" + assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 4444 assert obj.lucky_number() == 889.25 @@ -106,9 +96,7 @@ def test_inheriting_repeat(capture): pass obj = VI_CT() - with capture: - obj.say_something(3) - assert capture == "B says hi 3 times" + assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 4444 assert obj.lucky_number() == 888.0 @@ -117,9 +105,7 @@ def test_inheriting_repeat(capture): return VI_CR.lucky_number(self) * 10 obj = VI_CCR() - with capture: - obj.say_something(3) - assert capture == "B says hi 3 times" + assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 4444 assert obj.lucky_number() == 8892.5 @@ -128,9 +114,7 @@ def test_inheriting_repeat(capture): return VI_CT.lucky_number(self) * 1000 obj = VI_CCT() - with capture: - obj.say_something(3) - assert capture == "B says hi 3 times" + assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 4444 assert obj.lucky_number() == 888000.0 @@ -142,22 +126,18 @@ def test_inheriting_repeat(capture): return 42.0 for obj in [D_Repeat(), D_Tpl()]: - with capture: - obj.say_something(3) - assert capture == "B says hi 3 times" + assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 4444 assert obj.lucky_number() == 888.0 obj = VI_DR() - with capture: - obj.say_something(3) - assert capture == "B says hi 3 times" + assert obj.say_something(3) == "B says hi 3 times" assert obj.unlucky_number() == 123 assert obj.lucky_number() == 42.0 class VI_DT(D_Tpl): def say_something(self, times): - print("VI_DT says:" + (' quack' * times)) + return "VI_DT says:" + (' quack' * times) def unlucky_number(self): return 1234 @@ -166,14 +146,12 @@ def test_inheriting_repeat(capture): return -4.25 obj = VI_DT() - with capture: - obj.say_something(3) - assert capture == "VI_DT says: quack quack quack" + assert obj.say_something(3) == "VI_DT says: quack quack quack" assert obj.unlucky_number() == 1234 assert obj.lucky_number() == -4.25 -def test_move_support(capture): +def test_move_support(): from pybind11_tests import NCVirt, NonCopyable, Movable class NCVirtExt(NCVirt): @@ -198,16 +176,10 @@ def test_move_support(capture): return Movable(a, b) ncv1 = NCVirtExt() - with capture: - ncv1.print_nc(2, 3) - assert capture == "36" - with capture: - ncv1.print_movable(4, 5) - assert capture == "9" + assert ncv1.print_nc(2, 3) == "36" + assert ncv1.print_movable(4, 5) == "9" ncv2 = NCVirtExt2() - with capture: - ncv2.print_movable(7, 7) - assert capture == "14" + 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)