Commit 391c7544 authored by Jason Rhinelander's avatar Jason Rhinelander
Browse files

Update all remaining tests to new test styles

This udpates all the remaining tests to the new test suite code and
comment styles started in #898.  For the most part, the test coverage
here is unchanged, with a few minor exceptions as noted below.

- test_constants_and_functions: this adds more overload tests with
  overloads with different number of arguments for more comprehensive
  overload_cast testing.  The test style conversion broke the overload
  tests under MSVC 2015, prompting the additional tests while looking
  for a workaround.

- test_eigen: this dropped the unused functions `get_cm_corners` and
  `get_cm_corners_const`--these same tests were duplicates of the same
  things provided (and used) via ReturnTester methods.

- test_opaque_types: this test had a hidden dependence on ExampleMandA
  which is now fixed by using the global UserType which suffices for the
  relevant test.

- test_methods_and_attributes: this required some additions to UserType
  to make it usable as a replacement for the test's previous SimpleType:
  UserType gained a value mutator, and the `value` property is not
  mutable (it was previously readonly).  Some overload tests were also
  added to better test overload_cast (as described above).

- test_numpy_array: removed the untemplated mutate_data/mutate_data_t:
  the templated versions with an empty parameter pack expand to the same
  thing.

- test_stl: this was already mostly in the new style; this just tweaks
  things a bit, localizing a class, and adding some missing
  `// test_whatever` comments.

- test_virtual_functions: like `test_stl`, this was mostly in the new
  test style already, but needed some `// test_whatever` comments.
  This commit also moves the inherited virtual example code to the end
  of the file, after the main set of tests (since it is less important
  than the other tests, and rather length); it also got renamed to
  `test_inherited_virtuals` (from `test_inheriting_repeat`) because it
  tests both inherited virtual approaches, not just the repeat approach.
parent 9866a0f9
...@@ -9,56 +9,54 @@ ...@@ -9,56 +9,54 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
enum UnscopedEnum { TEST_SUBMODULE(enums, m) {
EOne = 1, // test_unscoped_enum
ETwo enum UnscopedEnum {
}; EOne = 1,
ETwo
enum class ScopedEnum {
Two = 2,
Three
};
enum Flags {
Read = 4,
Write = 2,
Execute = 1
};
class ClassWithUnscopedEnum {
public:
enum EMode {
EFirstMode = 1,
ESecondMode
}; };
static EMode test_function(EMode mode) {
return mode;
}
};
std::string test_scoped_enum(ScopedEnum z) {
return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three");
}
test_initializer enums([](py::module &m) {
m.def("test_scoped_enum", &test_scoped_enum);
py::enum_<UnscopedEnum>(m, "UnscopedEnum", py::arithmetic()) py::enum_<UnscopedEnum>(m, "UnscopedEnum", py::arithmetic())
.value("EOne", EOne) .value("EOne", EOne)
.value("ETwo", ETwo) .value("ETwo", ETwo)
.export_values(); .export_values();
// test_scoped_enum
enum class ScopedEnum {
Two = 2,
Three
};
py::enum_<ScopedEnum>(m, "ScopedEnum", py::arithmetic()) py::enum_<ScopedEnum>(m, "ScopedEnum", py::arithmetic())
.value("Two", ScopedEnum::Two) .value("Two", ScopedEnum::Two)
.value("Three", ScopedEnum::Three); .value("Three", ScopedEnum::Three);
m.def("test_scoped_enum", [](ScopedEnum z) {
return "ScopedEnum::" + std::string(z == ScopedEnum::Two ? "Two" : "Three");
});
// test_binary_operators
enum Flags {
Read = 4,
Write = 2,
Execute = 1
};
py::enum_<Flags>(m, "Flags", py::arithmetic()) py::enum_<Flags>(m, "Flags", py::arithmetic())
.value("Read", Flags::Read) .value("Read", Flags::Read)
.value("Write", Flags::Write) .value("Write", Flags::Write)
.value("Execute", Flags::Execute) .value("Execute", Flags::Execute)
.export_values(); .export_values();
// test_implicit_conversion
class ClassWithUnscopedEnum {
public:
enum EMode {
EFirstMode = 1,
ESecondMode
};
static EMode test_function(EMode mode) {
return mode;
}
};
py::class_<ClassWithUnscopedEnum> exenum_class(m, "ClassWithUnscopedEnum"); py::class_<ClassWithUnscopedEnum> exenum_class(m, "ClassWithUnscopedEnum");
exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function); exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function);
py::enum_<ClassWithUnscopedEnum::EMode>(exenum_class, "EMode") py::enum_<ClassWithUnscopedEnum::EMode>(exenum_class, "EMode")
...@@ -66,7 +64,8 @@ test_initializer enums([](py::module &m) { ...@@ -66,7 +64,8 @@ test_initializer enums([](py::module &m) {
.value("ESecondMode", ClassWithUnscopedEnum::ESecondMode) .value("ESecondMode", ClassWithUnscopedEnum::ESecondMode)
.export_values(); .export_values();
// test_enum_to_int
m.def("test_enum_to_int", [](int) { }); m.def("test_enum_to_int", [](int) { });
m.def("test_enum_to_uint", [](uint32_t) { }); m.def("test_enum_to_uint", [](uint32_t) { });
m.def("test_enum_to_long_long", [](long long) { }); m.def("test_enum_to_long_long", [](long long) { });
}); }
import pytest import pytest
from pybind11_tests import enums as m
def test_unscoped_enum(): def test_unscoped_enum():
from pybind11_tests import UnscopedEnum, EOne assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne"
assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"
assert str(UnscopedEnum.EOne) == "UnscopedEnum.EOne" assert str(m.EOne) == "UnscopedEnum.EOne"
assert str(UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"
assert str(EOne) == "UnscopedEnum.EOne"
# __members__ property # __members__ property
assert UnscopedEnum.__members__ == {"EOne": UnscopedEnum.EOne, "ETwo": UnscopedEnum.ETwo} assert m.UnscopedEnum.__members__ == \
{"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo}
# __members__ readonly # __members__ readonly
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
UnscopedEnum.__members__ = {} m.UnscopedEnum.__members__ = {}
# __members__ returns a copy # __members__ returns a copy
foo = UnscopedEnum.__members__ foo = m.UnscopedEnum.__members__
foo["bar"] = "baz" foo["bar"] = "baz"
assert UnscopedEnum.__members__ == {"EOne": UnscopedEnum.EOne, "ETwo": UnscopedEnum.ETwo} assert m.UnscopedEnum.__members__ == \
{"EOne": m.UnscopedEnum.EOne, "ETwo": m.UnscopedEnum.ETwo}
# no TypeError exception for unscoped enum ==/!= int comparisons # no TypeError exception for unscoped enum ==/!= int comparisons
y = UnscopedEnum.ETwo y = m.UnscopedEnum.ETwo
assert y == 2 assert y == 2
assert y != 3 assert y != 3
assert int(UnscopedEnum.ETwo) == 2 assert int(m.UnscopedEnum.ETwo) == 2
assert str(UnscopedEnum(2)) == "UnscopedEnum.ETwo" assert str(m.UnscopedEnum(2)) == "UnscopedEnum.ETwo"
# order # order
assert UnscopedEnum.EOne < UnscopedEnum.ETwo assert m.UnscopedEnum.EOne < m.UnscopedEnum.ETwo
assert UnscopedEnum.EOne < 2 assert m.UnscopedEnum.EOne < 2
assert UnscopedEnum.ETwo > UnscopedEnum.EOne assert m.UnscopedEnum.ETwo > m.UnscopedEnum.EOne
assert UnscopedEnum.ETwo > 1 assert m.UnscopedEnum.ETwo > 1
assert UnscopedEnum.ETwo <= 2 assert m.UnscopedEnum.ETwo <= 2
assert UnscopedEnum.ETwo >= 2 assert m.UnscopedEnum.ETwo >= 2
assert UnscopedEnum.EOne <= UnscopedEnum.ETwo assert m.UnscopedEnum.EOne <= m.UnscopedEnum.ETwo
assert UnscopedEnum.EOne <= 2 assert m.UnscopedEnum.EOne <= 2
assert UnscopedEnum.ETwo >= UnscopedEnum.EOne assert m.UnscopedEnum.ETwo >= m.UnscopedEnum.EOne
assert UnscopedEnum.ETwo >= 1 assert m.UnscopedEnum.ETwo >= 1
assert not (UnscopedEnum.ETwo < UnscopedEnum.EOne) assert not (m.UnscopedEnum.ETwo < m.UnscopedEnum.EOne)
assert not (2 < UnscopedEnum.EOne) assert not (2 < m.UnscopedEnum.EOne)
def test_scoped_enum(): def test_scoped_enum():
from pybind11_tests import ScopedEnum, test_scoped_enum assert m.test_scoped_enum(m.ScopedEnum.Three) == "ScopedEnum::Three"
z = m.ScopedEnum.Two
assert test_scoped_enum(ScopedEnum.Three) == "ScopedEnum::Three" assert m.test_scoped_enum(z) == "ScopedEnum::Two"
z = ScopedEnum.Two
assert test_scoped_enum(z) == "ScopedEnum::Two"
# expected TypeError exceptions for scoped enum ==/!= int comparisons # expected TypeError exceptions for scoped enum ==/!= int comparisons
with pytest.raises(TypeError): with pytest.raises(TypeError):
...@@ -54,23 +53,21 @@ def test_scoped_enum(): ...@@ -54,23 +53,21 @@ def test_scoped_enum():
assert z != 3 assert z != 3
# order # order
assert ScopedEnum.Two < ScopedEnum.Three assert m.ScopedEnum.Two < m.ScopedEnum.Three
assert ScopedEnum.Three > ScopedEnum.Two assert m.ScopedEnum.Three > m.ScopedEnum.Two
assert ScopedEnum.Two <= ScopedEnum.Three assert m.ScopedEnum.Two <= m.ScopedEnum.Three
assert ScopedEnum.Two <= ScopedEnum.Two assert m.ScopedEnum.Two <= m.ScopedEnum.Two
assert ScopedEnum.Two >= ScopedEnum.Two assert m.ScopedEnum.Two >= m.ScopedEnum.Two
assert ScopedEnum.Three >= ScopedEnum.Two assert m.ScopedEnum.Three >= m.ScopedEnum.Two
def test_implicit_conversion(): def test_implicit_conversion():
from pybind11_tests import ClassWithUnscopedEnum assert str(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode"
assert str(m.ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode"
assert str(ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode"
assert str(ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode"
f = ClassWithUnscopedEnum.test_function f = m.ClassWithUnscopedEnum.test_function
first = ClassWithUnscopedEnum.EFirstMode first = m.ClassWithUnscopedEnum.EFirstMode
second = ClassWithUnscopedEnum.ESecondMode second = m.ClassWithUnscopedEnum.ESecondMode
assert f(first) == 1 assert f(first) == 1
...@@ -95,21 +92,19 @@ def test_implicit_conversion(): ...@@ -95,21 +92,19 @@ def test_implicit_conversion():
def test_binary_operators(): def test_binary_operators():
from pybind11_tests import Flags assert int(m.Flags.Read) == 4
assert int(m.Flags.Write) == 2
assert int(Flags.Read) == 4 assert int(m.Flags.Execute) == 1
assert int(Flags.Write) == 2 assert int(m.Flags.Read | m.Flags.Write | m.Flags.Execute) == 7
assert int(Flags.Execute) == 1 assert int(m.Flags.Read | m.Flags.Write) == 6
assert int(Flags.Read | Flags.Write | Flags.Execute) == 7 assert int(m.Flags.Read | m.Flags.Execute) == 5
assert int(Flags.Read | Flags.Write) == 6 assert int(m.Flags.Write | m.Flags.Execute) == 3
assert int(Flags.Read | Flags.Execute) == 5 assert int(m.Flags.Write | 1) == 3
assert int(Flags.Write | Flags.Execute) == 3
assert int(Flags.Write | 1) == 3 state = m.Flags.Read | m.Flags.Write
assert (state & m.Flags.Read) != 0
state = Flags.Read | Flags.Write assert (state & m.Flags.Write) != 0
assert (state & Flags.Read) != 0 assert (state & m.Flags.Execute) == 0
assert (state & Flags.Write) != 0
assert (state & Flags.Execute) == 0
assert (state & 1) == 0 assert (state & 1) == 0
state2 = ~state state2 = ~state
...@@ -118,12 +113,9 @@ def test_binary_operators(): ...@@ -118,12 +113,9 @@ def test_binary_operators():
def test_enum_to_int(): def test_enum_to_int():
from pybind11_tests import Flags, ClassWithUnscopedEnum m.test_enum_to_int(m.Flags.Read)
from pybind11_tests import test_enum_to_int, test_enum_to_uint, test_enum_to_long_long m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode)
m.test_enum_to_uint(m.Flags.Read)
test_enum_to_int(Flags.Read) m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode)
test_enum_to_int(ClassWithUnscopedEnum.EMode.EFirstMode) m.test_enum_to_long_long(m.Flags.Read)
test_enum_to_uint(Flags.Read) m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode)
test_enum_to_uint(ClassWithUnscopedEnum.EMode.EFirstMode)
test_enum_to_long_long(Flags.Read)
test_enum_to_long_long(ClassWithUnscopedEnum.EMode.EFirstMode)
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
#include <pybind11/eval.h> #include <pybind11/eval.h>
#include "pybind11_tests.h" #include "pybind11_tests.h"
test_initializer eval([](py::module &m) { TEST_SUBMODULE(eval_, m) {
// test_evals
auto global = py::dict(py::module::import("__main__").attr("__dict__")); auto global = py::dict(py::module::import("__main__").attr("__dict__"));
m.def("test_eval_statements", [global]() { m.def("test_eval_statements", [global]() {
...@@ -86,4 +88,4 @@ test_initializer eval([](py::module &m) { ...@@ -86,4 +88,4 @@ test_initializer eval([](py::module &m) {
} }
return false; return false;
}); });
}); }
import os import os
from pybind11_tests import eval_ as m
def test_evals(capture): 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: with capture:
assert test_eval_statements() assert m.test_eval_statements()
assert capture == "Hello World!" assert capture == "Hello World!"
assert test_eval() assert m.test_eval()
assert test_eval_single_statement() assert m.test_eval_single_statement()
filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py") filename = os.path.join(os.path.dirname(__file__), "test_eval_call.py")
assert test_eval_file(filename) assert m.test_eval_file(filename)
assert test_eval_failure() assert m.test_eval_failure()
assert test_eval_file_failure() assert m.test_eval_file_failure()
...@@ -10,84 +10,62 @@ ...@@ -10,84 +10,62 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <pybind11/stl.h> #include <pybind11/stl.h>
std::string kw_func(int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); } TEST_SUBMODULE(kwargs_and_defaults, m) {
auto kw_func = [](int x, int y) { return "x=" + std::to_string(x) + ", y=" + std::to_string(y); };
std::string kw_func4(const std::vector<int> &entries) { // test_named_arguments
std::string ret = "{"; m.def("kw_func0", kw_func);
for (int i : entries) m.def("kw_func1", kw_func, py::arg("x"), py::arg("y"));
ret += std::to_string(i) + " "; m.def("kw_func2", kw_func, py::arg("x") = 100, py::arg("y") = 200);
ret.back() = '}';
return ret;
}
py::tuple args_function(py::args args) {
return args;
}
py::tuple args_kwargs_function(py::args args, py::kwargs kwargs) {
return py::make_tuple(args, kwargs);
}
py::tuple mixed_plus_args(int i, double j, py::args args) {
return py::make_tuple(i, j, args);
}
py::tuple mixed_plus_kwargs(int i, double j, py::kwargs kwargs) {
return py::make_tuple(i, j, kwargs);
}
py::tuple mixed_plus_args_kwargs(int i, double j, py::args args, py::kwargs kwargs) {
return py::make_tuple(i, j, args, kwargs);
}
// pybind11 won't allow these to be bound: args and kwargs, if present, must be at the end.
void bad_args1(py::args, int) {}
void bad_args2(py::kwargs, int) {}
void bad_args3(py::kwargs, py::args) {}
void bad_args4(py::args, int, py::kwargs) {}
void bad_args5(py::args, py::kwargs, int) {}
void bad_args6(py::args, py::args) {}
void bad_args7(py::kwargs, py::kwargs) {}
struct KWClass {
void foo(int, float) {}
};
test_initializer arg_keywords_and_defaults([](py::module &m) {
m.def("kw_func0", &kw_func);
m.def("kw_func1", &kw_func, py::arg("x"), py::arg("y"));
m.def("kw_func2", &kw_func, py::arg("x") = 100, py::arg("y") = 200);
m.def("kw_func3", [](const char *) { }, py::arg("data") = std::string("Hello world!")); m.def("kw_func3", [](const char *) { }, py::arg("data") = std::string("Hello world!"));
/* A fancier default argument */ /* A fancier default argument */
std::vector<int> list; std::vector<int> list{{13, 17}};
list.push_back(13); m.def("kw_func4", [](const std::vector<int> &entries) {
list.push_back(17); std::string ret = "{";
m.def("kw_func4", &kw_func4, py::arg("myList") = list); for (int i : entries)
ret += std::to_string(i) + " ";
m.def("args_function", &args_function); ret.back() = '}';
m.def("args_kwargs_function", &args_kwargs_function); return ret;
}, py::arg("myList") = list);
m.def("kw_func_udl", &kw_func, "x"_a, "y"_a=300);
m.def("kw_func_udl_z", &kw_func, "x"_a, "y"_a=0); m.def("kw_func_udl", kw_func, "x"_a, "y"_a=300);
m.def("kw_func_udl_z", kw_func, "x"_a, "y"_a=0);
// test_args_and_kwargs
m.def("args_function", [](py::args args) -> py::tuple { return args; });
m.def("args_kwargs_function", [](py::args args, py::kwargs kwargs) {
return py::make_tuple(args, kwargs);
});
// test_mixed_args_and_kwargs
m.def("mixed_plus_args", [](int i, double j, py::args args) {
return py::make_tuple(i, j, args);
});
m.def("mixed_plus_kwargs", [](int i, double j, py::kwargs kwargs) {
return py::make_tuple(i, j, kwargs);
});
auto mixed_plus_both = [](int i, double j, py::args args, py::kwargs kwargs) {
return py::make_tuple(i, j, args, kwargs);
};
m.def("mixed_plus_args_kwargs", mixed_plus_both);
m.def("mixed_plus_args_kwargs_defaults", mixed_plus_both,
py::arg("i") = 1, py::arg("j") = 3.14159);
// pybind11 won't allow these to be bound: args and kwargs, if present, must be at the end.
// Uncomment these to test that the static_assert is indeed working:
// m.def("bad_args1", [](py::args, int) {});
// m.def("bad_args2", [](py::kwargs, int) {});
// m.def("bad_args3", [](py::kwargs, py::args) {});
// m.def("bad_args4", [](py::args, int, py::kwargs) {});
// m.def("bad_args5", [](py::args, py::kwargs, int) {});
// m.def("bad_args6", [](py::args, py::args) {});
// m.def("bad_args7", [](py::kwargs, py::kwargs) {});
// test_function_signatures (along with most of the above)
struct KWClass { void foo(int, float) {} };
py::class_<KWClass>(m, "KWClass") py::class_<KWClass>(m, "KWClass")
.def("foo0", &KWClass::foo) .def("foo0", &KWClass::foo)
.def("foo1", &KWClass::foo, "x"_a, "y"_a); .def("foo1", &KWClass::foo, "x"_a, "y"_a);
}
m.def("mixed_plus_args", &mixed_plus_args);
m.def("mixed_plus_kwargs", &mixed_plus_kwargs);
m.def("mixed_plus_args_kwargs", &mixed_plus_args_kwargs);
m.def("mixed_plus_args_kwargs_defaults", &mixed_plus_args_kwargs,
py::arg("i") = 1, py::arg("j") = 3.14159);
// Uncomment these to test that the static_assert is indeed working:
// m.def("bad_args1", &bad_args1);
// m.def("bad_args2", &bad_args2);
// m.def("bad_args3", &bad_args3);
// m.def("bad_args4", &bad_args4);
// m.def("bad_args5", &bad_args5);
// m.def("bad_args6", &bad_args6);
// m.def("bad_args7", &bad_args7);
});
import pytest import pytest
from pybind11_tests import (kw_func0, kw_func1, kw_func2, kw_func3, kw_func4, args_function, from pybind11_tests import kwargs_and_defaults as m
args_kwargs_function, kw_func_udl, kw_func_udl_z, KWClass)
def test_function_signatures(doc): def test_function_signatures(doc):
assert doc(kw_func0) == "kw_func0(arg0: int, arg1: int) -> str" assert doc(m.kw_func0) == "kw_func0(arg0: int, arg1: int) -> str"
assert doc(kw_func1) == "kw_func1(x: int, y: int) -> str" assert doc(m.kw_func1) == "kw_func1(x: int, y: int) -> str"
assert doc(kw_func2) == "kw_func2(x: int=100, y: int=200) -> str" assert doc(m.kw_func2) == "kw_func2(x: int=100, y: int=200) -> str"
assert doc(kw_func3) == "kw_func3(data: str='Hello world!') -> None" assert doc(m.kw_func3) == "kw_func3(data: str='Hello world!') -> None"
assert doc(kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> str" assert doc(m.kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> str"
assert doc(kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> str" assert doc(m.kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> str"
assert doc(kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> str" assert doc(m.kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> str"
assert doc(args_function) == "args_function(*args) -> tuple" assert doc(m.args_function) == "args_function(*args) -> tuple"
assert doc(args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple" assert doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple"
assert doc(KWClass.foo0) == "foo0(self: m.KWClass, arg0: int, arg1: float) -> None" assert doc(m.KWClass.foo0) == \
assert doc(KWClass.foo1) == "foo1(self: m.KWClass, x: int, y: float) -> None" "foo0(self: m.kwargs_and_defaults.KWClass, arg0: int, arg1: float) -> None"
assert doc(m.KWClass.foo1) == \
"foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None"
def test_named_arguments(msg): def test_named_arguments(msg):
assert kw_func0(5, 10) == "x=5, y=10" assert m.kw_func0(5, 10) == "x=5, y=10"
assert kw_func1(5, 10) == "x=5, y=10" assert m.kw_func1(5, 10) == "x=5, y=10"
assert kw_func1(5, y=10) == "x=5, y=10" assert m.kw_func1(5, y=10) == "x=5, y=10"
assert kw_func1(y=10, x=5) == "x=5, y=10" assert m.kw_func1(y=10, x=5) == "x=5, y=10"
assert kw_func2() == "x=100, y=200" assert m.kw_func2() == "x=100, y=200"
assert kw_func2(5) == "x=5, y=200" assert m.kw_func2(5) == "x=5, y=200"
assert kw_func2(x=5) == "x=5, y=200" assert m.kw_func2(x=5) == "x=5, y=200"
assert kw_func2(y=10) == "x=100, y=10" assert m.kw_func2(y=10) == "x=100, y=10"
assert kw_func2(5, 10) == "x=5, y=10" assert m.kw_func2(5, 10) == "x=5, y=10"
assert kw_func2(x=5, y=10) == "x=5, y=10" assert m.kw_func2(x=5, y=10) == "x=5, y=10"
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
# noinspection PyArgumentList # noinspection PyArgumentList
kw_func2(x=5, y=10, z=12) m.kw_func2(x=5, y=10, z=12)
assert excinfo.match( assert excinfo.match(
r'(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$))' + '{3}$') r'(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$))' + '{3}$')
assert kw_func4() == "{13 17}" assert m.kw_func4() == "{13 17}"
assert kw_func4(myList=[1, 2, 3]) == "{1 2 3}" assert m.kw_func4(myList=[1, 2, 3]) == "{1 2 3}"
assert kw_func_udl(x=5, y=10) == "x=5, y=10" assert m.kw_func_udl(x=5, y=10) == "x=5, y=10"
assert kw_func_udl_z(x=5) == "x=5, y=0" assert m.kw_func_udl_z(x=5) == "x=5, y=0"
def test_arg_and_kwargs(): def test_arg_and_kwargs():
args = 'arg1_value', 'arg2_value', 3 args = 'arg1_value', 'arg2_value', 3
assert args_function(*args) == args assert m.args_function(*args) == args
args = 'a1', 'a2' args = 'a1', 'a2'
kwargs = dict(arg3='a3', arg4=4) kwargs = dict(arg3='a3', arg4=4)
assert args_kwargs_function(*args, **kwargs) == (args, kwargs) assert m.args_kwargs_function(*args, **kwargs) == (args, kwargs)
def test_mixed_args_and_kwargs(msg): def test_mixed_args_and_kwargs(msg):
from pybind11_tests import (mixed_plus_args, mixed_plus_kwargs, mixed_plus_args_kwargs, mpa = m.mixed_plus_args
mixed_plus_args_kwargs_defaults) mpk = m.mixed_plus_kwargs
mpa = mixed_plus_args mpak = m.mixed_plus_args_kwargs
mpk = mixed_plus_kwargs mpakd = m.mixed_plus_args_kwargs_defaults
mpak = mixed_plus_args_kwargs
mpakd = mixed_plus_args_kwargs_defaults
assert mpa(1, 2.5, 4, 99.5, None) == (1, 2.5, (4, 99.5, None)) assert mpa(1, 2.5, 4, 99.5, None) == (1, 2.5, (4, 99.5, None))
assert mpa(1, 2.5) == (1, 2.5, ()) assert mpa(1, 2.5) == (1, 2.5, ())
......
...@@ -26,40 +26,43 @@ public: ...@@ -26,40 +26,43 @@ public:
void operator=(const ExampleMandA &e) { print_copy_assigned(this); value = e.value; } void operator=(const ExampleMandA &e) { print_copy_assigned(this); value = e.value; }
void operator=(ExampleMandA &&e) { print_move_assigned(this); value = e.value; } void operator=(ExampleMandA &&e) { print_move_assigned(this); value = e.value; }
void add1(ExampleMandA other) { value += other.value; } // passing by value void add1(ExampleMandA other) { value += other.value; } // passing by value
void add2(ExampleMandA &other) { value += other.value; } // passing by reference void add2(ExampleMandA &other) { value += other.value; } // passing by reference
void add3(const ExampleMandA &other) { value += other.value; } // passing by const reference void add3(const ExampleMandA &other) { value += other.value; } // passing by const reference
void add4(ExampleMandA *other) { value += other->value; } // passing by pointer void add4(ExampleMandA *other) { value += other->value; } // passing by pointer
void add5(const ExampleMandA *other) { value += other->value; } // passing by const pointer void add5(const ExampleMandA *other) { value += other->value; } // passing by const pointer
void add6(int other) { value += other; } // passing by value void add6(int other) { value += other; } // passing by value
void add7(int &other) { value += other; } // passing by reference void add7(int &other) { value += other; } // passing by reference
void add8(const int &other) { value += other; } // passing by const reference void add8(const int &other) { value += other; } // passing by const reference
void add9(int *other) { value += *other; } // passing by pointer void add9(int *other) { value += *other; } // passing by pointer
void add10(const int *other) { value += *other; } // passing by const pointer void add10(const int *other) { value += *other; } // passing by const pointer
ExampleMandA self1() { return *this; } // return by value ExampleMandA self1() { return *this; } // return by value
ExampleMandA &self2() { return *this; } // return by reference ExampleMandA &self2() { return *this; } // return by reference
const ExampleMandA &self3() { return *this; } // return by const reference const ExampleMandA &self3() { return *this; } // return by const reference
ExampleMandA *self4() { return this; } // return by pointer ExampleMandA *self4() { return this; } // return by pointer
const ExampleMandA *self5() { return this; } // return by const pointer const ExampleMandA *self5() { return this; } // return by const pointer
int internal1() { return value; } // return by value int internal1() { return value; } // return by value
int &internal2() { return value; } // return by reference int &internal2() { return value; } // return by reference
const int &internal3() { return value; } // return by const reference const int &internal3() { return value; } // return by const reference
int *internal4() { return &value; } // return by pointer int *internal4() { return &value; } // return by pointer
const int *internal5() { return &value; } // return by const pointer const int *internal5() { return &value; } // return by const pointer
py::str overloaded() { return "()"; }
py::str overloaded(int) { return "(int)"; }
py::str overloaded(int, float) { return "(int, float)"; } py::str overloaded(int, float) { return "(int, float)"; }
py::str overloaded(float, int) { return "(float, int)"; } py::str overloaded(float, int) { return "(float, int)"; }
py::str overloaded(int, int) { return "(int, int)"; } py::str overloaded(int, int) { return "(int, int)"; }
py::str overloaded(float, float) { return "(float, float)"; } py::str overloaded(float, float) { return "(float, float)"; }
py::str overloaded(int) const { return "(int) const"; }
py::str overloaded(int, float) const { return "(int, float) const"; } py::str overloaded(int, float) const { return "(int, float) const"; }
py::str overloaded(float, int) const { return "(float, int) const"; } py::str overloaded(float, int) const { return "(float, int) const"; }
py::str overloaded(int, int) const { return "(int, int) const"; } py::str overloaded(int, int) const { return "(int, int) const"; }
py::str overloaded(float, float) const { return "(float, float) const"; } py::str overloaded(float, float) const { return "(float, float) const"; }
static py::str overloaded() { return "static"; } static py::str overloaded(float) { return "static float"; }
int value = 0; int value = 0;
}; };
...@@ -74,41 +77,28 @@ struct TestProperties { ...@@ -74,41 +77,28 @@ struct TestProperties {
static int static_get() { return static_value; } static int static_get() { return static_value; }
static void static_set(int v) { static_value = v; } static void static_set(int v) { static_value = v; }
}; };
int TestProperties::static_value = 1; int TestProperties::static_value = 1;
struct TestPropertiesOverride : TestProperties { struct TestPropertiesOverride : TestProperties {
int value = 99; int value = 99;
static int static_value; static int static_value;
}; };
int TestPropertiesOverride::static_value = 99; int TestPropertiesOverride::static_value = 99;
struct SimpleValue { int value = 1; };
struct TestPropRVP { struct TestPropRVP {
SimpleValue v1; UserType v1{1};
SimpleValue v2; UserType v2{1};
static SimpleValue sv1; static UserType sv1;
static SimpleValue sv2; static UserType sv2;
const SimpleValue &get1() const { return v1; } const UserType &get1() const { return v1; }
const SimpleValue &get2() const { return v2; } const UserType &get2() const { return v2; }
SimpleValue get_rvalue() const { return v2; } UserType get_rvalue() const { return v2; }
void set1(int v) { v1.value = v; } void set1(int v) { v1.set(v); }
void set2(int v) { v2.value = v; } void set2(int v) { v2.set(v); }
}; };
UserType TestPropRVP::sv1(1);
SimpleValue TestPropRVP::sv1{}; UserType TestPropRVP::sv2(1);
SimpleValue TestPropRVP::sv2{};
class DynamicClass {
public:
DynamicClass() { print_default_created(this); }
~DynamicClass() { print_destroyed(this); }
};
class CppDerivedDynamicClass : public DynamicClass { };
// py::arg/py::arg_v testing: these arguments just record their argument when invoked // py::arg/py::arg_v testing: these arguments just record their argument when invoked
class ArgInspector1 { public: std::string arg = "(default arg inspector 1)"; }; class ArgInspector1 { public: std::string arg = "(default arg inspector 1)"; };
...@@ -180,9 +170,6 @@ template <> struct type_caster<DestructionTester> { ...@@ -180,9 +170,6 @@ template <> struct type_caster<DestructionTester> {
}; };
}} }}
// Issue/PR #648: bad arg default debugging output
class NotRegistered {};
// Test None-allowed py::arg argument policy // Test None-allowed py::arg argument policy
class NoneTester { public: int answer = 42; }; class NoneTester { public: int answer = 42; };
int none1(const NoneTester &obj) { return obj.answer; } int none1(const NoneTester &obj) { return obj.answer; }
...@@ -215,7 +202,8 @@ public: ...@@ -215,7 +202,8 @@ public:
double sum() const { return rw_value + ro_value; } double sum() const { return rw_value + ro_value; }
}; };
test_initializer methods_and_attributes([](py::module &m) { TEST_SUBMODULE(methods_and_attributes, m) {
// test_methods_and_attributes
py::class_<ExampleMandA> emna(m, "ExampleMandA"); py::class_<ExampleMandA> emna(m, "ExampleMandA");
emna.def(py::init<>()) emna.def(py::init<>())
.def(py::init<int>()) .def(py::init<int>())
...@@ -241,43 +229,52 @@ test_initializer methods_and_attributes([](py::module &m) { ...@@ -241,43 +229,52 @@ test_initializer methods_and_attributes([](py::module &m) {
.def("internal4", &ExampleMandA::internal4) .def("internal4", &ExampleMandA::internal4)
.def("internal5", &ExampleMandA::internal5) .def("internal5", &ExampleMandA::internal5)
#if defined(PYBIND11_OVERLOAD_CAST) #if defined(PYBIND11_OVERLOAD_CAST)
.def("overloaded", py::overload_cast<>(&ExampleMandA::overloaded))
.def("overloaded", py::overload_cast<int>(&ExampleMandA::overloaded))
.def("overloaded", py::overload_cast<int, float>(&ExampleMandA::overloaded)) .def("overloaded", py::overload_cast<int, float>(&ExampleMandA::overloaded))
.def("overloaded", py::overload_cast<float, int>(&ExampleMandA::overloaded)) .def("overloaded", py::overload_cast<float, int>(&ExampleMandA::overloaded))
.def("overloaded", py::overload_cast<int, int>(&ExampleMandA::overloaded)) .def("overloaded", py::overload_cast<int, int>(&ExampleMandA::overloaded))
.def("overloaded", py::overload_cast<float, float>(&ExampleMandA::overloaded)) .def("overloaded", py::overload_cast<float, float>(&ExampleMandA::overloaded))
.def("overloaded_float", py::overload_cast<float, float>(&ExampleMandA::overloaded)) .def("overloaded_float", py::overload_cast<float, float>(&ExampleMandA::overloaded))
.def("overloaded_const", py::overload_cast<int >(&ExampleMandA::overloaded, py::const_))
.def("overloaded_const", py::overload_cast<int, float>(&ExampleMandA::overloaded, py::const_)) .def("overloaded_const", py::overload_cast<int, float>(&ExampleMandA::overloaded, py::const_))
.def("overloaded_const", py::overload_cast<float, int>(&ExampleMandA::overloaded, py::const_)) .def("overloaded_const", py::overload_cast<float, int>(&ExampleMandA::overloaded, py::const_))
.def("overloaded_const", py::overload_cast<int, int>(&ExampleMandA::overloaded, py::const_)) .def("overloaded_const", py::overload_cast<int, int>(&ExampleMandA::overloaded, py::const_))
.def("overloaded_const", py::overload_cast<float, float>(&ExampleMandA::overloaded, py::const_)) .def("overloaded_const", py::overload_cast<float, float>(&ExampleMandA::overloaded, py::const_))
#else #else
.def("overloaded", static_cast<py::str (ExampleMandA::*)()>(&ExampleMandA::overloaded))
.def("overloaded", static_cast<py::str (ExampleMandA::*)(int)>(&ExampleMandA::overloaded))
.def("overloaded", static_cast<py::str (ExampleMandA::*)(int, float)>(&ExampleMandA::overloaded)) .def("overloaded", static_cast<py::str (ExampleMandA::*)(int, float)>(&ExampleMandA::overloaded))
.def("overloaded", static_cast<py::str (ExampleMandA::*)(float, int)>(&ExampleMandA::overloaded)) .def("overloaded", static_cast<py::str (ExampleMandA::*)(float, int)>(&ExampleMandA::overloaded))
.def("overloaded", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded)) .def("overloaded", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
.def("overloaded", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded)) .def("overloaded", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded))
.def("overloaded_float", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded)) .def("overloaded_float", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded))
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int ) const>(&ExampleMandA::overloaded))
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int, float) const>(&ExampleMandA::overloaded)) .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int, float) const>(&ExampleMandA::overloaded))
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, int) const>(&ExampleMandA::overloaded)) .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, int) const>(&ExampleMandA::overloaded))
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int, int) const>(&ExampleMandA::overloaded)) .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int, int) const>(&ExampleMandA::overloaded))
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, float) const>(&ExampleMandA::overloaded)) .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, float) const>(&ExampleMandA::overloaded))
#endif #endif
// test_no_mixed_overloads
// Raise error if trying to mix static/non-static overloads on the same name: // Raise error if trying to mix static/non-static overloads on the same name:
.def_static("add_mixed_overloads1", []() { .def_static("add_mixed_overloads1", []() {
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests").attr("ExampleMandA")); auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA"));
emna.def ("overload_mixed1", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded)) emna.def ("overload_mixed1", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
.def_static("overload_mixed1", static_cast<py::str ( *)( )>(&ExampleMandA::overloaded)); .def_static("overload_mixed1", static_cast<py::str ( *)(float )>(&ExampleMandA::overloaded));
}) })
.def_static("add_mixed_overloads2", []() { .def_static("add_mixed_overloads2", []() {
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests").attr("ExampleMandA")); auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA"));
emna.def_static("overload_mixed2", static_cast<py::str ( *)( )>(&ExampleMandA::overloaded)) emna.def_static("overload_mixed2", static_cast<py::str ( *)(float )>(&ExampleMandA::overloaded))
.def ("overload_mixed2", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded)); .def ("overload_mixed2", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded));
}) })
.def("__str__", &ExampleMandA::toString) .def("__str__", &ExampleMandA::toString)
.def_readwrite("value", &ExampleMandA::value); .def_readwrite("value", &ExampleMandA::value);
// test_copy_method
// Issue #443: can't call copied methods in Python 3 // Issue #443: can't call copied methods in Python 3
emna.attr("add2b") = emna.attr("add2"); emna.attr("add2b") = emna.attr("add2");
// test_properties, test_static_properties, test_static_cls
py::class_<TestProperties>(m, "TestProperties") py::class_<TestProperties>(m, "TestProperties")
.def(py::init<>()) .def(py::init<>())
.def_readonly("def_readonly", &TestProperties::value) .def_readonly("def_readonly", &TestProperties::value)
...@@ -300,15 +297,13 @@ test_initializer methods_and_attributes([](py::module &m) { ...@@ -300,15 +297,13 @@ test_initializer methods_and_attributes([](py::module &m) {
.def_readonly("def_readonly", &TestPropertiesOverride::value) .def_readonly("def_readonly", &TestPropertiesOverride::value)
.def_readonly_static("def_readonly_static", &TestPropertiesOverride::static_value); .def_readonly_static("def_readonly_static", &TestPropertiesOverride::static_value);
py::class_<SimpleValue>(m, "SimpleValue") auto static_get1 = [](py::object) -> const UserType & { return TestPropRVP::sv1; };
.def_readwrite("value", &SimpleValue::value); auto static_get2 = [](py::object) -> const UserType & { return TestPropRVP::sv2; };
auto static_set1 = [](py::object, int v) { TestPropRVP::sv1.set(v); };
auto static_get1 = [](py::object) -> const SimpleValue & { return TestPropRVP::sv1; }; auto static_set2 = [](py::object, int v) { TestPropRVP::sv2.set(v); };
auto static_get2 = [](py::object) -> const SimpleValue & { return TestPropRVP::sv2; };
auto static_set1 = [](py::object, int v) { TestPropRVP::sv1.value = v; };
auto static_set2 = [](py::object, int v) { TestPropRVP::sv2.value = v; };
auto rvp_copy = py::return_value_policy::copy; auto rvp_copy = py::return_value_policy::copy;
// test_property_return_value_policies
py::class_<TestPropRVP>(m, "TestPropRVP") py::class_<TestPropRVP>(m, "TestPropRVP")
.def(py::init<>()) .def(py::init<>())
.def_property_readonly("ro_ref", &TestPropRVP::get1) .def_property_readonly("ro_ref", &TestPropRVP::get1)
...@@ -323,21 +318,32 @@ test_initializer methods_and_attributes([](py::module &m) { ...@@ -323,21 +318,32 @@ test_initializer methods_and_attributes([](py::module &m) {
.def_property_static("static_rw_ref", static_get1, static_set1) .def_property_static("static_rw_ref", static_get1, static_set1)
.def_property_static("static_rw_copy", static_get2, static_set2, rvp_copy) .def_property_static("static_rw_copy", static_get2, static_set2, rvp_copy)
.def_property_static("static_rw_func", py::cpp_function(static_get2, rvp_copy), static_set2) .def_property_static("static_rw_func", py::cpp_function(static_get2, rvp_copy), static_set2)
// test_property_rvalue_policy
.def_property_readonly("rvalue", &TestPropRVP::get_rvalue) .def_property_readonly("rvalue", &TestPropRVP::get_rvalue)
.def_property_readonly_static("static_rvalue", [](py::object) { return SimpleValue(); }); .def_property_readonly_static("static_rvalue", [](py::object) { return UserType(1); });
// test_metaclass_override
struct MetaclassOverride { }; struct MetaclassOverride { };
py::class_<MetaclassOverride>(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type)) py::class_<MetaclassOverride>(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type))
.def_property_readonly_static("readonly", [](py::object) { return 1; }); .def_property_readonly_static("readonly", [](py::object) { return 1; });
#if !defined(PYPY_VERSION) #if !defined(PYPY_VERSION)
// test_dynamic_attributes
class DynamicClass {
public:
DynamicClass() { print_default_created(this); }
~DynamicClass() { print_destroyed(this); }
};
py::class_<DynamicClass>(m, "DynamicClass", py::dynamic_attr()) py::class_<DynamicClass>(m, "DynamicClass", py::dynamic_attr())
.def(py::init()); .def(py::init());
class CppDerivedDynamicClass : public DynamicClass { };
py::class_<CppDerivedDynamicClass, DynamicClass>(m, "CppDerivedDynamicClass") py::class_<CppDerivedDynamicClass, DynamicClass>(m, "CppDerivedDynamicClass")
.def(py::init()); .def(py::init());
#endif #endif
// test_noconvert_args
//
// Test converting. The ArgAlwaysConverts is just there to make the first no-conversion pass // Test converting. The ArgAlwaysConverts is just there to make the first no-conversion pass
// fail so that our call always ends up happening via the second dispatch (the one that allows // fail so that our call always ends up happening via the second dispatch (the one that allows
// some conversion). // some conversion).
...@@ -363,6 +369,7 @@ test_initializer methods_and_attributes([](py::module &m) { ...@@ -363,6 +369,7 @@ test_initializer methods_and_attributes([](py::module &m) {
m.def("ints_preferred", [](int i) { return i / 2; }, py::arg("i")); m.def("ints_preferred", [](int i) { return i / 2; }, py::arg("i"));
m.def("ints_only", [](int i) { return i / 2; }, py::arg("i").noconvert()); m.def("ints_only", [](int i) { return i / 2; }, py::arg("i").noconvert());
// test_bad_arg_default
// Issue/PR #648: bad arg default debugging output // Issue/PR #648: bad arg default debugging output
#if !defined(NDEBUG) #if !defined(NDEBUG)
m.attr("debug_enabled") = true; m.attr("debug_enabled") = true;
...@@ -371,13 +378,14 @@ test_initializer methods_and_attributes([](py::module &m) { ...@@ -371,13 +378,14 @@ test_initializer methods_and_attributes([](py::module &m) {
#endif #endif
m.def("bad_arg_def_named", []{ m.def("bad_arg_def_named", []{
auto m = py::module::import("pybind11_tests"); auto m = py::module::import("pybind11_tests");
m.def("should_fail", [](int, NotRegistered) {}, py::arg(), py::arg("a") = NotRegistered()); m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg("a") = UnregisteredType());
}); });
m.def("bad_arg_def_unnamed", []{ m.def("bad_arg_def_unnamed", []{
auto m = py::module::import("pybind11_tests"); auto m = py::module::import("pybind11_tests");
m.def("should_fail", [](int, NotRegistered) {}, py::arg(), py::arg() = NotRegistered()); m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg() = UnregisteredType());
}); });
// test_accepts_none
py::class_<NoneTester, std::shared_ptr<NoneTester>>(m, "NoneTester") py::class_<NoneTester, std::shared_ptr<NoneTester>>(m, "NoneTester")
.def(py::init<>()); .def(py::init<>());
m.def("no_none1", &none1, py::arg().none(false)); m.def("no_none1", &none1, py::arg().none(false));
...@@ -391,6 +399,7 @@ test_initializer methods_and_attributes([](py::module &m) { ...@@ -391,6 +399,7 @@ test_initializer methods_and_attributes([](py::module &m) {
m.def("ok_none4", &none4, py::arg().none(true)); m.def("ok_none4", &none4, py::arg().none(true));
m.def("ok_none5", &none5); m.def("ok_none5", &none5);
// test_str_issue
// Issue #283: __str__ called on uninitialized instance when constructor arguments invalid // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
py::class_<StrIssue>(m, "StrIssue") py::class_<StrIssue>(m, "StrIssue")
.def(py::init<int>()) .def(py::init<int>())
...@@ -399,6 +408,8 @@ test_initializer methods_and_attributes([](py::module &m) { ...@@ -399,6 +408,8 @@ test_initializer methods_and_attributes([](py::module &m) {
return "StrIssue[" + std::to_string(si.val) + "]"; } return "StrIssue[" + std::to_string(si.val) + "]"; }
); );
// test_unregistered_base_implementations
//
// Issues #854/910: incompatible function args when member function/pointer is in unregistered // Issues #854/910: incompatible function args when member function/pointer is in unregistered
// base class The methods and member pointers below actually resolve to members/pointers in // base class The methods and member pointers below actually resolve to members/pointers in
// UnregisteredBase; before this test/fix they would be registered via lambda with a first // UnregisteredBase; before this test/fix they would be registered via lambda with a first
...@@ -410,8 +421,8 @@ test_initializer methods_and_attributes([](py::module &m) { ...@@ -410,8 +421,8 @@ test_initializer methods_and_attributes([](py::module &m) {
.def_readwrite("rw_value", &RegisteredDerived::rw_value) .def_readwrite("rw_value", &RegisteredDerived::rw_value)
.def_readonly("ro_value", &RegisteredDerived::ro_value) .def_readonly("ro_value", &RegisteredDerived::ro_value)
// These should trigger a static_assert if uncommented // These should trigger a static_assert if uncommented
//.def_readwrite("fails", &SimpleValue::value) // should trigger a static_assert if uncommented //.def_readwrite("fails", &UserType::value) // should trigger a static_assert if uncommented
//.def_readonly("fails", &SimpleValue::value) // should trigger a static_assert if uncommented //.def_readonly("fails", &UserType::value) // should trigger a static_assert if uncommented
.def_property("rw_value_prop", &RegisteredDerived::get_int, &RegisteredDerived::set_int) .def_property("rw_value_prop", &RegisteredDerived::get_int, &RegisteredDerived::set_int)
.def_property_readonly("ro_value_prop", &RegisteredDerived::get_double) .def_property_readonly("ro_value_prop", &RegisteredDerived::get_double)
// This one is in the registered class: // This one is in the registered class:
...@@ -432,4 +443,4 @@ test_initializer methods_and_attributes([](py::module &m) { ...@@ -432,4 +443,4 @@ test_initializer methods_and_attributes([](py::module &m) {
m.def("custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); }, m.def("custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); },
py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction) py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction)
m.def("destruction_tester_cstats", &ConstructorStats::get<DestructionTester>, py::return_value_policy::reference); m.def("destruction_tester_cstats", &ConstructorStats::get<DestructionTester>, py::return_value_policy::reference);
}); }
import pytest import pytest
from pybind11_tests import ExampleMandA, ConstructorStats from pybind11_tests import methods_and_attributes as m
from pybind11_tests import ConstructorStats
def test_methods_and_attributes(): def test_methods_and_attributes():
instance1 = ExampleMandA() instance1 = m.ExampleMandA()
instance2 = ExampleMandA(32) instance2 = m.ExampleMandA(32)
instance1.add1(instance2) instance1.add1(instance2)
instance1.add2(instance2) instance1.add2(instance2)
...@@ -31,10 +32,13 @@ def test_methods_and_attributes(): ...@@ -31,10 +32,13 @@ def test_methods_and_attributes():
assert instance1.internal4() == 320 assert instance1.internal4() == 320
assert instance1.internal5() == 320 assert instance1.internal5() == 320
assert instance1.overloaded() == "()"
assert instance1.overloaded(0) == "(int)"
assert instance1.overloaded(1, 1.0) == "(int, float)" assert instance1.overloaded(1, 1.0) == "(int, float)"
assert instance1.overloaded(2.0, 2) == "(float, int)" assert instance1.overloaded(2.0, 2) == "(float, int)"
assert instance1.overloaded(3, 3) == "(int, int)" assert instance1.overloaded(3, 3) == "(int, int)"
assert instance1.overloaded(4., 4.) == "(float, float)" assert instance1.overloaded(4., 4.) == "(float, float)"
assert instance1.overloaded_const(-3) == "(int) const"
assert instance1.overloaded_const(5, 5.0) == "(int, float) const" assert instance1.overloaded_const(5, 5.0) == "(int, float) const"
assert instance1.overloaded_const(6.0, 6) == "(float, int) const" assert instance1.overloaded_const(6.0, 6) == "(float, int) const"
assert instance1.overloaded_const(7, 7) == "(int, int) const" assert instance1.overloaded_const(7, 7) == "(int, int) const"
...@@ -48,7 +52,7 @@ def test_methods_and_attributes(): ...@@ -48,7 +52,7 @@ def test_methods_and_attributes():
instance1.value = 100 instance1.value = 100
assert str(instance1) == "ExampleMandA[value=100]" assert str(instance1) == "ExampleMandA[value=100]"
cstats = ConstructorStats.get(ExampleMandA) cstats = ConstructorStats.get(m.ExampleMandA)
assert cstats.alive() == 2 assert cstats.alive() == 2
del instance1, instance2 del instance1, instance2
assert cstats.alive() == 0 assert cstats.alive() == 0
...@@ -60,10 +64,25 @@ def test_methods_and_attributes(): ...@@ -60,10 +64,25 @@ def test_methods_and_attributes():
assert cstats.move_assignments == 0 assert cstats.move_assignments == 0
def test_properties(): def test_copy_method():
from pybind11_tests import TestProperties """Issue #443: calling copied methods fails in Python 3"""
m.ExampleMandA.add2c = m.ExampleMandA.add2
m.ExampleMandA.add2d = m.ExampleMandA.add2b
a = m.ExampleMandA(123)
assert a.value == 123
a.add2(m.ExampleMandA(-100))
assert a.value == 23
a.add2b(m.ExampleMandA(20))
assert a.value == 43
a.add2c(m.ExampleMandA(6))
assert a.value == 49
a.add2d(m.ExampleMandA(-7))
assert a.value == 42
instance = TestProperties()
def test_properties():
instance = m.TestProperties()
assert instance.def_readonly == 1 assert instance.def_readonly == 1
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
...@@ -80,122 +99,97 @@ def test_properties(): ...@@ -80,122 +99,97 @@ def test_properties():
assert instance.def_property == 3 assert instance.def_property == 3
def test_copy_method():
"""Issue #443: calling copied methods fails in Python 3"""
from pybind11_tests import ExampleMandA
ExampleMandA.add2c = ExampleMandA.add2
ExampleMandA.add2d = ExampleMandA.add2b
a = ExampleMandA(123)
assert a.value == 123
a.add2(ExampleMandA(-100))
assert a.value == 23
a.add2b(ExampleMandA(20))
assert a.value == 43
a.add2c(ExampleMandA(6))
assert a.value == 49
a.add2d(ExampleMandA(-7))
assert a.value == 42
def test_static_properties(): def test_static_properties():
from pybind11_tests import TestProperties as Type assert m.TestProperties.def_readonly_static == 1
assert Type.def_readonly_static == 1
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
Type.def_readonly_static = 2 m.TestProperties.def_readonly_static = 2
assert "can't set attribute" in str(excinfo) assert "can't set attribute" in str(excinfo)
Type.def_readwrite_static = 2 m.TestProperties.def_readwrite_static = 2
assert Type.def_readwrite_static == 2 assert m.TestProperties.def_readwrite_static == 2
assert Type.def_property_readonly_static == 2 assert m.TestProperties.def_property_readonly_static == 2
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
Type.def_property_readonly_static = 3 m.TestProperties.def_property_readonly_static = 3
assert "can't set attribute" in str(excinfo) assert "can't set attribute" in str(excinfo)
Type.def_property_static = 3 m.TestProperties.def_property_static = 3
assert Type.def_property_static == 3 assert m.TestProperties.def_property_static == 3
# Static property read and write via instance # Static property read and write via instance
instance = Type() instance = m.TestProperties()
Type.def_readwrite_static = 0 m.TestProperties.def_readwrite_static = 0
assert Type.def_readwrite_static == 0 assert m.TestProperties.def_readwrite_static == 0
assert instance.def_readwrite_static == 0 assert instance.def_readwrite_static == 0
instance.def_readwrite_static = 2 instance.def_readwrite_static = 2
assert Type.def_readwrite_static == 2 assert m.TestProperties.def_readwrite_static == 2
assert instance.def_readwrite_static == 2 assert instance.def_readwrite_static == 2
# It should be possible to override properties in derived classes # It should be possible to override properties in derived classes
from pybind11_tests import TestPropertiesOverride as TypeOverride assert m.TestPropertiesOverride().def_readonly == 99
assert m.TestPropertiesOverride.def_readonly_static == 99
assert TypeOverride().def_readonly == 99
assert TypeOverride.def_readonly_static == 99
def test_static_cls(): def test_static_cls():
"""Static property getter and setters expect the type object as the their only argument""" """Static property getter and setters expect the type object as the their only argument"""
from pybind11_tests import TestProperties as Type
instance = Type() instance = m.TestProperties()
assert Type.static_cls is Type assert m.TestProperties.static_cls is m.TestProperties
assert instance.static_cls is Type assert instance.static_cls is m.TestProperties
def check_self(self): def check_self(self):
assert self is Type assert self is m.TestProperties
Type.static_cls = check_self m.TestProperties.static_cls = check_self
instance.static_cls = check_self instance.static_cls = check_self
def test_metaclass_override(): def test_metaclass_override():
"""Overriding pybind11's default metaclass changes the behavior of `static_property`""" """Overriding pybind11's default metaclass changes the behavior of `static_property`"""
from pybind11_tests import MetaclassOverride
assert type(ExampleMandA).__name__ == "pybind11_type" assert type(m.ExampleMandA).__name__ == "pybind11_type"
assert type(MetaclassOverride).__name__ == "type" assert type(m.MetaclassOverride).__name__ == "type"
assert MetaclassOverride.readonly == 1 assert m.MetaclassOverride.readonly == 1
assert type(MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property" assert type(m.MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property"
# Regular `type` replaces the property instead of calling `__set__()` # Regular `type` replaces the property instead of calling `__set__()`
MetaclassOverride.readonly = 2 m.MetaclassOverride.readonly = 2
assert MetaclassOverride.readonly == 2 assert m.MetaclassOverride.readonly == 2
assert isinstance(MetaclassOverride.__dict__["readonly"], int) assert isinstance(m.MetaclassOverride.__dict__["readonly"], int)
def test_no_mixed_overloads(): def test_no_mixed_overloads():
from pybind11_tests import debug_enabled from pybind11_tests import debug_enabled
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
ExampleMandA.add_mixed_overloads1() m.ExampleMandA.add_mixed_overloads1()
assert (str(excinfo.value) == assert (str(excinfo.value) ==
"overloading a method with both static and instance methods is not supported; " + "overloading a method with both static and instance methods is not supported; " +
("compile in debug mode for more details" if not debug_enabled else ("compile in debug mode for more details" if not debug_enabled else
"error while attempting to bind static method ExampleMandA.overload_mixed1" "error while attempting to bind static method ExampleMandA.overload_mixed1"
"() -> str") "(arg0: float) -> str")
) )
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
ExampleMandA.add_mixed_overloads2() m.ExampleMandA.add_mixed_overloads2()
assert (str(excinfo.value) == assert (str(excinfo.value) ==
"overloading a method with both static and instance methods is not supported; " + "overloading a method with both static and instance methods is not supported; " +
("compile in debug mode for more details" if not debug_enabled else ("compile in debug mode for more details" if not debug_enabled else
"error while attempting to bind instance method ExampleMandA.overload_mixed2" "error while attempting to bind instance method ExampleMandA.overload_mixed2"
"(self: pybind11_tests.ExampleMandA, arg0: int, arg1: int) -> str") "(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)"
" -> str")
) )
@pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"]) @pytest.mark.parametrize("access", ["ro", "rw", "static_ro", "static_rw"])
def test_property_return_value_policies(access): def test_property_return_value_policies(access):
from pybind11_tests import TestPropRVP
if not access.startswith("static"): if not access.startswith("static"):
obj = TestPropRVP() obj = m.TestPropRVP()
else: else:
obj = TestPropRVP obj = m.TestPropRVP
ref = getattr(obj, access + "_ref") ref = getattr(obj, access + "_ref")
assert ref.value == 1 assert ref.value == 1
...@@ -216,30 +210,20 @@ def test_property_return_value_policies(access): ...@@ -216,30 +210,20 @@ def test_property_return_value_policies(access):
def test_property_rvalue_policy(): def test_property_rvalue_policy():
"""When returning an rvalue, the return value policy is automatically changed from """When returning an rvalue, the return value policy is automatically changed from
`reference(_internal)` to `move`. The following would not work otherwise. `reference(_internal)` to `move`. The following would not work otherwise."""
"""
from pybind11_tests import TestPropRVP
instance = TestPropRVP() instance = m.TestPropRVP()
o = instance.rvalue o = instance.rvalue
assert o.value == 1 assert o.value == 1
os = m.TestPropRVP.static_rvalue
def test_property_rvalue_policy_static(): assert os.value == 1
"""When returning an rvalue, the return value policy is automatically changed from
`reference(_internal)` to `move`. The following would not work otherwise.
"""
from pybind11_tests import TestPropRVP
o = TestPropRVP.static_rvalue
assert o.value == 1
# https://bitbucket.org/pypy/pypy/issues/2447 # https://bitbucket.org/pypy/pypy/issues/2447
@pytest.unsupported_on_pypy @pytest.unsupported_on_pypy
def test_dynamic_attributes(): def test_dynamic_attributes():
from pybind11_tests import DynamicClass, CppDerivedDynamicClass instance = m.DynamicClass()
instance = DynamicClass()
assert not hasattr(instance, "foo") assert not hasattr(instance, "foo")
assert "foo" not in dir(instance) assert "foo" not in dir(instance)
...@@ -259,16 +243,16 @@ def test_dynamic_attributes(): ...@@ -259,16 +243,16 @@ def test_dynamic_attributes():
instance.__dict__ = [] instance.__dict__ = []
assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'" assert str(excinfo.value) == "__dict__ must be set to a dictionary, not a 'list'"
cstats = ConstructorStats.get(DynamicClass) cstats = ConstructorStats.get(m.DynamicClass)
assert cstats.alive() == 1 assert cstats.alive() == 1
del instance del instance
assert cstats.alive() == 0 assert cstats.alive() == 0
# Derived classes should work as well # Derived classes should work as well
class PythonDerivedDynamicClass(DynamicClass): class PythonDerivedDynamicClass(m.DynamicClass):
pass pass
for cls in CppDerivedDynamicClass, PythonDerivedDynamicClass: for cls in m.CppDerivedDynamicClass, PythonDerivedDynamicClass:
derived = cls() derived = cls()
derived.foobar = 100 derived.foobar = 100
assert derived.foobar == 100 assert derived.foobar == 100
...@@ -281,20 +265,18 @@ def test_dynamic_attributes(): ...@@ -281,20 +265,18 @@ def test_dynamic_attributes():
# https://bitbucket.org/pypy/pypy/issues/2447 # https://bitbucket.org/pypy/pypy/issues/2447
@pytest.unsupported_on_pypy @pytest.unsupported_on_pypy
def test_cyclic_gc(): def test_cyclic_gc():
from pybind11_tests import DynamicClass
# One object references itself # One object references itself
instance = DynamicClass() instance = m.DynamicClass()
instance.circular_reference = instance instance.circular_reference = instance
cstats = ConstructorStats.get(DynamicClass) cstats = ConstructorStats.get(m.DynamicClass)
assert cstats.alive() == 1 assert cstats.alive() == 1
del instance del instance
assert cstats.alive() == 0 assert cstats.alive() == 0
# Two object reference each other # Two object reference each other
i1 = DynamicClass() i1 = m.DynamicClass()
i2 = DynamicClass() i2 = m.DynamicClass()
i1.cycle = i2 i1.cycle = i2
i2.cycle = i1 i2.cycle = i1
...@@ -304,8 +286,6 @@ def test_cyclic_gc(): ...@@ -304,8 +286,6 @@ def test_cyclic_gc():
def test_noconvert_args(msg): def test_noconvert_args(msg):
import pybind11_tests as m
a = m.ArgInspector() a = m.ArgInspector()
assert msg(a.f("hi")) == """ assert msg(a.f("hi")) == """
loading ArgInspector1 argument WITH conversion allowed. Argument value = hi loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
...@@ -369,23 +349,23 @@ def test_noconvert_args(msg): ...@@ -369,23 +349,23 @@ def test_noconvert_args(msg):
def test_bad_arg_default(msg): def test_bad_arg_default(msg):
from pybind11_tests import debug_enabled, bad_arg_def_named, bad_arg_def_unnamed from pybind11_tests import debug_enabled
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
bad_arg_def_named() m.bad_arg_def_named()
assert msg(excinfo.value) == ( assert msg(excinfo.value) == (
"arg(): could not convert default argument 'a: NotRegistered' in function 'should_fail' " "arg(): could not convert default argument 'a: UnregisteredType' in function "
"into a Python object (type not registered yet?)" "'should_fail' into a Python object (type not registered yet?)"
if debug_enabled else if debug_enabled else
"arg(): could not convert default argument into a Python object (type not registered " "arg(): could not convert default argument into a Python object (type not registered "
"yet?). Compile in debug mode for more information." "yet?). Compile in debug mode for more information."
) )
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
bad_arg_def_unnamed() m.bad_arg_def_unnamed()
assert msg(excinfo.value) == ( assert msg(excinfo.value) == (
"arg(): could not convert default argument 'NotRegistered' in function 'should_fail' " "arg(): could not convert default argument 'UnregisteredType' in function "
"into a Python object (type not registered yet?)" "'should_fail' into a Python object (type not registered yet?)"
if debug_enabled else if debug_enabled else
"arg(): could not convert default argument into a Python object (type not registered " "arg(): could not convert default argument into a Python object (type not registered "
"yet?). Compile in debug mode for more information." "yet?). Compile in debug mode for more information."
...@@ -393,76 +373,69 @@ def test_bad_arg_default(msg): ...@@ -393,76 +373,69 @@ def test_bad_arg_default(msg):
def test_accepts_none(msg): def test_accepts_none(msg):
from pybind11_tests import (NoneTester, a = m.NoneTester()
no_none1, no_none2, no_none3, no_none4, no_none5, assert m.no_none1(a) == 42
ok_none1, ok_none2, ok_none3, ok_none4, ok_none5) assert m.no_none2(a) == 42
assert m.no_none3(a) == 42
a = NoneTester() assert m.no_none4(a) == 42
assert no_none1(a) == 42 assert m.no_none5(a) == 42
assert no_none2(a) == 42 assert m.ok_none1(a) == 42
assert no_none3(a) == 42 assert m.ok_none2(a) == 42
assert no_none4(a) == 42 assert m.ok_none3(a) == 42
assert no_none5(a) == 42 assert m.ok_none4(a) == 42
assert ok_none1(a) == 42 assert m.ok_none5(a) == 42
assert ok_none2(a) == 42
assert ok_none3(a) == 42
assert ok_none4(a) == 42
assert ok_none5(a) == 42
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
no_none1(None) m.no_none1(None)
assert "incompatible function arguments" in str(excinfo.value) assert "incompatible function arguments" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
no_none2(None) m.no_none2(None)
assert "incompatible function arguments" in str(excinfo.value) assert "incompatible function arguments" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
no_none3(None) m.no_none3(None)
assert "incompatible function arguments" in str(excinfo.value) assert "incompatible function arguments" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
no_none4(None) m.no_none4(None)
assert "incompatible function arguments" in str(excinfo.value) assert "incompatible function arguments" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
no_none5(None) m.no_none5(None)
assert "incompatible function arguments" in str(excinfo.value) assert "incompatible function arguments" in str(excinfo.value)
# The first one still raises because you can't pass None as a lvalue reference arg: # The first one still raises because you can't pass None as a lvalue reference arg:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
assert ok_none1(None) == -1 assert m.ok_none1(None) == -1
assert msg(excinfo.value) == """ assert msg(excinfo.value) == """
ok_none1(): incompatible function arguments. The following argument types are supported: ok_none1(): incompatible function arguments. The following argument types are supported:
1. (arg0: m.NoneTester) -> int 1. (arg0: m.methods_and_attributes.NoneTester) -> int
Invoked with: None Invoked with: None
""" """
# The rest take the argument as pointer or holder, and accept None: # The rest take the argument as pointer or holder, and accept None:
assert ok_none2(None) == -1 assert m.ok_none2(None) == -1
assert ok_none3(None) == -1 assert m.ok_none3(None) == -1
assert ok_none4(None) == -1 assert m.ok_none4(None) == -1
assert ok_none5(None) == -1 assert m.ok_none5(None) == -1
def test_str_issue(msg): def test_str_issue(msg):
"""#283: __str__ called on uninitialized instance when constructor arguments invalid""" """#283: __str__ called on uninitialized instance when constructor arguments invalid"""
from pybind11_tests import StrIssue
assert str(StrIssue(3)) == "StrIssue[3]" assert str(m.StrIssue(3)) == "StrIssue[3]"
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
str(StrIssue("no", "such", "constructor")) str(m.StrIssue("no", "such", "constructor"))
assert msg(excinfo.value) == """ assert msg(excinfo.value) == """
__init__(): incompatible constructor arguments. The following argument types are supported: __init__(): incompatible constructor arguments. The following argument types are supported:
1. m.StrIssue(arg0: int) 1. m.methods_and_attributes.StrIssue(arg0: int)
2. m.StrIssue() 2. m.methods_and_attributes.StrIssue()
Invoked with: 'no', 'such', 'constructor' Invoked with: 'no', 'such', 'constructor'
""" """
def test_unregistered_base_implementations(): def test_unregistered_base_implementations():
from pybind11_tests import RegisteredDerived a = m.RegisteredDerived()
a = RegisteredDerived()
a.do_nothing() a.do_nothing()
assert a.rw_value == 42 assert a.rw_value == 42
assert a.ro_value == 1.25 assert a.ro_value == 1.25
...@@ -480,11 +453,8 @@ def test_unregistered_base_implementations(): ...@@ -480,11 +453,8 @@ def test_unregistered_base_implementations():
def test_custom_caster_destruction(): def test_custom_caster_destruction():
""" """Tests that returning a pointer to a type that gets converted with a custom type caster gets
Tests that returning a pointer to a type that gets converted with a custom type caster gets destroyed when the function has py::return_value_policy::take_ownership policy applied."""
destroyed when the function has py::return_value_policy::take_ownership policy applied.
"""
import pybind11_tests as m
cstats = m.destruction_tester_cstats() cstats = m.destruction_tester_cstats()
# This one *doesn't* have take_ownership: the pointer should be used but not destroyed: # This one *doesn't* have take_ownership: the pointer should be used but not destroyed:
......
...@@ -11,42 +11,38 @@ ...@@ -11,42 +11,38 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include "constructor_stats.h" #include "constructor_stats.h"
std::string submodule_func() { TEST_SUBMODULE(modules, m) {
return "submodule_func()"; // test_nested_modules
} py::module m_sub = m.def_submodule("subsubmodule");
m_sub.def("submodule_func", []() { return "submodule_func()"; });
class A {
public: // test_reference_internal
A(int v) : v(v) { print_created(this, v); } class A {
~A() { print_destroyed(this); } public:
A(const A&) { print_copy_created(this); } A(int v) : v(v) { print_created(this, v); }
A& operator=(const A &copy) { print_copy_assigned(this); v = copy.v; return *this; } ~A() { print_destroyed(this); }
std::string toString() { return "A[" + std::to_string(v) + "]"; } A(const A&) { print_copy_created(this); }
private: A& operator=(const A &copy) { print_copy_assigned(this); v = copy.v; return *this; }
int v; std::string toString() { return "A[" + std::to_string(v) + "]"; }
}; private:
int v;
class B { };
public:
B() { print_default_created(this); }
~B() { print_destroyed(this); }
B(const B&) { print_copy_created(this); }
B& operator=(const B &copy) { print_copy_assigned(this); a1 = copy.a1; a2 = copy.a2; return *this; }
A &get_a1() { return a1; }
A &get_a2() { return a2; }
A a1{1};
A a2{2};
};
test_initializer modules([](py::module &m) {
py::module m_sub = m.def_submodule("submodule");
m_sub.def("submodule_func", &submodule_func);
py::class_<A>(m_sub, "A") py::class_<A>(m_sub, "A")
.def(py::init<int>()) .def(py::init<int>())
.def("__repr__", &A::toString); .def("__repr__", &A::toString);
class B {
public:
B() { print_default_created(this); }
~B() { print_destroyed(this); }
B(const B&) { print_copy_created(this); }
B& operator=(const B &copy) { print_copy_assigned(this); a1 = copy.a1; a2 = copy.a2; return *this; }
A &get_a1() { return a1; }
A &get_a2() { return a2; }
A a1{1};
A a2{2};
};
py::class_<B>(m_sub, "B") py::class_<B>(m_sub, "B")
.def(py::init<>()) .def(py::init<>())
.def("get_a1", &B::get_a1, "Return the internal A 1", py::return_value_policy::reference_internal) .def("get_a1", &B::get_a1, "Return the internal A 1", py::return_value_policy::reference_internal)
...@@ -56,6 +52,7 @@ test_initializer modules([](py::module &m) { ...@@ -56,6 +52,7 @@ test_initializer modules([](py::module &m) {
m.attr("OD") = py::module::import("collections").attr("OrderedDict"); m.attr("OD") = py::module::import("collections").attr("OrderedDict");
// test_duplicate_registration
// Registering two things with the same name // Registering two things with the same name
m.def("duplicate_registration", []() { m.def("duplicate_registration", []() {
class Dupe1 { }; class Dupe1 { };
...@@ -98,4 +95,4 @@ test_initializer modules([](py::module &m) { ...@@ -98,4 +95,4 @@ test_initializer modules([](py::module &m) {
return failures; return failures;
}); });
}); }
from pybind11_tests import modules as m
from pybind11_tests.modules import subsubmodule as ms
from pybind11_tests import ConstructorStats
def test_nested_modules(): def test_nested_modules():
import pybind11_tests import pybind11_tests
from pybind11_tests.submodule import submodule_func
assert pybind11_tests.__name__ == "pybind11_tests" assert pybind11_tests.__name__ == "pybind11_tests"
assert pybind11_tests.submodule.__name__ == "pybind11_tests.submodule" assert pybind11_tests.modules.__name__ == "pybind11_tests.modules"
assert pybind11_tests.modules.subsubmodule.__name__ == "pybind11_tests.modules.subsubmodule"
assert m.__name__ == "pybind11_tests.modules"
assert ms.__name__ == "pybind11_tests.modules.subsubmodule"
assert submodule_func() == "submodule_func()" assert ms.submodule_func() == "submodule_func()"
def test_reference_internal(): def test_reference_internal():
from pybind11_tests import ConstructorStats b = ms.B()
from pybind11_tests.submodule import A, B
b = B()
assert str(b.get_a1()) == "A[1]" assert str(b.get_a1()) == "A[1]"
assert str(b.a1) == "A[1]" assert str(b.a1) == "A[1]"
assert str(b.get_a2()) == "A[2]" assert str(b.get_a2()) == "A[2]"
assert str(b.a2) == "A[2]" assert str(b.a2) == "A[2]"
b.a1 = A(42) b.a1 = ms.A(42)
b.a2 = A(43) b.a2 = ms.A(43)
assert str(b.get_a1()) == "A[42]" assert str(b.get_a1()) == "A[42]"
assert str(b.a1) == "A[42]" assert str(b.a1) == "A[42]"
assert str(b.get_a2()) == "A[43]" assert str(b.get_a2()) == "A[43]"
assert str(b.a2) == "A[43]" assert str(b.a2) == "A[43]"
astats, bstats = ConstructorStats.get(A), ConstructorStats.get(B) astats, bstats = ConstructorStats.get(ms.A), ConstructorStats.get(ms.B)
assert astats.alive() == 2 assert astats.alive() == 2
assert bstats.alive() == 1 assert bstats.alive() == 1
del b del b
...@@ -47,7 +49,7 @@ def test_reference_internal(): ...@@ -47,7 +49,7 @@ def test_reference_internal():
def test_importing(): def test_importing():
from pybind11_tests import OD from pybind11_tests.modules import OD
from collections import OrderedDict from collections import OrderedDict
assert OD is OrderedDict assert OD is OrderedDict
...@@ -66,6 +68,5 @@ def test_pydoc(): ...@@ -66,6 +68,5 @@ def test_pydoc():
def test_duplicate_registration(): def test_duplicate_registration():
"""Registering two things with the same name""" """Registering two things with the same name"""
from pybind11_tests import duplicate_registration
assert duplicate_registration() == [] assert m.duplicate_registration() == []
...@@ -26,20 +26,6 @@ template<typename... Ix> arr data_t(const arr_t& a, Ix... index) { ...@@ -26,20 +26,6 @@ template<typename... Ix> arr data_t(const arr_t& a, Ix... index) {
return arr(a.size() - a.index_at(index...), a.data(index...)); return arr(a.size() - a.index_at(index...), a.data(index...));
} }
arr& mutate_data(arr& a) {
auto ptr = (uint8_t *) a.mutable_data();
for (ssize_t i = 0; i < a.nbytes(); i++)
ptr[i] = (uint8_t) (ptr[i] * 2);
return a;
}
arr_t& mutate_data_t(arr_t& a) {
auto ptr = a.mutable_data();
for (ssize_t i = 0; i < a.size(); i++)
ptr[i]++;
return a;
}
template<typename... Ix> arr& mutate_data(arr& a, Ix... index) { template<typename... Ix> arr& mutate_data(arr& a, Ix... index) {
auto ptr = (uint8_t *) a.mutable_data(index...); auto ptr = (uint8_t *) a.mutable_data(index...);
for (ssize_t i = 0; i < a.nbytes() - a.offset_at(index...); i++) for (ssize_t i = 0; i < a.nbytes() - a.offset_at(index...); i++)
...@@ -82,9 +68,11 @@ template <typename T, typename T2> py::handle auxiliaries(T &&r, T2 &&r2) { ...@@ -82,9 +68,11 @@ template <typename T, typename T2> py::handle auxiliaries(T &&r, T2 &&r2) {
return l.release(); return l.release();
} }
test_initializer numpy_array([](py::module &m) { TEST_SUBMODULE(numpy_array, sm) {
auto sm = m.def_submodule("array"); try { py::module::import("numpy"); }
catch (...) { return; }
// test_array_attributes
sm.def("ndim", [](const arr& a) { return a.ndim(); }); sm.def("ndim", [](const arr& a) { return a.ndim(); });
sm.def("shape", [](const arr& a) { return arr(a.ndim(), a.shape()); }); sm.def("shape", [](const arr& a) { return arr(a.ndim(), a.shape()); });
sm.def("shape", [](const arr& a, ssize_t dim) { return a.shape(dim); }); sm.def("shape", [](const arr& a, ssize_t dim) { return a.shape(dim); });
...@@ -96,25 +84,25 @@ test_initializer numpy_array([](py::module &m) { ...@@ -96,25 +84,25 @@ test_initializer numpy_array([](py::module &m) {
sm.def("nbytes", [](const arr& a) { return a.nbytes(); }); sm.def("nbytes", [](const arr& a) { return a.nbytes(); });
sm.def("owndata", [](const arr& a) { return a.owndata(); }); sm.def("owndata", [](const arr& a) { return a.owndata(); });
def_index_fn(data, const arr&); // test_index_offset
def_index_fn(data_t, const arr_t&);
def_index_fn(index_at, const arr&); def_index_fn(index_at, const arr&);
def_index_fn(index_at_t, const arr_t&); def_index_fn(index_at_t, const arr_t&);
def_index_fn(offset_at, const arr&); def_index_fn(offset_at, const arr&);
def_index_fn(offset_at_t, const arr_t&); def_index_fn(offset_at_t, const arr_t&);
// test_data
def_index_fn(data, const arr&);
def_index_fn(data_t, const arr_t&);
// test_mutate_data, test_mutate_readonly
def_index_fn(mutate_data, arr&); def_index_fn(mutate_data, arr&);
def_index_fn(mutate_data_t, arr_t&); def_index_fn(mutate_data_t, arr_t&);
def_index_fn(at_t, const arr_t&); def_index_fn(at_t, const arr_t&);
def_index_fn(mutate_at_t, arr_t&); def_index_fn(mutate_at_t, arr_t&);
sm.def("make_f_array", [] { // test_make_c_f_array
return py::array_t<float>({ 2, 2 }, { 4, 8 }); sm.def("make_f_array", [] { return py::array_t<float>({ 2, 2 }, { 4, 8 }); });
}); sm.def("make_c_array", [] { return py::array_t<float>({ 2, 2 }, { 8, 4 }); });
sm.def("make_c_array", [] {
return py::array_t<float>({ 2, 2 }, { 8, 4 });
});
// test_wrap
sm.def("wrap", [](py::array a) { sm.def("wrap", [](py::array a) {
return py::array( return py::array(
a.dtype(), a.dtype(),
...@@ -125,12 +113,12 @@ test_initializer numpy_array([](py::module &m) { ...@@ -125,12 +113,12 @@ test_initializer numpy_array([](py::module &m) {
); );
}); });
// test_numpy_view
struct ArrayClass { struct ArrayClass {
int data[2] = { 1, 2 }; int data[2] = { 1, 2 };
ArrayClass() { py::print("ArrayClass()"); } ArrayClass() { py::print("ArrayClass()"); }
~ArrayClass() { py::print("~ArrayClass()"); } ~ArrayClass() { py::print("~ArrayClass()"); }
}; };
py::class_<ArrayClass>(sm, "ArrayClass") py::class_<ArrayClass>(sm, "ArrayClass")
.def(py::init<>()) .def(py::init<>())
.def("numpy_view", [](py::object &obj) { .def("numpy_view", [](py::object &obj) {
...@@ -140,16 +128,18 @@ test_initializer numpy_array([](py::module &m) { ...@@ -140,16 +128,18 @@ test_initializer numpy_array([](py::module &m) {
} }
); );
// test_cast_numpy_int64_to_uint64
sm.def("function_taking_uint64", [](uint64_t) { }); sm.def("function_taking_uint64", [](uint64_t) { });
// test_isinstance
sm.def("isinstance_untyped", [](py::object yes, py::object no) { sm.def("isinstance_untyped", [](py::object yes, py::object no) {
return py::isinstance<py::array>(yes) && !py::isinstance<py::array>(no); return py::isinstance<py::array>(yes) && !py::isinstance<py::array>(no);
}); });
sm.def("isinstance_typed", [](py::object o) { sm.def("isinstance_typed", [](py::object o) {
return py::isinstance<py::array_t<double>>(o) && !py::isinstance<py::array_t<int>>(o); return py::isinstance<py::array_t<double>>(o) && !py::isinstance<py::array_t<int>>(o);
}); });
// test_constructors
sm.def("default_constructors", []() { sm.def("default_constructors", []() {
return py::dict( return py::dict(
"array"_a=py::array(), "array"_a=py::array(),
...@@ -157,7 +147,6 @@ test_initializer numpy_array([](py::module &m) { ...@@ -157,7 +147,6 @@ test_initializer numpy_array([](py::module &m) {
"array_t<double>"_a=py::array_t<double>() "array_t<double>"_a=py::array_t<double>()
); );
}); });
sm.def("converting_constructors", [](py::object o) { sm.def("converting_constructors", [](py::object o) {
return py::dict( return py::dict(
"array"_a=py::array(o), "array"_a=py::array(o),
...@@ -166,7 +155,7 @@ test_initializer numpy_array([](py::module &m) { ...@@ -166,7 +155,7 @@ test_initializer numpy_array([](py::module &m) {
); );
}); });
// Overload resolution tests: // test_overload_resolution
sm.def("overloaded", [](py::array_t<double>) { return "double"; }); sm.def("overloaded", [](py::array_t<double>) { return "double"; });
sm.def("overloaded", [](py::array_t<float>) { return "float"; }); sm.def("overloaded", [](py::array_t<float>) { return "float"; });
sm.def("overloaded", [](py::array_t<int>) { return "int"; }); sm.def("overloaded", [](py::array_t<int>) { return "int"; });
...@@ -194,11 +183,13 @@ test_initializer numpy_array([](py::module &m) { ...@@ -194,11 +183,13 @@ test_initializer numpy_array([](py::module &m) {
sm.def("overloaded5", [](py::array_t<unsigned int>) { return "unsigned int"; }); sm.def("overloaded5", [](py::array_t<unsigned int>) { return "unsigned int"; });
sm.def("overloaded5", [](py::array_t<double>) { return "double"; }); sm.def("overloaded5", [](py::array_t<double>) { return "double"; });
// test_greedy_string_overload
// Issue 685: ndarray shouldn't go to std::string overload // Issue 685: ndarray shouldn't go to std::string overload
sm.def("issue685", [](std::string) { return "string"; }); sm.def("issue685", [](std::string) { return "string"; });
sm.def("issue685", [](py::array) { return "array"; }); sm.def("issue685", [](py::array) { return "array"; });
sm.def("issue685", [](py::object) { return "other"; }); sm.def("issue685", [](py::object) { return "other"; });
// test_array_unchecked_fixed_dims
sm.def("proxy_add2", [](py::array_t<double> a, double v) { sm.def("proxy_add2", [](py::array_t<double> a, double v) {
auto r = a.mutable_unchecked<2>(); auto r = a.mutable_unchecked<2>();
for (ssize_t i = 0; i < r.shape(0); i++) for (ssize_t i = 0; i < r.shape(0); i++)
...@@ -238,6 +229,7 @@ test_initializer numpy_array([](py::module &m) { ...@@ -238,6 +229,7 @@ test_initializer numpy_array([](py::module &m) {
return auxiliaries(r, r2); return auxiliaries(r, r2);
}); });
// test_array_unchecked_dyn_dims
// Same as the above, but without a compile-time dimensions specification: // Same as the above, but without a compile-time dimensions specification:
sm.def("proxy_add2_dyn", [](py::array_t<double> a, double v) { sm.def("proxy_add2_dyn", [](py::array_t<double> a, double v) {
auto r = a.mutable_unchecked(); auto r = a.mutable_unchecked();
...@@ -264,19 +256,21 @@ test_initializer numpy_array([](py::module &m) { ...@@ -264,19 +256,21 @@ test_initializer numpy_array([](py::module &m) {
return auxiliaries(a, a); return auxiliaries(a, a);
}); });
// test_array_failures
// Issue #785: Uninformative "Unknown internal error" exception when constructing array from empty object: // Issue #785: Uninformative "Unknown internal error" exception when constructing array from empty object:
sm.def("array_fail_test", []() { return py::array(py::object()); }); sm.def("array_fail_test", []() { return py::array(py::object()); });
sm.def("array_t_fail_test", []() { return py::array_t<double>(py::object()); }); sm.def("array_t_fail_test", []() { return py::array_t<double>(py::object()); });
// Make sure the error from numpy is being passed through: // Make sure the error from numpy is being passed through:
sm.def("array_fail_test_negative_size", []() { int c = 0; return py::array(-1, &c); }); sm.def("array_fail_test_negative_size", []() { int c = 0; return py::array(-1, &c); });
// test_initializer_list
// Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous // Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous
sm.def("array_initializer_list", []() { return py::array_t<float>(1); }); // { 1 } also works, but clang warns about it sm.def("array_initializer_list1", []() { return py::array_t<float>(1); }); // { 1 } also works, but clang warns about it
sm.def("array_initializer_list", []() { return py::array_t<float>({ 1, 2 }); }); sm.def("array_initializer_list2", []() { return py::array_t<float>({ 1, 2 }); });
sm.def("array_initializer_list", []() { return py::array_t<float>({ 1, 2, 3 }); }); sm.def("array_initializer_list3", []() { return py::array_t<float>({ 1, 2, 3 }); });
sm.def("array_initializer_list", []() { return py::array_t<float>({ 1, 2, 3, 4 }); }); sm.def("array_initializer_list4", []() { return py::array_t<float>({ 1, 2, 3, 4 }); });
// test_array_resize
// reshape array to 2D without changing size // reshape array to 2D without changing size
sm.def("array_reshape2", [](py::array_t<double> a) { sm.def("array_reshape2", [](py::array_t<double> a) {
const ssize_t dim_sz = (ssize_t)std::sqrt(a.size()); const ssize_t dim_sz = (ssize_t)std::sqrt(a.size());
...@@ -290,6 +284,7 @@ test_initializer numpy_array([](py::module &m) { ...@@ -290,6 +284,7 @@ test_initializer numpy_array([](py::module &m) {
a.resize({N, N, N}, refcheck); a.resize({N, N, N}, refcheck);
}); });
// test_array_create_and_resize
// return 2D array with Nrows = Ncols = N // return 2D array with Nrows = Ncols = N
sm.def("create_and_resize", [](size_t N) { sm.def("create_and_resize", [](size_t N) {
py::array_t<double> a; py::array_t<double> a;
...@@ -297,4 +292,4 @@ test_initializer numpy_array([](py::module &m) { ...@@ -297,4 +292,4 @@ test_initializer numpy_array([](py::module &m) {
std::fill(a.mutable_data(), a.mutable_data() + a.size(), 42.); std::fill(a.mutable_data(), a.mutable_data() + a.size(), 42.);
return a; return a;
}); });
}); }
This diff is collapsed.
...@@ -156,90 +156,6 @@ py::array_t<S, 0> create_recarray(size_t n) { ...@@ -156,90 +156,6 @@ py::array_t<S, 0> create_recarray(size_t n) {
return arr; return arr;
} }
std::string get_format_unbound() {
return py::format_descriptor<UnboundStruct>::format();
}
py::array_t<NestedStruct, 0> create_nested(size_t n) {
auto arr = mkarray_via_buffer<NestedStruct>(n);
auto req = arr.request();
auto ptr = static_cast<NestedStruct*>(req.ptr);
for (size_t i = 0; i < n; i++) {
SET_TEST_VALS(ptr[i].a, i);
SET_TEST_VALS(ptr[i].b, i + 1);
}
return arr;
}
py::array_t<PartialNestedStruct, 0> create_partial_nested(size_t n) {
auto arr = mkarray_via_buffer<PartialNestedStruct>(n);
auto req = arr.request();
auto ptr = static_cast<PartialNestedStruct*>(req.ptr);
for (size_t i = 0; i < n; i++) {
SET_TEST_VALS(ptr[i].a, i);
}
return arr;
}
py::array_t<StringStruct, 0> create_string_array(bool non_empty) {
auto arr = mkarray_via_buffer<StringStruct>(non_empty ? 4 : 0);
if (non_empty) {
auto req = arr.request();
auto ptr = static_cast<StringStruct*>(req.ptr);
for (ssize_t i = 0; i < req.size * req.itemsize; i++)
static_cast<char*>(req.ptr)[i] = 0;
ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a';
ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a';
ptr[3].a[0] = 'a'; ptr[3].b[0] = 'a';
ptr[2].a[1] = 'b'; ptr[2].b[1] = 'b';
ptr[3].a[1] = 'b'; ptr[3].b[1] = 'b';
ptr[3].a[2] = 'c'; ptr[3].b[2] = 'c';
}
return arr;
}
py::array_t<ArrayStruct, 0> create_array_array(size_t n) {
auto arr = mkarray_via_buffer<ArrayStruct>(n);
auto ptr = (ArrayStruct *) arr.mutable_data();
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < 3; j++)
for (size_t k = 0; k < 4; k++)
ptr[i].a[j][k] = char('A' + (i * 100 + j * 10 + k) % 26);
for (size_t j = 0; j < 2; j++)
ptr[i].b[j] = int32_t(i * 1000 + j);
for (size_t j = 0; j < 3; j++)
ptr[i].c[j] = uint8_t(i * 10 + j);
for (size_t j = 0; j < 4; j++)
for (size_t k = 0; k < 2; k++)
ptr[i].d[j][k] = float(i) * 100.0f + float(j) * 10.0f + float(k);
}
return arr;
}
py::array_t<EnumStruct, 0> create_enum_array(size_t n) {
auto arr = mkarray_via_buffer<EnumStruct>(n);
auto ptr = (EnumStruct *) arr.mutable_data();
for (size_t i = 0; i < n; i++) {
ptr[i].e1 = static_cast<E1>(-1 + ((int) i % 2) * 2);
ptr[i].e2 = static_cast<E2>(1 + (i % 2));
}
return arr;
}
py::array_t<ComplexStruct, 0> create_complex_array(size_t n) {
auto arr = mkarray_via_buffer<ComplexStruct>(n);
auto ptr = (ComplexStruct *) arr.mutable_data();
for (size_t i = 0; i < n; i++) {
ptr[i].cflt.real(float(i));
ptr[i].cflt.imag(float(i) + 0.25f);
ptr[i].cdbl.real(double(i) + 0.5);
ptr[i].cdbl.imag(double(i) + 0.75);
}
return arr;
}
template <typename S> template <typename S>
py::list print_recarray(py::array_t<S, 0> arr) { py::list print_recarray(py::array_t<S, 0> arr) {
const auto req = arr.request(); const auto req = arr.request();
...@@ -253,45 +169,6 @@ py::list print_recarray(py::array_t<S, 0> arr) { ...@@ -253,45 +169,6 @@ py::list print_recarray(py::array_t<S, 0> arr) {
return l; return l;
} }
py::list print_format_descriptors() {
const auto fmts = {
py::format_descriptor<SimpleStruct>::format(),
py::format_descriptor<PackedStruct>::format(),
py::format_descriptor<NestedStruct>::format(),
py::format_descriptor<PartialStruct>::format(),
py::format_descriptor<PartialNestedStruct>::format(),
py::format_descriptor<StringStruct>::format(),
py::format_descriptor<ArrayStruct>::format(),
py::format_descriptor<EnumStruct>::format(),
py::format_descriptor<ComplexStruct>::format()
};
auto l = py::list();
for (const auto &fmt : fmts) {
l.append(py::cast(fmt));
}
return l;
}
py::list print_dtypes() {
const auto dtypes = {
py::str(py::dtype::of<SimpleStruct>()),
py::str(py::dtype::of<PackedStruct>()),
py::str(py::dtype::of<NestedStruct>()),
py::str(py::dtype::of<PartialStruct>()),
py::str(py::dtype::of<PartialNestedStruct>()),
py::str(py::dtype::of<StringStruct>()),
py::str(py::dtype::of<ArrayStruct>()),
py::str(py::dtype::of<EnumStruct>()),
py::str(py::dtype::of<StructWithUglyNames>()),
py::str(py::dtype::of<ComplexStruct>())
};
auto l = py::list();
for (const auto &s : dtypes) {
l.append(s);
}
return l;
}
py::array_t<int32_t, 0> test_array_ctors(int i) { py::array_t<int32_t, 0> test_array_ctors(int i) {
using arr_t = py::array_t<int32_t, 0>; using arr_t = py::array_t<int32_t, 0>;
...@@ -367,51 +244,9 @@ py::list test_dtype_ctors() { ...@@ -367,51 +244,9 @@ py::list test_dtype_ctors() {
return list; return list;
} }
struct TrailingPaddingStruct { TEST_SUBMODULE(numpy_dtypes, m) {
int32_t a; try { py::module::import("numpy"); }
char b; catch (...) { return; }
};
py::dtype trailing_padding_dtype() {
return py::dtype::of<TrailingPaddingStruct>();
}
py::dtype buffer_to_dtype(py::buffer& buf) {
return py::dtype(buf.request());
}
py::list test_dtype_methods() {
py::list list;
auto dt1 = py::dtype::of<int32_t>();
auto dt2 = py::dtype::of<SimpleStruct>();
list.append(dt1); list.append(dt2);
list.append(py::bool_(dt1.has_fields())); list.append(py::bool_(dt2.has_fields()));
list.append(py::int_(dt1.itemsize())); list.append(py::int_(dt2.itemsize()));
return list;
}
struct CompareStruct {
bool x;
uint32_t y;
float z;
};
py::list test_compare_buffer_info() {
py::list list;
list.append(py::bool_(py::detail::compare_buffer_info<float>::compare(py::buffer_info(nullptr, sizeof(float), "f", 1))));
list.append(py::bool_(py::detail::compare_buffer_info<unsigned>::compare(py::buffer_info(nullptr, sizeof(int), "I", 1))));
list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(py::buffer_info(nullptr, sizeof(long), "l", 1))));
list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(py::buffer_info(nullptr, sizeof(long), sizeof(long) == sizeof(int) ? "i" : "q", 1))));
list.append(py::bool_(py::detail::compare_buffer_info<CompareStruct>::compare(py::buffer_info(nullptr, sizeof(CompareStruct), "T{?:x:3xI:y:f:z:}", 1))));
return list;
}
test_initializer numpy_dtypes([](py::module &m) {
try {
py::module::import("numpy");
} catch (...) {
return;
}
// typeinfo may be registered before the dtype descriptor for scalar casts to work... // typeinfo may be registered before the dtype descriptor for scalar casts to work...
py::class_<SimpleStruct>(m, "SimpleStruct"); py::class_<SimpleStruct>(m, "SimpleStruct");
...@@ -425,8 +260,6 @@ test_initializer numpy_dtypes([](py::module &m) { ...@@ -425,8 +260,6 @@ test_initializer numpy_dtypes([](py::module &m) {
PYBIND11_NUMPY_DTYPE(ArrayStruct, a, b, c, d); PYBIND11_NUMPY_DTYPE(ArrayStruct, a, b, c, d);
PYBIND11_NUMPY_DTYPE(EnumStruct, e1, e2); PYBIND11_NUMPY_DTYPE(EnumStruct, e1, e2);
PYBIND11_NUMPY_DTYPE(ComplexStruct, cflt, cdbl); PYBIND11_NUMPY_DTYPE(ComplexStruct, cflt, cdbl);
PYBIND11_NUMPY_DTYPE(TrailingPaddingStruct, a, b);
PYBIND11_NUMPY_DTYPE(CompareStruct, x, y, z);
// ... or after // ... or after
py::class_<PackedStruct>(m, "PackedStruct"); py::class_<PackedStruct>(m, "PackedStruct");
...@@ -438,35 +271,181 @@ test_initializer numpy_dtypes([](py::module &m) { ...@@ -438,35 +271,181 @@ test_initializer numpy_dtypes([](py::module &m) {
// struct NotPOD { std::string v; NotPOD() : v("hi") {}; }; // struct NotPOD { std::string v; NotPOD() : v("hi") {}; };
// PYBIND11_NUMPY_DTYPE(NotPOD, v); // PYBIND11_NUMPY_DTYPE(NotPOD, v);
// test_recarray, test_scalar_conversion
m.def("create_rec_simple", &create_recarray<SimpleStruct>); m.def("create_rec_simple", &create_recarray<SimpleStruct>);
m.def("create_rec_packed", &create_recarray<PackedStruct>); m.def("create_rec_packed", &create_recarray<PackedStruct>);
m.def("create_rec_nested", &create_nested); m.def("create_rec_nested", [](size_t n) { // test_signature
py::array_t<NestedStruct, 0> arr = mkarray_via_buffer<NestedStruct>(n);
auto req = arr.request();
auto ptr = static_cast<NestedStruct*>(req.ptr);
for (size_t i = 0; i < n; i++) {
SET_TEST_VALS(ptr[i].a, i);
SET_TEST_VALS(ptr[i].b, i + 1);
}
return arr;
});
m.def("create_rec_partial", &create_recarray<PartialStruct>); m.def("create_rec_partial", &create_recarray<PartialStruct>);
m.def("create_rec_partial_nested", &create_partial_nested); m.def("create_rec_partial_nested", [](size_t n) {
m.def("print_format_descriptors", &print_format_descriptors); py::array_t<PartialNestedStruct, 0> arr = mkarray_via_buffer<PartialNestedStruct>(n);
auto req = arr.request();
auto ptr = static_cast<PartialNestedStruct*>(req.ptr);
for (size_t i = 0; i < n; i++) {
SET_TEST_VALS(ptr[i].a, i);
}
return arr;
});
m.def("print_rec_simple", &print_recarray<SimpleStruct>); m.def("print_rec_simple", &print_recarray<SimpleStruct>);
m.def("print_rec_packed", &print_recarray<PackedStruct>); m.def("print_rec_packed", &print_recarray<PackedStruct>);
m.def("print_rec_nested", &print_recarray<NestedStruct>); m.def("print_rec_nested", &print_recarray<NestedStruct>);
m.def("print_dtypes", &print_dtypes);
m.def("get_format_unbound", &get_format_unbound); // test_format_descriptors
m.def("create_string_array", &create_string_array); m.def("get_format_unbound", []() { return py::format_descriptor<UnboundStruct>::format(); });
m.def("print_format_descriptors", []() {
py::list l;
for (const auto &fmt : {
py::format_descriptor<SimpleStruct>::format(),
py::format_descriptor<PackedStruct>::format(),
py::format_descriptor<NestedStruct>::format(),
py::format_descriptor<PartialStruct>::format(),
py::format_descriptor<PartialNestedStruct>::format(),
py::format_descriptor<StringStruct>::format(),
py::format_descriptor<ArrayStruct>::format(),
py::format_descriptor<EnumStruct>::format(),
py::format_descriptor<ComplexStruct>::format()
}) {
l.append(py::cast(fmt));
}
return l;
});
// test_dtype
m.def("print_dtypes", []() {
py::list l;
for (const py::handle &d : {
py::dtype::of<SimpleStruct>(),
py::dtype::of<PackedStruct>(),
py::dtype::of<NestedStruct>(),
py::dtype::of<PartialStruct>(),
py::dtype::of<PartialNestedStruct>(),
py::dtype::of<StringStruct>(),
py::dtype::of<ArrayStruct>(),
py::dtype::of<EnumStruct>(),
py::dtype::of<StructWithUglyNames>(),
py::dtype::of<ComplexStruct>()
})
l.append(py::str(d));
return l;
});
m.def("test_dtype_ctors", &test_dtype_ctors);
m.def("test_dtype_methods", []() {
py::list list;
auto dt1 = py::dtype::of<int32_t>();
auto dt2 = py::dtype::of<SimpleStruct>();
list.append(dt1); list.append(dt2);
list.append(py::bool_(dt1.has_fields())); list.append(py::bool_(dt2.has_fields()));
list.append(py::int_(dt1.itemsize())); list.append(py::int_(dt2.itemsize()));
return list;
});
struct TrailingPaddingStruct {
int32_t a;
char b;
};
PYBIND11_NUMPY_DTYPE(TrailingPaddingStruct, a, b);
m.def("trailing_padding_dtype", []() { return py::dtype::of<TrailingPaddingStruct>(); });
// test_string_array
m.def("create_string_array", [](bool non_empty) {
py::array_t<StringStruct, 0> arr = mkarray_via_buffer<StringStruct>(non_empty ? 4 : 0);
if (non_empty) {
auto req = arr.request();
auto ptr = static_cast<StringStruct*>(req.ptr);
for (ssize_t i = 0; i < req.size * req.itemsize; i++)
static_cast<char*>(req.ptr)[i] = 0;
ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a';
ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a';
ptr[3].a[0] = 'a'; ptr[3].b[0] = 'a';
ptr[2].a[1] = 'b'; ptr[2].b[1] = 'b';
ptr[3].a[1] = 'b'; ptr[3].b[1] = 'b';
ptr[3].a[2] = 'c'; ptr[3].b[2] = 'c';
}
return arr;
});
m.def("print_string_array", &print_recarray<StringStruct>); m.def("print_string_array", &print_recarray<StringStruct>);
m.def("create_array_array", &create_array_array);
// test_array_array
m.def("create_array_array", [](size_t n) {
py::array_t<ArrayStruct, 0> arr = mkarray_via_buffer<ArrayStruct>(n);
auto ptr = (ArrayStruct *) arr.mutable_data();
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < 3; j++)
for (size_t k = 0; k < 4; k++)
ptr[i].a[j][k] = char('A' + (i * 100 + j * 10 + k) % 26);
for (size_t j = 0; j < 2; j++)
ptr[i].b[j] = int32_t(i * 1000 + j);
for (size_t j = 0; j < 3; j++)
ptr[i].c[j] = uint8_t(i * 10 + j);
for (size_t j = 0; j < 4; j++)
for (size_t k = 0; k < 2; k++)
ptr[i].d[j][k] = float(i) * 100.0f + float(j) * 10.0f + float(k);
}
return arr;
});
m.def("print_array_array", &print_recarray<ArrayStruct>); m.def("print_array_array", &print_recarray<ArrayStruct>);
m.def("create_enum_array", &create_enum_array);
// test_enum_array
m.def("create_enum_array", [](size_t n) {
py::array_t<EnumStruct, 0> arr = mkarray_via_buffer<EnumStruct>(n);
auto ptr = (EnumStruct *) arr.mutable_data();
for (size_t i = 0; i < n; i++) {
ptr[i].e1 = static_cast<E1>(-1 + ((int) i % 2) * 2);
ptr[i].e2 = static_cast<E2>(1 + (i % 2));
}
return arr;
});
m.def("print_enum_array", &print_recarray<EnumStruct>); m.def("print_enum_array", &print_recarray<EnumStruct>);
m.def("create_complex_array", &create_complex_array);
// test_complex_array
m.def("create_complex_array", [](size_t n) {
py::array_t<ComplexStruct, 0> arr = mkarray_via_buffer<ComplexStruct>(n);
auto ptr = (ComplexStruct *) arr.mutable_data();
for (size_t i = 0; i < n; i++) {
ptr[i].cflt.real(float(i));
ptr[i].cflt.imag(float(i) + 0.25f);
ptr[i].cdbl.real(double(i) + 0.5);
ptr[i].cdbl.imag(double(i) + 0.75);
}
return arr;
});
m.def("print_complex_array", &print_recarray<ComplexStruct>); m.def("print_complex_array", &print_recarray<ComplexStruct>);
// test_array_constructors
m.def("test_array_ctors", &test_array_ctors); m.def("test_array_ctors", &test_array_ctors);
m.def("test_dtype_ctors", &test_dtype_ctors);
m.def("test_dtype_methods", &test_dtype_methods); // test_compare_buffer_info
m.def("compare_buffer_info", &test_compare_buffer_info); struct CompareStruct {
m.def("trailing_padding_dtype", &trailing_padding_dtype); bool x;
m.def("buffer_to_dtype", &buffer_to_dtype); uint32_t y;
float z;
};
PYBIND11_NUMPY_DTYPE(CompareStruct, x, y, z);
m.def("compare_buffer_info", []() {
py::list list;
list.append(py::bool_(py::detail::compare_buffer_info<float>::compare(py::buffer_info(nullptr, sizeof(float), "f", 1))));
list.append(py::bool_(py::detail::compare_buffer_info<unsigned>::compare(py::buffer_info(nullptr, sizeof(int), "I", 1))));
list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(py::buffer_info(nullptr, sizeof(long), "l", 1))));
list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(py::buffer_info(nullptr, sizeof(long), sizeof(long) == sizeof(int) ? "i" : "q", 1))));
list.append(py::bool_(py::detail::compare_buffer_info<CompareStruct>::compare(py::buffer_info(nullptr, sizeof(CompareStruct), "T{?:x:3xI:y:f:z:}", 1))));
return list;
});
m.def("buffer_to_dtype", [](py::buffer& buf) { return py::dtype(buf.request()); });
// test_scalar_conversion
m.def("f_simple", [](SimpleStruct s) { return s.uint_ * 10; }); m.def("f_simple", [](SimpleStruct s) { return s.uint_ * 10; });
m.def("f_packed", [](PackedStruct s) { return s.uint_ * 10; }); m.def("f_packed", [](PackedStruct s) { return s.uint_ * 10; });
m.def("f_nested", [](NestedStruct s) { return s.a.uint_ * 10; }); m.def("f_nested", [](NestedStruct s) { return s.a.uint_ * 10; });
m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); });
});
#undef PYBIND11_PACKED // test_register_dtype
m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); });
}
This diff is collapsed.
...@@ -16,22 +16,11 @@ double my_func(int x, float y, double z) { ...@@ -16,22 +16,11 @@ double my_func(int x, float y, double z) {
return (float) x*y*z; return (float) x*y*z;
} }
std::complex<double> my_func3(std::complex<double> c) { TEST_SUBMODULE(numpy_vectorize, m) {
return c * std::complex<double>(2.f); try { py::module::import("numpy"); }
} catch (...) { return; }
struct VectorizeTestClass {
VectorizeTestClass(int v) : value{v} {};
float method(int x, float y) { return y + (float) (x + value); }
int value = 0;
};
struct NonPODClass {
NonPODClass(int v) : value{v} {}
int value;
};
test_initializer numpy_vectorize([](py::module &m) { // test_vectorize, test_docs, test_array_collapse
// Vectorize all arguments of a function (though non-vector arguments are also allowed) // Vectorize all arguments of a function (though non-vector arguments are also allowed)
m.def("vectorized_func", py::vectorize(my_func)); m.def("vectorized_func", py::vectorize(my_func));
...@@ -43,16 +32,24 @@ test_initializer numpy_vectorize([](py::module &m) { ...@@ -43,16 +32,24 @@ test_initializer numpy_vectorize([](py::module &m) {
); );
// Vectorize a complex-valued function // Vectorize a complex-valued function
m.def("vectorized_func3", py::vectorize(my_func3)); m.def("vectorized_func3", py::vectorize(
[](std::complex<double> c) { return c * std::complex<double>(2.f); }
));
/// Numpy function which only accepts specific data types // test_type_selection
// Numpy function which only accepts specific data types
m.def("selective_func", [](py::array_t<int, py::array::c_style>) { return "Int branch taken."; }); m.def("selective_func", [](py::array_t<int, py::array::c_style>) { return "Int branch taken."; });
m.def("selective_func", [](py::array_t<float, py::array::c_style>) { return "Float branch taken."; }); m.def("selective_func", [](py::array_t<float, py::array::c_style>) { return "Float branch taken."; });
m.def("selective_func", [](py::array_t<std::complex<float>, py::array::c_style>) { return "Complex float branch taken."; }); m.def("selective_func", [](py::array_t<std::complex<float>, py::array::c_style>) { return "Complex float branch taken."; });
// test_passthrough_arguments
// Passthrough test: references and non-pod types should be automatically passed through (in the // Passthrough test: references and non-pod types should be automatically passed through (in the
// function definition below, only `b`, `d`, and `g` are vectorized): // function definition below, only `b`, `d`, and `g` are vectorized):
struct NonPODClass {
NonPODClass(int v) : value{v} {}
int value;
};
py::class_<NonPODClass>(m, "NonPODClass").def(py::init<int>()); py::class_<NonPODClass>(m, "NonPODClass").def(py::init<int>());
m.def("vec_passthrough", py::vectorize( m.def("vec_passthrough", py::vectorize(
[](double *a, double b, py::array_t<double> c, const int &d, int &e, NonPODClass f, const double g) { [](double *a, double b, py::array_t<double> c, const int &d, int &e, NonPODClass f, const double g) {
...@@ -60,6 +57,12 @@ test_initializer numpy_vectorize([](py::module &m) { ...@@ -60,6 +57,12 @@ test_initializer numpy_vectorize([](py::module &m) {
} }
)); ));
// test_method_vectorization
struct VectorizeTestClass {
VectorizeTestClass(int v) : value{v} {};
float method(int x, float y) { return y + (float) (x + value); }
int value = 0;
};
py::class_<VectorizeTestClass> vtc(m, "VectorizeTestClass"); py::class_<VectorizeTestClass> vtc(m, "VectorizeTestClass");
vtc .def(py::init<int>()) vtc .def(py::init<int>())
.def_readwrite("value", &VectorizeTestClass::value); .def_readwrite("value", &VectorizeTestClass::value);
...@@ -67,6 +70,7 @@ test_initializer numpy_vectorize([](py::module &m) { ...@@ -67,6 +70,7 @@ test_initializer numpy_vectorize([](py::module &m) {
// Automatic vectorizing of methods // Automatic vectorizing of methods
vtc.def("method", py::vectorize(&VectorizeTestClass::method)); vtc.def("method", py::vectorize(&VectorizeTestClass::method));
// test_trivial_broadcasting
// Internal optimization test for whether the input is trivially broadcastable: // Internal optimization test for whether the input is trivially broadcastable:
py::enum_<py::detail::broadcast_trivial>(m, "trivial") py::enum_<py::detail::broadcast_trivial>(m, "trivial")
.value("f_trivial", py::detail::broadcast_trivial::f_trivial) .value("f_trivial", py::detail::broadcast_trivial::f_trivial)
...@@ -82,4 +86,4 @@ test_initializer numpy_vectorize([](py::module &m) { ...@@ -82,4 +86,4 @@ test_initializer numpy_vectorize([](py::module &m) {
std::array<py::buffer_info, 3> buffers {{ arg1.request(), arg2.request(), arg3.request() }}; std::array<py::buffer_info, 3> buffers {{ arg1.request(), arg2.request(), arg3.request() }};
return py::detail::broadcast(buffers, ndim, shape); return py::detail::broadcast(buffers, ndim, shape);
}); });
}); }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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