Commit faec30c4 authored by Wenzel Jakob's avatar Wenzel Jakob Committed by GitHub
Browse files

Merge pull request #321 from dean0x7d/pytest

Port test suite to pytest
parents bf099587 99dbdc16
/*
example/example-buffers.cpp -- supporting Pythons' buffer protocol
tests/test_buffers.cpp -- supporting Pythons' buffer protocol
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
......@@ -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:
......
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
/*
example/example-callbacks.cpp -- callbacks
tests/test_callbacks.cpp -- callbacks
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
......@@ -7,23 +7,21 @@
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 <pybind11/functional.h>
bool test_callback1(py::object func) {
func();
return false;
py::object test_callback1(py::object func) {
return func();
}
int test_callback2(py::object func) {
py::object result = func("Hello", 'x', true, 5);
return result.cast<int>();
py::tuple test_callback2(py::object func) {
return func("Hello", 'x', true, 5);
}
void test_callback3(const std::function<int(int)> &func) {
cout << "func(43) = " << func(43)<< std::endl;
std::string test_callback3(const std::function<int(int)> &func) {
return "func(43) = " + std::to_string(func(43));
}
std::function<int(int)> test_callback4() {
......@@ -37,27 +35,24 @@ py::cpp_function test_callback5() {
int dummy_function(int i) { return i + 1; }
int dummy_function2(int i, int j) { return i + j; }
std::function<int(int)> roundtrip(std::function<int(int)> f) {
if (!f)
std::cout << "roundtrip (got None).." << std::endl;
else
std::cout << "roundtrip.." << std::endl;
std::function<int(int)> roundtrip(std::function<int(int)> f, bool expect_none = false) {
if (expect_none && f) {
throw std::runtime_error("Expected None to be converted to empty std::function");
}
return f;
}
void test_dummy_function(const std::function<int(int)> &f) {
std::string test_dummy_function(const std::function<int(int)> &f) {
using fn_type = int (*)(int);
auto result = f.target<fn_type>();
if (!result) {
std::cout << "could not convert to a function pointer." << std::endl;
auto r = f(1);
std::cout << "eval(1) = " << r << std::endl;
return "can't convert to function pointer: eval(1) = " + std::to_string(r);
} else if (*result == dummy_function) {
std::cout << "argument matches dummy_function" << std::endl;
auto r = (*result)(1);
std::cout << "eval(1) = " << r << std::endl;
return "matches dummy_function: eval(1) = " + std::to_string(r);
} else {
std::cout << "argument does NOT match dummy_function. This should never happen!" << std::endl;
return "argument does NOT match dummy_function. This should never happen!";
}
}
......@@ -96,7 +91,7 @@ void init_ex_callbacks(py::module &m) {
/* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */
m.def("dummy_function", &dummy_function);
m.def("dummy_function2", &dummy_function2);
m.def("roundtrip", &roundtrip);
m.def("roundtrip", &roundtrip, py::arg("f"), py::arg("expect_none")=false);
m.def("test_dummy_function", &test_dummy_function);
// Export the payload constructor statistics for testing purposes:
m.def("payload_cstats", &ConstructorStats::get<Payload>);
......
import pytest
def test_callbacks():
from functools import partial
from pybind11_tests import (test_callback1, test_callback2, test_callback3,
test_callback4, test_callback5)
def func1():
return "func1"
def func2(a, b, c, d):
return "func2", a, b, c, d
def func3(a):
return "func3({})".format(a)
assert test_callback1(func1) == "func1"
assert test_callback2(func2) == ("func2", "Hello", "x", True, 5)
assert test_callback1(partial(func2, 1, 2, 3, 4)) == ("func2", 1, 2, 3, 4)
assert test_callback1(partial(func3, "partial")) == "func3(partial)"
assert test_callback3(lambda i: i + 1) == "func(43) = 44"
f = test_callback4()
assert f(43) == 44
f = test_callback5()
assert f(number=43) == 44
def test_lambda_closure_cleanup():
from pybind11_tests import test_cleanup, payload_cstats
test_cleanup()
cstats = payload_cstats()
assert cstats.alive() == 0
assert cstats.copy_constructions == 1
assert cstats.move_constructions >= 1
def test_cpp_function_roundtrip():
"""Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer"""
from pybind11_tests import dummy_function, dummy_function2, test_dummy_function, roundtrip
assert test_dummy_function(dummy_function) == "matches dummy_function: eval(1) = 2"
assert test_dummy_function(roundtrip(dummy_function)) == "matches dummy_function: eval(1) = 2"
assert roundtrip(None, expect_none=True) is None
assert test_dummy_function(lambda x: x + 2) == "can't convert to function pointer: eval(1) = 3"
with pytest.raises(TypeError) as excinfo:
test_dummy_function(dummy_function2)
assert "Incompatible function arguments" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo:
test_dummy_function(lambda x, y: x + y)
assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument",
"takes exactly 2 arguments"))
def test_function_signatures(doc):
from pybind11_tests import test_callback3, test_callback4
assert doc(test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str"
assert doc(test_callback4) == "test_callback4() -> Callable[[int], int]"
/*
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 <wenzel.jakob@epfl.ch>
......@@ -7,47 +7,20 @@
BSD-style license that can be found in the LICENSE file.
*/
#include "example.h"
#include "pybind11_tests.h"
enum EMyEnumeration {
EFirstEntry = 1,
ESecondEntry
};
enum MyEnum { EFirstEntry = 1, ESecondEntry };
enum class ECMyEnum {
Two = 2,
Three
};
class ExampleWithEnum {
public:
enum EMode {
EFirstMode = 1,
ESecondMode
};
static EMode test_function(EMode mode) {
std::cout << "ExampleWithEnum::test_function(enum=" << mode << ")" << std::endl;
return mode;
}
};
bool test_function1() {
std::cout << "test_function()" << std::endl;
return false;
std::string test_function1() {
return "test_function()";
}
void test_function2(EMyEnumeration k) {
std::cout << "test_function(enum=" << k << ")" << std::endl;
std::string test_function2(MyEnum k) {
return "test_function(enum=" + std::to_string(k) + ")";
}
float test_function3(int i) {
std::cout << "test_function(" << i << ")" << std::endl;
return (float) i / 2.f;
}
void test_ecenum(ECMyEnum z) {
std::cout << "test_ecenum(ECMyEnum::" << (z == ECMyEnum::Two ? "Two" : "Three") << ")" << std::endl;
std::string test_function3(int i) {
return "test_function(" + std::to_string(i) + ")";
}
py::bytes return_bytes() {
......@@ -55,36 +28,28 @@ py::bytes return_bytes() {
return std::string(data, 4);
}
void print_bytes(py::bytes bytes) {
std::string value = (std::string) bytes;
for (size_t i = 0; i < value.length(); ++i)
std::cout << "bytes[" << i << "]=" << (int) value[i] << std::endl;
std::string print_bytes(py::bytes bytes) {
std::string ret = "bytes[";
const auto value = static_cast<std::string>(bytes);
for (size_t i = 0; i < value.length(); ++i) {
ret += std::to_string(static_cast<int>(value[i])) + " ";
}
ret.back() = ']';
return ret;
}
void init_ex_constants_and_functions(py::module &m) {
m.attr("some_constant") = py::int_(14);
m.def("test_function", &test_function1);
m.def("test_function", &test_function2);
m.def("test_function", &test_function3);
m.def("test_ecenum", &test_ecenum);
m.attr("some_constant") = py::int_(14);
py::enum_<EMyEnumeration>(m, "EMyEnumeration")
py::enum_<MyEnum>(m, "MyEnum")
.value("EFirstEntry", EFirstEntry)
.value("ESecondEntry", ESecondEntry)
.export_values();
py::enum_<ECMyEnum>(m, "ECMyEnum")
.value("Two", ECMyEnum::Two)
.value("Three", ECMyEnum::Three)
;
py::class_<ExampleWithEnum> exenum_class(m, "ExampleWithEnum");
exenum_class.def_static("test_function", &ExampleWithEnum::test_function);
py::enum_<ExampleWithEnum::EMode>(exenum_class, "EMode")
.value("EFirstMode", ExampleWithEnum::EFirstMode)
.value("ESecondMode", ExampleWithEnum::ESecondMode)
.export_values();
m.def("return_bytes", &return_bytes);
m.def("print_bytes", &print_bytes);
}
def test_constants():
from pybind11_tests import some_constant
assert some_constant == 14
def test_function_overloading():
from pybind11_tests import MyEnum, test_function
assert test_function() == "test_function()"
assert test_function(7) == "test_function(7)"
assert test_function(MyEnum.EFirstEntry) == "test_function(enum=1)"
assert test_function(MyEnum.ESecondEntry) == "test_function(enum=2)"
def test_bytes():
from pybind11_tests import return_bytes, print_bytes
assert print_bytes(return_bytes()) == "bytes[1 0 2 0]"
/*
example/eigen.cpp -- automatic conversion of Eigen types
tests/eigen.cpp -- automatic conversion of Eigen types
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
......@@ -7,7 +7,7 @@
BSD-style license that can be found in the LICENSE file.
*/
#include "example.h"
#include "pybind11_tests.h"
#include <pybind11/eigen.h>
#include <Eigen/Cholesky>
......
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]"
/*
tests/test_enums.cpp -- enumerations
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#include "pybind11_tests.h"
enum UnscopedEnum {
EOne = 1,
ETwo
};
enum class ScopedEnum {
Two = 2,
Three
};
class ClassWithUnscopedEnum {
public:
enum EMode {
EFirstMode = 1,
ESecondMode
};
static EMode test_function(EMode mode) {
return mode;
}
};
std::string test_scoped_enum(ScopedEnum z) {
return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three");
}
void init_ex_enum(py::module &m) {
m.def("test_scoped_enum", &test_scoped_enum);
py::enum_<UnscopedEnum>(m, "UnscopedEnum")
.value("EOne", EOne)
.value("ETwo", ETwo)
.export_values();
py::enum_<ScopedEnum>(m, "ScopedEnum")
.value("Two", ScopedEnum::Two)
.value("Three", ScopedEnum::Three)
;
py::class_<ClassWithUnscopedEnum> exenum_class(m, "ClassWithUnscopedEnum");
exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function);
py::enum_<ClassWithUnscopedEnum::EMode>(exenum_class, "EMode")
.value("EFirstMode", ClassWithUnscopedEnum::EFirstMode)
.value("ESecondMode", ClassWithUnscopedEnum::ESecondMode)
.export_values();
}
import pytest
def test_unscoped_enum():
from pybind11_tests import UnscopedEnum, EOne
assert str(UnscopedEnum.EOne) == "UnscopedEnum.EOne"
assert str(UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"
assert str(EOne) == "UnscopedEnum.EOne"
# no TypeError exception for unscoped enum ==/!= int comparisons
y = UnscopedEnum.ETwo
assert y == 2
assert y != 3
assert int(UnscopedEnum.ETwo) == 2
assert str(UnscopedEnum(2)) == "UnscopedEnum.ETwo"
def test_scoped_enum():
from pybind11_tests import ScopedEnum, test_scoped_enum
assert test_scoped_enum(ScopedEnum.Three) == "ScopedEnum::Three"
z = ScopedEnum.Two
assert test_scoped_enum(z) == "ScopedEnum::Two"
# expected TypeError exceptions for scoped enum ==/!= int comparisons
with pytest.raises(TypeError):
assert z == 2
with pytest.raises(TypeError):
assert z != 3
def test_implicit_conversion():
from pybind11_tests import ClassWithUnscopedEnum
assert str(ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode"
assert str(ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode"
f = ClassWithUnscopedEnum.test_function
first = ClassWithUnscopedEnum.EFirstMode
second = ClassWithUnscopedEnum.ESecondMode
assert f(first) == 1
assert f(first) == f(first)
assert not f(first) != f(first)
assert f(first) != f(second)
assert not f(first) == f(second)
assert f(first) == int(f(first))
assert not f(first) != int(f(first))
assert f(first) != int(f(second))
assert not f(first) == int(f(second))
# noinspection PyDictCreation
x = {f(first): 1, f(second): 2}
x[f(first)] = 3
x[f(second)] = 4
# Hashing test
assert str(x) == "{EMode.EFirstMode: 3, EMode.ESecondMode: 4}"
/*
tests/test_eval.cpp -- Usage of eval() and eval_file()
Copyright (c) 2016 Klemens D. Morgenstern
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#include <pybind11/eval.h>
#include "pybind11_tests.h"
void init_ex_eval(py::module & m) {
auto global = py::dict(py::module::import("__main__").attr("__dict__"));
m.def("test_eval_statements", [global]() {
auto local = py::dict();
local["call_test"] = py::cpp_function([&]() -> int {
return 42;
});
auto result = py::eval<py::eval_statements>(
"print('Hello World!');\n"
"x = call_test();",
global, local
);
auto x = local["x"].cast<int>();
return result == py::none() && x == 42;
});
m.def("test_eval", [global]() {
auto local = py::dict();
local["x"] = py::int_(42);
auto x = py::eval("x", global, local);
return x.cast<int>() == 42;
});
m.def("test_eval_single_statement", []() {
auto local = py::dict();
local["call_test"] = py::cpp_function([&]() -> int {
return 42;
});
auto result = py::eval<py::eval_single_statement>("x = call_test()", py::dict(), local);
auto x = local["x"].cast<int>();
return result == py::none() && x == 42;
});
m.def("test_eval_file", [global](py::str filename) {
auto local = py::dict();
local["y"] = py::int_(43);
int val_out;
local["call_test2"] = py::cpp_function([&](int value) { val_out = value; });
auto result = py::eval_file(filename, global, local);
return val_out == 43 && result == py::none();
});
m.def("test_eval_failure", []() {
try {
py::eval("nonsense code ...");
} catch (py::error_already_set &) {
PyErr_Clear();
return true;
}
return false;
});
m.def("test_eval_file_failure", []() {
try {
py::eval_file("non-existing file");
} catch (std::exception &) {
return true;
}
return false;
});
}
import os
def test_evals(capture):
from pybind11_tests import (test_eval_statements, test_eval, test_eval_single_statement,
test_eval_file, test_eval_failure, test_eval_file_failure)
with capture:
assert test_eval_statements()
assert capture == "Hello World!"
assert test_eval()
assert test_eval_single_statement()
filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py")
assert test_eval_file(filename)
assert test_eval_failure()
assert test_eval_file_failure()
# This file is called from 'test_eval.py'
if 'call_test2' in locals():
call_test2(y)
/*
example/example-custom-exceptions.cpp -- exception translation
tests/test_custom-exceptions.cpp -- exception translation
Copyright (c) 2016 Pim Schellart <P.Schellart@princeton.edu>
......@@ -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 {
......
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"
/*
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 <wenzel.jakob@epfl.ch>
......@@ -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:
......@@ -23,7 +23,7 @@ private:
class Dog : public Pet {
public:
Dog(const std::string &name) : Pet(name, "dog") {}
void bark() const { std::cout << "Woof!" << std::endl; }
std::string bark() const { return "Woof!"; }
};
class Rabbit : public Pet {
......@@ -31,12 +31,12 @@ public:
Rabbit(const std::string &name) : Pet(name, "parrot") {}
};
void pet_print(const Pet &pet) {
std::cout << pet.name() + " is a " + pet.species() << std::endl;
std::string pet_name_species(const Pet &pet) {
return pet.name() + " is a " + pet.species();
}
void dog_bark(const Dog &dog) {
dog.bark();
std::string dog_bark(const Dog &dog) {
return dog.bark();
}
......@@ -59,7 +59,7 @@ void init_ex_inheritance(py::module &m) {
py::class_<Rabbit>(m, "Rabbit", py::base<Pet>())
.def(py::init<std::string>());
m.def("pet_print", pet_print);
m.def("pet_name_species", pet_name_species);
m.def("dog_bark", dog_bark);
py::class_<BaseClass>(m, "BaseClass").def(py::init<>());
......
import pytest
def test_inheritance(msg):
from pybind11_tests import Pet, Dog, Rabbit, dog_bark, pet_name_species
roger = Rabbit('Rabbit')
assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
assert pet_name_species(roger) == "Rabbit is a parrot"
polly = Pet('Polly', 'parrot')
assert polly.name() + " is a " + polly.species() == "Polly is a parrot"
assert pet_name_species(polly) == "Polly is a parrot"
molly = Dog('Molly')
assert molly.name() + " is a " + molly.species() == "Molly is a dog"
assert pet_name_species(molly) == "Molly is a dog"
assert dog_bark(molly) == "Woof!"
with pytest.raises(TypeError) as excinfo:
dog_bark(polly)
assert msg(excinfo.value) == """
Incompatible function arguments. The following argument types are supported:
1. (arg0: m.Dog) -> str
Invoked with: <m.Pet object at 0>
"""
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"
/*
example/issues.cpp -- collection of testcases for miscellaneous issues
tests/test_issues.cpp -- collection of testcases for miscellaneous issues
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
......@@ -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 <pybind11/stl.h>
#include <pybind11/operators.h>
......@@ -34,19 +34,20 @@ void init_issues(py::module &m) {
#endif
// #137: const char* isn't handled properly
m2.def("print_cchar", [](const char *string) { std::cout << string << std::endl; });
m2.def("print_cchar", [](const char *s) { return std::string(s); });
// #150: char bindings broken
m2.def("print_char", [](char c) { std::cout << c << std::endl; });
m2.def("print_char", [](char c) { return std::string(1, c); });
// #159: virtual function dispatch has problems with similar-named functions
struct Base { virtual void dispatch(void) const {
struct Base { virtual std::string dispatch() const {
/* for some reason MSVC2015 can't compile this if the function is pure virtual */
return {};
}; };
struct DispatchIssue : Base {
virtual void dispatch(void) const {
PYBIND11_OVERLOAD_PURE(void, Base, dispatch, /* no arguments */);
virtual std::string dispatch() const {
PYBIND11_OVERLOAD_PURE(std::string, Base, dispatch, /* no arguments */);
}
};
......@@ -54,7 +55,7 @@ void init_issues(py::module &m) {
.def(py::init<>())
.def("dispatch", &Base::dispatch);
m2.def("dispatch_issue_go", [](const Base * b) { b->dispatch(); });
m2.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); });
struct Placeholder { int i; Placeholder(int i) : i(i) { } };
......@@ -110,7 +111,7 @@ void init_issues(py::module &m) {
});
// (no id): should not be able to pass 'None' to a reference argument
m2.def("print_element", [](ElementA &el) { std::cout << el.value() << std::endl; });
m2.def("get_element", [](ElementA &el) { return el.value(); });
// (no id): don't cast doubles to ints
m2.def("expect_float", [](float f) { return f; });
......@@ -159,10 +160,7 @@ void init_issues(py::module &m) {
py::class_<StrIssue> si(m2, "StrIssue");
si .def(py::init<int>())
.def(py::init<>())
.def("__str__", [](const StrIssue &si) {
std::cout << "StrIssue.__str__ called" << std::endl;
return "StrIssue[" + std::to_string(si.value()) + "]";
})
.def("__str__", [](const StrIssue &si) { return "StrIssue[" + std::to_string(si.value()) + "]"; })
;
// Issue #328: first member in a class can't be used in operators
......@@ -171,7 +169,7 @@ void init_issues(py::module &m) {
.def("as_base", [](NestA &a) -> NestABase& { return (NestABase&) a; }, py::return_value_policy::reference_internal);
py::class_<NestB>(m2, "NestB").def(py::init<>()).def(py::self -= int()).def_readwrite("a", &NestB::a);
py::class_<NestC>(m2, "NestC").def(py::init<>()).def(py::self *= int()).def_readwrite("b", &NestC::b);
m2.def("print_NestA", [](const NestA &a) { std::cout << a.value << std::endl; });
m2.def("print_NestB", [](const NestB &b) { std::cout << b.value << std::endl; });
m2.def("print_NestC", [](const NestC &c) { std::cout << c.value << std::endl; });
m2.def("get_NestA", [](const NestA &a) { return a.value; });
m2.def("get_NestB", [](const NestB &b) { return b.value; });
m2.def("get_NestC", [](const NestC &c) { return c.value; });
}
import pytest
import gc
def test_regressions():
from pybind11_tests.issues import print_cchar, print_char
# #137: const char* isn't handled properly
assert print_cchar("const char *") == "const char *"
# #150: char bindings broken
assert print_char("c") == "c"
def test_dispatch_issue(msg):
"""#159: virtual function dispatch has problems with similar-named functions"""
from pybind11_tests.issues import DispatchIssue, dispatch_issue_go
class PyClass1(DispatchIssue):
def dispatch(self):
return "Yay.."
class PyClass2(DispatchIssue):
def dispatch(self):
with pytest.raises(RuntimeError) as excinfo:
super(PyClass2, self).dispatch()
assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"'
p = PyClass1()
return dispatch_issue_go(p)
b = PyClass2()
assert dispatch_issue_go(b) == "Yay.."
def test_reference_wrapper():
"""#171: Can't return reference wrappers (or STL data structures containing them)"""
from pybind11_tests.issues import Placeholder, return_vec_of_reference_wrapper
assert str(return_vec_of_reference_wrapper(Placeholder(4))) == \
"[Placeholder[1], Placeholder[2], Placeholder[3], Placeholder[4]]"
def test_iterator_passthrough():
"""#181: iterator passthrough did not compile"""
from pybind11_tests.issues import iterator_passthrough
assert list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15]))) == [3, 5, 7, 9, 11, 13, 15]
def test_shared_ptr_gc():
"""// #187: issue involving std::shared_ptr<> return value policy & garbage collection"""
from pybind11_tests.issues import ElementList, ElementA
el = ElementList()
for i in range(10):
el.add(ElementA(i))
gc.collect()
for i, v in enumerate(el.get()):
assert i == v.value()
def test_no_id(capture, msg):
from pybind11_tests.issues import get_element, expect_float, expect_int
with pytest.raises(TypeError) as excinfo:
get_element(None)
assert msg(excinfo.value) == """
Incompatible function arguments. The following argument types are supported:
1. (arg0: m.issues.ElementA) -> int
Invoked with: None
"""
with pytest.raises(TypeError) as excinfo:
expect_int(5.2)
assert msg(excinfo.value) == """
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(msg):
"""Issue #283: __str__ called on uninitialized instance when constructor arguments invalid"""
from pybind11_tests.issues import StrIssue
assert str(StrIssue(3)) == "StrIssue[3]"
with pytest.raises(TypeError) as excinfo:
str(StrIssue("no", "such", "constructor"))
assert msg(excinfo.value) == """
Incompatible constructor arguments. The following argument types are supported:
1. m.issues.StrIssue(arg0: int)
2. m.issues.StrIssue()
Invoked with: no, such, constructor
"""
def test_nested():
""" #328: first member in a class can't be used in operators"""
from pybind11_tests.issues import NestA, NestB, NestC, get_NestA, get_NestB, get_NestC
a = NestA()
b = NestB()
c = NestC()
a += 10
assert get_NestA(a) == 13
b.a += 100
assert get_NestA(b.a) == 103
c.b.a += 1000
assert get_NestA(c.b.a) == 1003
b -= 1
assert get_NestB(b) == 3
c.b -= 3
assert get_NestB(c.b) == 1
c *= 7
assert get_NestC(c) == 35
abase = a.as_base()
assert abase.value == -2
a.as_base().value += 44
assert abase.value == 42
assert c.b.a.as_base().value == -2
c.b.a.as_base().value += 44
assert c.b.a.as_base().value == 42
del c
gc.collect()
del a # Should't delete while abase is still alive
gc.collect()
assert abase.value == 42
del abase, b
gc.collect()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment