diff --git a/.appveyor.yml b/.appveyor.yml index 12a51b8f..688a92ef 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 d1676c9b..ab667585 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 abdb4bb4..e74a2506 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 450f651c..cd2c4cb2 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 2cc8f832..00000000 --- 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 18c8a453..00000000 --- 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 626c6048..00000000 --- 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 2536782f..00000000 --- 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 d3ca9976..00000000 --- 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 185e6d3c..00000000 --- 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 1e02ffd9..00000000 --- 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 68a485a7..00000000 --- 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 c6f8f531..00000000 --- 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 852902f0..00000000 --- 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 48056311..00000000 --- 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 d4ee5f85..00000000 --- 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 a0489234..00000000 --- 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 eec10c3b..00000000 --- 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 db350bde..00000000 --- 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 db96fd3f..00000000 --- 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 b4bcb655..00000000 --- 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 96003367..00000000 --- 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 187ad534..00000000 --- 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 775aff41..00000000 --- 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 8f2a5243..00000000 --- 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 338539e7..00000000 --- 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 91c075c7..00000000 --- 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 1ca07834..00000000 --- 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 06185914..00000000 --- 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 4f07ce44..00000000 --- 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 10356346..00000000 --- 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 12b87d35..00000000 --- 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 4253a75a..00000000 --- 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 82365312..00000000 --- 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 1810d3e2..00000000 --- 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 d804973a..00000000 --- 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 11b89bfe..00000000 --- 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 d89acb65..00000000 --- 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 764a5276..00000000 --- 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 d658fba1..00000000 --- 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 fe23e113..00000000 --- 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 52ffa8bf..00000000 --- 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 feae3070..00000000 --- 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 cc271f3a..00000000 --- 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 d67539b6..00000000 --- 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 5927e0d6..00000000 --- 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 facdafa8..00000000 --- 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 1d5d0fbc..00000000 --- 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 2785c8ea..00000000 --- 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 07465bb6..425e6c57 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 00000000..f4339295 --- /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 00000000..5641392d --- /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 0f505c14..757ebf90 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 4e6fa6e6..99a6916c 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 bd6ac9b3..507ede82 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 fa3178b5..5a4dc67d 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 00000000..f0ea964d --- /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 a5a3b833..80a0d0ea 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 00000000..3f70e87c --- /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 d7f8ad17..1977a0ae 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 00000000..119965bf --- /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 c88bee2b..42bb969f 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 00000000..43cc2fb7 --- /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 f6de893d..21098ac7 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 00000000..2d7611c8 --- /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 00000000..b8a7603e --- /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 41d51d84..492308fa 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 00000000..24f9769b --- /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 082978b4..b70ea77a 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 00000000..a7a9778c --- /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 7dfa9f5a..085dff90 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 00000000..0ab2e360 --- /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 c2aeaeef..25f852ea 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 00000000..c83d5d28 --- /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 9c58605f..28162461 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 00000000..0d785a42 --- /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 9056e3cb..9317d780 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 00000000..9340e6fb --- /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 bd25af17..3d96df61 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 00000000..3deb02e3 --- /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 e5292bba..9afd342b 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 00000000..783f6ad2 --- /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 8780d28f..a36b7d01 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 00000000..6fcf8081 --- /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 2c24f354..0ede5e32 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 00000000..5c2ca924 --- /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 f6b9967b..b84a5b84 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 00000000..e0d42391 --- /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 b89f78a3..4a484525 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 00000000..f6e4c04f --- /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 55066a81..39e43eb6 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 00000000..3738d41c --- /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 791a9292..a92c6bf6 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 00000000..a35dc584 --- /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 c4dd2c8d..46c83b37 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 00000000..ffc407db --- /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 d02ed09f..e2a44e19 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 00000000..2aaaf3aa --- /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 b24925f5..6ea7c2cf 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 00000000..f2efb6be --- /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