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;
}); });
}); }
import pytest import pytest
from pybind11_tests import numpy_array as m
pytestmark = pytest.requires_numpy pytestmark = pytest.requires_numpy
...@@ -12,62 +13,55 @@ def arr(): ...@@ -12,62 +13,55 @@ def arr():
def test_array_attributes(): def test_array_attributes():
from pybind11_tests.array import (
ndim, shape, strides, writeable, size, itemsize, nbytes, owndata
)
a = np.array(0, 'f8') a = np.array(0, 'f8')
assert ndim(a) == 0 assert m.ndim(a) == 0
assert all(shape(a) == []) assert all(m.shape(a) == [])
assert all(strides(a) == []) assert all(m.strides(a) == [])
with pytest.raises(IndexError) as excinfo: with pytest.raises(IndexError) as excinfo:
shape(a, 0) m.shape(a, 0)
assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)' assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)'
with pytest.raises(IndexError) as excinfo: with pytest.raises(IndexError) as excinfo:
strides(a, 0) m.strides(a, 0)
assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)' assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)'
assert writeable(a) assert m.writeable(a)
assert size(a) == 1 assert m.size(a) == 1
assert itemsize(a) == 8 assert m.itemsize(a) == 8
assert nbytes(a) == 8 assert m.nbytes(a) == 8
assert owndata(a) assert m.owndata(a)
a = np.array([[1, 2, 3], [4, 5, 6]], 'u2').view() a = np.array([[1, 2, 3], [4, 5, 6]], 'u2').view()
a.flags.writeable = False a.flags.writeable = False
assert ndim(a) == 2 assert m.ndim(a) == 2
assert all(shape(a) == [2, 3]) assert all(m.shape(a) == [2, 3])
assert shape(a, 0) == 2 assert m.shape(a, 0) == 2
assert shape(a, 1) == 3 assert m.shape(a, 1) == 3
assert all(strides(a) == [6, 2]) assert all(m.strides(a) == [6, 2])
assert strides(a, 0) == 6 assert m.strides(a, 0) == 6
assert strides(a, 1) == 2 assert m.strides(a, 1) == 2
with pytest.raises(IndexError) as excinfo: with pytest.raises(IndexError) as excinfo:
shape(a, 2) m.shape(a, 2)
assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)' assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)'
with pytest.raises(IndexError) as excinfo: with pytest.raises(IndexError) as excinfo:
strides(a, 2) m.strides(a, 2)
assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)' assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)'
assert not writeable(a) assert not m.writeable(a)
assert size(a) == 6 assert m.size(a) == 6
assert itemsize(a) == 2 assert m.itemsize(a) == 2
assert nbytes(a) == 12 assert m.nbytes(a) == 12
assert not owndata(a) assert not m.owndata(a)
@pytest.mark.parametrize('args, ret', [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)]) @pytest.mark.parametrize('args, ret', [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)])
def test_index_offset(arr, args, ret): def test_index_offset(arr, args, ret):
from pybind11_tests.array import index_at, index_at_t, offset_at, offset_at_t assert m.index_at(arr, *args) == ret
assert index_at(arr, *args) == ret assert m.index_at_t(arr, *args) == ret
assert index_at_t(arr, *args) == ret assert m.offset_at(arr, *args) == ret * arr.dtype.itemsize
assert offset_at(arr, *args) == ret * arr.dtype.itemsize assert m.offset_at_t(arr, *args) == ret * arr.dtype.itemsize
assert offset_at_t(arr, *args) == ret * arr.dtype.itemsize
def test_dim_check_fail(arr): def test_dim_check_fail(arr):
from pybind11_tests.array import (index_at, index_at_t, offset_at, offset_at_t, data, data_t, for func in (m.index_at, m.index_at_t, m.offset_at, m.offset_at_t, m.data, m.data_t,
mutate_data, mutate_data_t) m.mutate_data, m.mutate_data_t):
for func in (index_at, index_at_t, offset_at, offset_at_t, data, data_t,
mutate_data, mutate_data_t):
with pytest.raises(IndexError) as excinfo: with pytest.raises(IndexError) as excinfo:
func(arr, 1, 2, 3) func(arr, 1, 2, 3)
assert str(excinfo.value) == 'too many indices for an array: 3 (ndim = 2)' assert str(excinfo.value) == 'too many indices for an array: 3 (ndim = 2)'
...@@ -79,63 +73,53 @@ def test_dim_check_fail(arr): ...@@ -79,63 +73,53 @@ def test_dim_check_fail(arr):
([0, 1], [2, 3, 4, 5, 6]), ([0, 1], [2, 3, 4, 5, 6]),
([1, 2], [6])]) ([1, 2], [6])])
def test_data(arr, args, ret): def test_data(arr, args, ret):
from pybind11_tests.array import data, data_t
from sys import byteorder from sys import byteorder
assert all(data_t(arr, *args) == ret) assert all(m.data_t(arr, *args) == ret)
assert all(data(arr, *args)[(0 if byteorder == 'little' else 1)::2] == ret) assert all(m.data(arr, *args)[(0 if byteorder == 'little' else 1)::2] == ret)
assert all(data(arr, *args)[(1 if byteorder == 'little' else 0)::2] == 0) assert all(m.data(arr, *args)[(1 if byteorder == 'little' else 0)::2] == 0)
def test_mutate_readonly(arr):
from pybind11_tests.array import mutate_data, mutate_data_t, mutate_at_t
arr.flags.writeable = False
for func, args in (mutate_data, ()), (mutate_data_t, ()), (mutate_at_t, (0, 0)):
with pytest.raises(ValueError) as excinfo:
func(arr, *args)
assert str(excinfo.value) == 'array is not writeable'
@pytest.mark.parametrize('dim', [0, 1, 3]) @pytest.mark.parametrize('dim', [0, 1, 3])
def test_at_fail(arr, dim): def test_at_fail(arr, dim):
from pybind11_tests.array import at_t, mutate_at_t for func in m.at_t, m.mutate_at_t:
for func in at_t, mutate_at_t:
with pytest.raises(IndexError) as excinfo: with pytest.raises(IndexError) as excinfo:
func(arr, *([0] * dim)) func(arr, *([0] * dim))
assert str(excinfo.value) == 'index dimension mismatch: {} (ndim = 2)'.format(dim) assert str(excinfo.value) == 'index dimension mismatch: {} (ndim = 2)'.format(dim)
def test_at(arr): def test_at(arr):
from pybind11_tests.array import at_t, mutate_at_t assert m.at_t(arr, 0, 2) == 3
assert m.at_t(arr, 1, 0) == 4
assert all(m.mutate_at_t(arr, 0, 2).ravel() == [1, 2, 4, 4, 5, 6])
assert all(m.mutate_at_t(arr, 1, 0).ravel() == [1, 2, 4, 5, 5, 6])
assert at_t(arr, 0, 2) == 3
assert at_t(arr, 1, 0) == 4
assert all(mutate_at_t(arr, 0, 2).ravel() == [1, 2, 4, 4, 5, 6]) def test_mutate_readonly(arr):
assert all(mutate_at_t(arr, 1, 0).ravel() == [1, 2, 4, 5, 5, 6]) arr.flags.writeable = False
for func, args in (m.mutate_data, ()), (m.mutate_data_t, ()), (m.mutate_at_t, (0, 0)):
with pytest.raises(ValueError) as excinfo:
func(arr, *args)
assert str(excinfo.value) == 'array is not writeable'
def test_mutate_data(arr): def test_mutate_data(arr):
from pybind11_tests.array import mutate_data, mutate_data_t assert all(m.mutate_data(arr).ravel() == [2, 4, 6, 8, 10, 12])
assert all(m.mutate_data(arr).ravel() == [4, 8, 12, 16, 20, 24])
assert all(mutate_data(arr).ravel() == [2, 4, 6, 8, 10, 12]) assert all(m.mutate_data(arr, 1).ravel() == [4, 8, 12, 32, 40, 48])
assert all(mutate_data(arr).ravel() == [4, 8, 12, 16, 20, 24]) assert all(m.mutate_data(arr, 0, 1).ravel() == [4, 16, 24, 64, 80, 96])
assert all(mutate_data(arr, 1).ravel() == [4, 8, 12, 32, 40, 48]) assert all(m.mutate_data(arr, 1, 2).ravel() == [4, 16, 24, 64, 80, 192])
assert all(mutate_data(arr, 0, 1).ravel() == [4, 16, 24, 64, 80, 96])
assert all(mutate_data(arr, 1, 2).ravel() == [4, 16, 24, 64, 80, 192])
assert all(mutate_data_t(arr).ravel() == [5, 17, 25, 65, 81, 193]) assert all(m.mutate_data_t(arr).ravel() == [5, 17, 25, 65, 81, 193])
assert all(mutate_data_t(arr).ravel() == [6, 18, 26, 66, 82, 194]) assert all(m.mutate_data_t(arr).ravel() == [6, 18, 26, 66, 82, 194])
assert all(mutate_data_t(arr, 1).ravel() == [6, 18, 26, 67, 83, 195]) assert all(m.mutate_data_t(arr, 1).ravel() == [6, 18, 26, 67, 83, 195])
assert all(mutate_data_t(arr, 0, 1).ravel() == [6, 19, 27, 68, 84, 196]) assert all(m.mutate_data_t(arr, 0, 1).ravel() == [6, 19, 27, 68, 84, 196])
assert all(mutate_data_t(arr, 1, 2).ravel() == [6, 19, 27, 68, 84, 197]) assert all(m.mutate_data_t(arr, 1, 2).ravel() == [6, 19, 27, 68, 84, 197])
def test_bounds_check(arr): def test_bounds_check(arr):
from pybind11_tests.array import (index_at, index_at_t, data, data_t, for func in (m.index_at, m.index_at_t, m.data, m.data_t,
mutate_data, mutate_data_t, at_t, mutate_at_t) m.mutate_data, m.mutate_data_t, m.at_t, m.mutate_at_t):
funcs = (index_at, index_at_t, data, data_t,
mutate_data, mutate_data_t, at_t, mutate_at_t)
for func in funcs:
with pytest.raises(IndexError) as excinfo: with pytest.raises(IndexError) as excinfo:
func(arr, 2, 0) func(arr, 2, 0)
assert str(excinfo.value) == 'index 2 is out of bounds for axis 0 with size 2' assert str(excinfo.value) == 'index 2 is out of bounds for axis 0 with size 2'
...@@ -145,18 +129,13 @@ def test_bounds_check(arr): ...@@ -145,18 +129,13 @@ def test_bounds_check(arr):
def test_make_c_f_array(): def test_make_c_f_array():
from pybind11_tests.array import ( assert m.make_c_array().flags.c_contiguous
make_c_array, make_f_array assert not m.make_c_array().flags.f_contiguous
) assert m.make_f_array().flags.f_contiguous
assert make_c_array().flags.c_contiguous assert not m.make_f_array().flags.c_contiguous
assert not make_c_array().flags.f_contiguous
assert make_f_array().flags.f_contiguous
assert not make_f_array().flags.c_contiguous
def test_wrap(): def test_wrap():
from pybind11_tests.array import wrap
def assert_references(a, b, base=None): def assert_references(a, b, base=None):
if base is None: if base is None:
base = a base = a
...@@ -178,40 +157,39 @@ def test_wrap(): ...@@ -178,40 +157,39 @@ def test_wrap():
a1 = np.array([1, 2], dtype=np.int16) a1 = np.array([1, 2], dtype=np.int16)
assert a1.flags.owndata and a1.base is None assert a1.flags.owndata and a1.base is None
a2 = wrap(a1) a2 = m.wrap(a1)
assert_references(a1, a2) assert_references(a1, a2)
a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='F') a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='F')
assert a1.flags.owndata and a1.base is None assert a1.flags.owndata and a1.base is None
a2 = wrap(a1) a2 = m.wrap(a1)
assert_references(a1, a2) assert_references(a1, a2)
a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='C') a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='C')
a1.flags.writeable = False a1.flags.writeable = False
a2 = wrap(a1) a2 = m.wrap(a1)
assert_references(a1, a2) assert_references(a1, a2)
a1 = np.random.random((4, 4, 4)) a1 = np.random.random((4, 4, 4))
a2 = wrap(a1) a2 = m.wrap(a1)
assert_references(a1, a2) assert_references(a1, a2)
a1t = a1.transpose() a1t = a1.transpose()
a2 = wrap(a1t) a2 = m.wrap(a1t)
assert_references(a1t, a2, a1) assert_references(a1t, a2, a1)
a1d = a1.diagonal() a1d = a1.diagonal()
a2 = wrap(a1d) a2 = m.wrap(a1d)
assert_references(a1d, a2, a1) assert_references(a1d, a2, a1)
a1m = a1[::-1, ::-1, ::-1] a1m = a1[::-1, ::-1, ::-1]
a2 = wrap(a1m) a2 = m.wrap(a1m)
assert_references(a1m, a2, a1) assert_references(a1m, a2, a1)
def test_numpy_view(capture): def test_numpy_view(capture):
from pybind11_tests.array import ArrayClass
with capture: with capture:
ac = ArrayClass() ac = m.ArrayClass()
ac_view_1 = ac.numpy_view() ac_view_1 = ac.numpy_view()
ac_view_2 = ac.numpy_view() ac_view_2 = ac.numpy_view()
assert np.all(ac_view_1 == np.array([1, 2], dtype=np.int32)) assert np.all(ac_view_1 == np.array([1, 2], dtype=np.int32))
...@@ -238,29 +216,24 @@ def test_numpy_view(capture): ...@@ -238,29 +216,24 @@ def test_numpy_view(capture):
@pytest.unsupported_on_pypy @pytest.unsupported_on_pypy
def test_cast_numpy_int64_to_uint64(): def test_cast_numpy_int64_to_uint64():
from pybind11_tests.array import function_taking_uint64 m.function_taking_uint64(123)
function_taking_uint64(123) m.function_taking_uint64(np.uint64(123))
function_taking_uint64(np.uint64(123))
def test_isinstance(): def test_isinstance():
from pybind11_tests.array import isinstance_untyped, isinstance_typed assert m.isinstance_untyped(np.array([1, 2, 3]), "not an array")
assert m.isinstance_typed(np.array([1.0, 2.0, 3.0]))
assert isinstance_untyped(np.array([1, 2, 3]), "not an array")
assert isinstance_typed(np.array([1.0, 2.0, 3.0]))
def test_constructors(): def test_constructors():
from pybind11_tests.array import default_constructors, converting_constructors defaults = m.default_constructors()
defaults = default_constructors()
for a in defaults.values(): for a in defaults.values():
assert a.size == 0 assert a.size == 0
assert defaults["array"].dtype == np.array([]).dtype assert defaults["array"].dtype == np.array([]).dtype
assert defaults["array_t<int32>"].dtype == np.int32 assert defaults["array_t<int32>"].dtype == np.int32
assert defaults["array_t<double>"].dtype == np.float64 assert defaults["array_t<double>"].dtype == np.float64
results = converting_constructors([1, 2, 3]) results = m.converting_constructors([1, 2, 3])
for a in results.values(): for a in results.values():
np.testing.assert_array_equal(a, [1, 2, 3]) np.testing.assert_array_equal(a, [1, 2, 3])
assert results["array"].dtype == np.int_ assert results["array"].dtype == np.int_
...@@ -269,22 +242,20 @@ def test_constructors(): ...@@ -269,22 +242,20 @@ def test_constructors():
def test_overload_resolution(msg): def test_overload_resolution(msg):
from pybind11_tests.array import overloaded, overloaded2, overloaded3, overloaded4, overloaded5
# Exact overload matches: # Exact overload matches:
assert overloaded(np.array([1], dtype='float64')) == 'double' assert m.overloaded(np.array([1], dtype='float64')) == 'double'
assert overloaded(np.array([1], dtype='float32')) == 'float' assert m.overloaded(np.array([1], dtype='float32')) == 'float'
assert overloaded(np.array([1], dtype='ushort')) == 'unsigned short' assert m.overloaded(np.array([1], dtype='ushort')) == 'unsigned short'
assert overloaded(np.array([1], dtype='intc')) == 'int' assert m.overloaded(np.array([1], dtype='intc')) == 'int'
assert overloaded(np.array([1], dtype='longlong')) == 'long long' assert m.overloaded(np.array([1], dtype='longlong')) == 'long long'
assert overloaded(np.array([1], dtype='complex')) == 'double complex' assert m.overloaded(np.array([1], dtype='complex')) == 'double complex'
assert overloaded(np.array([1], dtype='csingle')) == 'float complex' assert m.overloaded(np.array([1], dtype='csingle')) == 'float complex'
# No exact match, should call first convertible version: # No exact match, should call first convertible version:
assert overloaded(np.array([1], dtype='uint8')) == 'double' assert m.overloaded(np.array([1], dtype='uint8')) == 'double'
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
overloaded("not an array") m.overloaded("not an array")
assert msg(excinfo.value) == """ assert msg(excinfo.value) == """
overloaded(): incompatible function arguments. The following argument types are supported: overloaded(): incompatible function arguments. The following argument types are supported:
1. (arg0: numpy.ndarray[float64]) -> str 1. (arg0: numpy.ndarray[float64]) -> str
...@@ -298,14 +269,14 @@ def test_overload_resolution(msg): ...@@ -298,14 +269,14 @@ def test_overload_resolution(msg):
Invoked with: 'not an array' Invoked with: 'not an array'
""" """
assert overloaded2(np.array([1], dtype='float64')) == 'double' assert m.overloaded2(np.array([1], dtype='float64')) == 'double'
assert overloaded2(np.array([1], dtype='float32')) == 'float' assert m.overloaded2(np.array([1], dtype='float32')) == 'float'
assert overloaded2(np.array([1], dtype='complex64')) == 'float complex' assert m.overloaded2(np.array([1], dtype='complex64')) == 'float complex'
assert overloaded2(np.array([1], dtype='complex128')) == 'double complex' assert m.overloaded2(np.array([1], dtype='complex128')) == 'double complex'
assert overloaded2(np.array([1], dtype='float32')) == 'float' assert m.overloaded2(np.array([1], dtype='float32')) == 'float'
assert overloaded3(np.array([1], dtype='float64')) == 'double' assert m.overloaded3(np.array([1], dtype='float64')) == 'double'
assert overloaded3(np.array([1], dtype='intc')) == 'int' assert m.overloaded3(np.array([1], dtype='intc')) == 'int'
expected_exc = """ expected_exc = """
overloaded3(): incompatible function arguments. The following argument types are supported: overloaded3(): incompatible function arguments. The following argument types are supported:
1. (arg0: numpy.ndarray[int32]) -> str 1. (arg0: numpy.ndarray[int32]) -> str
...@@ -314,122 +285,118 @@ def test_overload_resolution(msg): ...@@ -314,122 +285,118 @@ def test_overload_resolution(msg):
Invoked with:""" Invoked with:"""
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
overloaded3(np.array([1], dtype='uintc')) m.overloaded3(np.array([1], dtype='uintc'))
assert msg(excinfo.value) == expected_exc + " array([1], dtype=uint32)" assert msg(excinfo.value) == expected_exc + " array([1], dtype=uint32)"
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
overloaded3(np.array([1], dtype='float32')) m.overloaded3(np.array([1], dtype='float32'))
assert msg(excinfo.value) == expected_exc + " array([ 1.], dtype=float32)" assert msg(excinfo.value) == expected_exc + " array([ 1.], dtype=float32)"
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
overloaded3(np.array([1], dtype='complex')) m.overloaded3(np.array([1], dtype='complex'))
assert msg(excinfo.value) == expected_exc + " array([ 1.+0.j])" assert msg(excinfo.value) == expected_exc + " array([ 1.+0.j])"
# Exact matches: # Exact matches:
assert overloaded4(np.array([1], dtype='double')) == 'double' assert m.overloaded4(np.array([1], dtype='double')) == 'double'
assert overloaded4(np.array([1], dtype='longlong')) == 'long long' assert m.overloaded4(np.array([1], dtype='longlong')) == 'long long'
# Non-exact matches requiring conversion. Since float to integer isn't a # Non-exact matches requiring conversion. Since float to integer isn't a
# save conversion, it should go to the double overload, but short can go to # save conversion, it should go to the double overload, but short can go to
# either (and so should end up on the first-registered, the long long). # either (and so should end up on the first-registered, the long long).
assert overloaded4(np.array([1], dtype='float32')) == 'double' assert m.overloaded4(np.array([1], dtype='float32')) == 'double'
assert overloaded4(np.array([1], dtype='short')) == 'long long' assert m.overloaded4(np.array([1], dtype='short')) == 'long long'
assert overloaded5(np.array([1], dtype='double')) == 'double' assert m.overloaded5(np.array([1], dtype='double')) == 'double'
assert overloaded5(np.array([1], dtype='uintc')) == 'unsigned int' assert m.overloaded5(np.array([1], dtype='uintc')) == 'unsigned int'
assert overloaded5(np.array([1], dtype='float32')) == 'unsigned int' assert m.overloaded5(np.array([1], dtype='float32')) == 'unsigned int'
def test_greedy_string_overload(): # issue 685 def test_greedy_string_overload():
from pybind11_tests.array import issue685 """Tests fix for #685 - ndarray shouldn't go to std::string overload"""
assert issue685("abc") == "string" assert m.issue685("abc") == "string"
assert issue685(np.array([97, 98, 99], dtype='b')) == "array" assert m.issue685(np.array([97, 98, 99], dtype='b')) == "array"
assert issue685(123) == "other" assert m.issue685(123) == "other"
def test_array_unchecked_fixed_dims(msg): def test_array_unchecked_fixed_dims(msg):
from pybind11_tests.array import (proxy_add2, proxy_init3F, proxy_init3, proxy_squared_L2_norm,
proxy_auxiliaries2, array_auxiliaries2)
z1 = np.array([[1, 2], [3, 4]], dtype='float64') z1 = np.array([[1, 2], [3, 4]], dtype='float64')
proxy_add2(z1, 10) m.proxy_add2(z1, 10)
assert np.all(z1 == [[11, 12], [13, 14]]) assert np.all(z1 == [[11, 12], [13, 14]])
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
proxy_add2(np.array([1., 2, 3]), 5.0) m.proxy_add2(np.array([1., 2, 3]), 5.0)
assert msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2" assert msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2"
expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int') expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int')
assert np.all(proxy_init3(3.0) == expect_c) assert np.all(m.proxy_init3(3.0) == expect_c)
expect_f = np.transpose(expect_c) expect_f = np.transpose(expect_c)
assert np.all(proxy_init3F(3.0) == expect_f) assert np.all(m.proxy_init3F(3.0) == expect_f)
assert proxy_squared_L2_norm(np.array(range(6))) == 55 assert m.proxy_squared_L2_norm(np.array(range(6))) == 55
assert proxy_squared_L2_norm(np.array(range(6), dtype="float64")) == 55 assert m.proxy_squared_L2_norm(np.array(range(6), dtype="float64")) == 55
assert proxy_auxiliaries2(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32] assert m.proxy_auxiliaries2(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
assert proxy_auxiliaries2(z1) == array_auxiliaries2(z1) assert m.proxy_auxiliaries2(z1) == m.array_auxiliaries2(z1)
def test_array_unchecked_dyn_dims(msg): def test_array_unchecked_dyn_dims(msg):
from pybind11_tests.array import (proxy_add2_dyn, proxy_init3_dyn, proxy_auxiliaries2_dyn,
array_auxiliaries2)
z1 = np.array([[1, 2], [3, 4]], dtype='float64') z1 = np.array([[1, 2], [3, 4]], dtype='float64')
proxy_add2_dyn(z1, 10) m.proxy_add2_dyn(z1, 10)
assert np.all(z1 == [[11, 12], [13, 14]]) assert np.all(z1 == [[11, 12], [13, 14]])
expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int') expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int')
assert np.all(proxy_init3_dyn(3.0) == expect_c) assert np.all(m.proxy_init3_dyn(3.0) == expect_c)
assert proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32] assert m.proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
assert proxy_auxiliaries2_dyn(z1) == array_auxiliaries2(z1) assert m.proxy_auxiliaries2_dyn(z1) == m.array_auxiliaries2(z1)
def test_array_failure(): def test_array_failure():
from pybind11_tests.array import (array_fail_test, array_t_fail_test,
array_fail_test_negative_size)
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
array_fail_test() m.array_fail_test()
assert str(excinfo.value) == 'cannot create a pybind11::array from a nullptr' assert str(excinfo.value) == 'cannot create a pybind11::array from a nullptr'
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
array_t_fail_test() m.array_t_fail_test()
assert str(excinfo.value) == 'cannot create a pybind11::array_t from a nullptr' assert str(excinfo.value) == 'cannot create a pybind11::array_t from a nullptr'
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
array_fail_test_negative_size() m.array_fail_test_negative_size()
assert str(excinfo.value) == 'negative dimensions are not allowed' assert str(excinfo.value) == 'negative dimensions are not allowed'
def test_array_resize(msg): def test_initializer_list():
from pybind11_tests.array import (array_reshape2, array_resize3) assert m.array_initializer_list1().shape == (1,)
assert m.array_initializer_list2().shape == (1, 2)
assert m.array_initializer_list3().shape == (1, 2, 3)
assert m.array_initializer_list4().shape == (1, 2, 3, 4)
def test_array_resize(msg):
a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype='float64') a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype='float64')
array_reshape2(a) m.array_reshape2(a)
assert(a.size == 9) assert(a.size == 9)
assert(np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]])) assert(np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
# total size change should succced with refcheck off # total size change should succced with refcheck off
array_resize3(a, 4, False) m.array_resize3(a, 4, False)
assert(a.size == 64) assert(a.size == 64)
# ... and fail with refcheck on # ... and fail with refcheck on
try: try:
array_resize3(a, 3, True) m.array_resize3(a, 3, True)
except ValueError as e: except ValueError as e:
assert(str(e).startswith("cannot resize an array")) assert(str(e).startswith("cannot resize an array"))
# transposed array doesn't own data # transposed array doesn't own data
b = a.transpose() b = a.transpose()
try: try:
array_resize3(b, 3, False) m.array_resize3(b, 3, False)
except ValueError as e: except ValueError as e:
assert(str(e).startswith("cannot resize this array: it does not own its data")) assert(str(e).startswith("cannot resize this array: it does not own its data"))
# ... but reshape should be fine # ... but reshape should be fine
array_reshape2(b) m.array_reshape2(b)
assert(b.shape == (8, 8)) assert(b.shape == (8, 8))
@pytest.unsupported_on_pypy @pytest.unsupported_on_pypy
def test_array_create_and_resize(msg): def test_array_create_and_resize(msg):
from pybind11_tests.array import create_and_resize a = m.create_and_resize(2)
a = create_and_resize(2)
assert(a.size == 4) assert(a.size == 4)
assert(np.all(a == 42.)) assert(np.all(a == 42.))
...@@ -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_); });
}
import re import re
import pytest import pytest
from pybind11_tests import numpy_dtypes as m
pytestmark = pytest.requires_numpy pytestmark = pytest.requires_numpy
...@@ -65,10 +66,8 @@ def assert_equal(actual, expected_data, expected_dtype): ...@@ -65,10 +66,8 @@ def assert_equal(actual, expected_data, expected_dtype):
def test_format_descriptors(): def test_format_descriptors():
from pybind11_tests import get_format_unbound, print_format_descriptors
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
get_format_unbound() m.get_format_unbound()
assert re.match('^NumPy type info missing for .*UnboundStruct.*$', str(excinfo.value)) assert re.match('^NumPy type info missing for .*UnboundStruct.*$', str(excinfo.value))
ld = np.dtype('longdouble') ld = np.dtype('longdouble')
...@@ -79,7 +78,7 @@ def test_format_descriptors(): ...@@ -79,7 +78,7 @@ def test_format_descriptors():
str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8)) + str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8)) +
"xg:ldbl_:}") "xg:ldbl_:}")
nested_extra = str(max(8, ld.alignment)) nested_extra = str(max(8, ld.alignment))
assert print_format_descriptors() == [ assert m.print_format_descriptors() == [
ss_fmt, ss_fmt,
"^T{?:bool_:I:uint_:f:float_:g:ldbl_:}", "^T{?:bool_:I:uint_:f:float_:g:ldbl_:}",
"^T{" + ss_fmt + ":a:^T{?:bool_:I:uint_:f:float_:g:ldbl_:}:b:}", "^T{" + ss_fmt + ":a:^T{?:bool_:I:uint_:f:float_:g:ldbl_:}:b:}",
...@@ -93,12 +92,10 @@ def test_format_descriptors(): ...@@ -93,12 +92,10 @@ def test_format_descriptors():
def test_dtype(simple_dtype): def test_dtype(simple_dtype):
from pybind11_tests import (print_dtypes, test_dtype_ctors, test_dtype_methods,
trailing_padding_dtype, buffer_to_dtype)
from sys import byteorder from sys import byteorder
e = '<' if byteorder == 'little' else '>' e = '<' if byteorder == 'little' else '>'
assert print_dtypes() == [ assert m.print_dtypes() == [
simple_dtype_fmt(), simple_dtype_fmt(),
packed_dtype_fmt(), packed_dtype_fmt(),
"[('a', {}), ('b', {})]".format(simple_dtype_fmt(), packed_dtype_fmt()), "[('a', {}), ('b', {})]".format(simple_dtype_fmt(), packed_dtype_fmt()),
...@@ -116,23 +113,19 @@ def test_dtype(simple_dtype): ...@@ -116,23 +113,19 @@ def test_dtype(simple_dtype):
d1 = np.dtype({'names': ['a', 'b'], 'formats': ['int32', 'float64'], d1 = np.dtype({'names': ['a', 'b'], 'formats': ['int32', 'float64'],
'offsets': [1, 10], 'itemsize': 20}) 'offsets': [1, 10], 'itemsize': 20})
d2 = np.dtype([('a', 'i4'), ('b', 'f4')]) d2 = np.dtype([('a', 'i4'), ('b', 'f4')])
assert test_dtype_ctors() == [np.dtype('int32'), np.dtype('float64'), assert m.test_dtype_ctors() == [np.dtype('int32'), np.dtype('float64'),
np.dtype('bool'), d1, d1, np.dtype('uint32'), d2] np.dtype('bool'), d1, d1, np.dtype('uint32'), d2]
assert test_dtype_methods() == [np.dtype('int32'), simple_dtype, False, True, assert m.test_dtype_methods() == [np.dtype('int32'), simple_dtype, False, True,
np.dtype('int32').itemsize, simple_dtype.itemsize] np.dtype('int32').itemsize, simple_dtype.itemsize]
assert trailing_padding_dtype() == buffer_to_dtype(np.zeros(1, trailing_padding_dtype())) assert m.trailing_padding_dtype() == m.buffer_to_dtype(np.zeros(1, m.trailing_padding_dtype()))
def test_recarray(simple_dtype, packed_dtype): def test_recarray(simple_dtype, packed_dtype):
from pybind11_tests import (create_rec_simple, create_rec_packed, create_rec_nested,
print_rec_simple, print_rec_packed, print_rec_nested,
create_rec_partial, create_rec_partial_nested)
elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)] elements = [(False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)]
for func, dtype in [(create_rec_simple, simple_dtype), (create_rec_packed, packed_dtype)]: for func, dtype in [(m.create_rec_simple, simple_dtype), (m.create_rec_packed, packed_dtype)]:
arr = func(0) arr = func(0)
assert arr.dtype == dtype assert arr.dtype == dtype
assert_equal(arr, [], simple_dtype) assert_equal(arr, [], simple_dtype)
...@@ -144,13 +137,13 @@ def test_recarray(simple_dtype, packed_dtype): ...@@ -144,13 +137,13 @@ def test_recarray(simple_dtype, packed_dtype):
assert_equal(arr, elements, packed_dtype) assert_equal(arr, elements, packed_dtype)
if dtype == simple_dtype: if dtype == simple_dtype:
assert print_rec_simple(arr) == [ assert m.print_rec_simple(arr) == [
"s:0,0,0,-0", "s:0,0,0,-0",
"s:1,1,1.5,-2.5", "s:1,1,1.5,-2.5",
"s:0,2,3,-5" "s:0,2,3,-5"
] ]
else: else:
assert print_rec_packed(arr) == [ assert m.print_rec_packed(arr) == [
"p:0,0,0,-0", "p:0,0,0,-0",
"p:1,1,1.5,-2.5", "p:1,1,1.5,-2.5",
"p:0,2,3,-5" "p:0,2,3,-5"
...@@ -158,22 +151,22 @@ def test_recarray(simple_dtype, packed_dtype): ...@@ -158,22 +151,22 @@ def test_recarray(simple_dtype, packed_dtype):
nested_dtype = np.dtype([('a', simple_dtype), ('b', packed_dtype)]) nested_dtype = np.dtype([('a', simple_dtype), ('b', packed_dtype)])
arr = create_rec_nested(0) arr = m.create_rec_nested(0)
assert arr.dtype == nested_dtype assert arr.dtype == nested_dtype
assert_equal(arr, [], nested_dtype) assert_equal(arr, [], nested_dtype)
arr = create_rec_nested(3) arr = m.create_rec_nested(3)
assert arr.dtype == nested_dtype assert arr.dtype == nested_dtype
assert_equal(arr, [((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)), assert_equal(arr, [((False, 0, 0.0, -0.0), (True, 1, 1.5, -2.5)),
((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)), ((True, 1, 1.5, -2.5), (False, 2, 3.0, -5.0)),
((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5))], nested_dtype) ((False, 2, 3.0, -5.0), (True, 3, 4.5, -7.5))], nested_dtype)
assert print_rec_nested(arr) == [ assert m.print_rec_nested(arr) == [
"n:a=s:0,0,0,-0;b=p:1,1,1.5,-2.5", "n:a=s:0,0,0,-0;b=p:1,1,1.5,-2.5",
"n:a=s:1,1,1.5,-2.5;b=p:0,2,3,-5", "n:a=s:1,1,1.5,-2.5;b=p:0,2,3,-5",
"n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5" "n:a=s:0,2,3,-5;b=p:1,3,4.5,-7.5"
] ]
arr = create_rec_partial(3) arr = m.create_rec_partial(3)
assert str(arr.dtype) == partial_dtype_fmt() assert str(arr.dtype) == partial_dtype_fmt()
partial_dtype = arr.dtype partial_dtype = arr.dtype
assert '' not in arr.dtype.fields assert '' not in arr.dtype.fields
...@@ -181,32 +174,28 @@ def test_recarray(simple_dtype, packed_dtype): ...@@ -181,32 +174,28 @@ def test_recarray(simple_dtype, packed_dtype):
assert_equal(arr, elements, simple_dtype) assert_equal(arr, elements, simple_dtype)
assert_equal(arr, elements, packed_dtype) assert_equal(arr, elements, packed_dtype)
arr = create_rec_partial_nested(3) arr = m.create_rec_partial_nested(3)
assert str(arr.dtype) == partial_nested_fmt() assert str(arr.dtype) == partial_nested_fmt()
assert '' not in arr.dtype.fields assert '' not in arr.dtype.fields
assert '' not in arr.dtype.fields['a'][0].fields assert '' not in arr.dtype.fields['a'][0].fields
assert arr.dtype.itemsize > partial_dtype.itemsize assert arr.dtype.itemsize > partial_dtype.itemsize
np.testing.assert_equal(arr['a'], create_rec_partial(3)) np.testing.assert_equal(arr['a'], m.create_rec_partial(3))
def test_array_constructors(): def test_array_constructors():
from pybind11_tests import test_array_ctors
data = np.arange(1, 7, dtype='int32') data = np.arange(1, 7, dtype='int32')
for i in range(8): for i in range(8):
np.testing.assert_array_equal(test_array_ctors(10 + i), data.reshape((3, 2))) np.testing.assert_array_equal(m.test_array_ctors(10 + i), data.reshape((3, 2)))
np.testing.assert_array_equal(test_array_ctors(20 + i), data.reshape((3, 2))) np.testing.assert_array_equal(m.test_array_ctors(20 + i), data.reshape((3, 2)))
for i in range(5): for i in range(5):
np.testing.assert_array_equal(test_array_ctors(30 + i), data) np.testing.assert_array_equal(m.test_array_ctors(30 + i), data)
np.testing.assert_array_equal(test_array_ctors(40 + i), data) np.testing.assert_array_equal(m.test_array_ctors(40 + i), data)
def test_string_array(): def test_string_array():
from pybind11_tests import create_string_array, print_string_array arr = m.create_string_array(True)
arr = create_string_array(True)
assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]" assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]"
assert print_string_array(arr) == [ assert m.print_string_array(arr) == [
"a='',b=''", "a='',b=''",
"a='a',b='a'", "a='a',b='a'",
"a='ab',b='ab'", "a='ab',b='ab'",
...@@ -215,21 +204,20 @@ def test_string_array(): ...@@ -215,21 +204,20 @@ def test_string_array():
dtype = arr.dtype dtype = arr.dtype
assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc'] assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc']
assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc'] assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc']
arr = create_string_array(False) arr = m.create_string_array(False)
assert dtype == arr.dtype assert dtype == arr.dtype
def test_array_array(): def test_array_array():
from pybind11_tests import create_array_array, print_array_array
from sys import byteorder from sys import byteorder
e = '<' if byteorder == 'little' else '>' e = '<' if byteorder == 'little' else '>'
arr = create_array_array(3) arr = m.create_array_array(3)
assert str(arr.dtype) == ( assert str(arr.dtype) == (
"{{'names':['a','b','c','d'], " + "{{'names':['a','b','c','d'], " +
"'formats':[('S4', (3,)),('<i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], " + "'formats':[('S4', (3,)),('<i4', (2,)),('u1', (3,)),('{e}f4', (4, 2))], " +
"'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e) "'offsets':[0,12,20,24], 'itemsize':56}}").format(e=e)
assert print_array_array(arr) == [ assert m.print_array_array(arr) == [
"a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1}," + "a={{A,B,C,D},{K,L,M,N},{U,V,W,X}},b={0,1}," +
"c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}", "c={0,1,2},d={{0,1},{10,11},{20,21},{30,31}}",
"a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001}," + "a={{W,X,Y,Z},{G,H,I,J},{Q,R,S,T}},b={1000,1001}," +
...@@ -241,61 +229,53 @@ def test_array_array(): ...@@ -241,61 +229,53 @@ def test_array_array():
[b'WXYZ', b'GHIJ', b'QRST'], [b'WXYZ', b'GHIJ', b'QRST'],
[b'STUV', b'CDEF', b'MNOP']] [b'STUV', b'CDEF', b'MNOP']]
assert arr['b'].tolist() == [[0, 1], [1000, 1001], [2000, 2001]] assert arr['b'].tolist() == [[0, 1], [1000, 1001], [2000, 2001]]
assert create_array_array(0).dtype == arr.dtype assert m.create_array_array(0).dtype == arr.dtype
def test_enum_array(): def test_enum_array():
from pybind11_tests import create_enum_array, print_enum_array
from sys import byteorder from sys import byteorder
e = '<' if byteorder == 'little' else '>' e = '<' if byteorder == 'little' else '>'
arr = create_enum_array(3) arr = m.create_enum_array(3)
dtype = arr.dtype dtype = arr.dtype
assert dtype == np.dtype([('e1', e + 'i8'), ('e2', 'u1')]) assert dtype == np.dtype([('e1', e + 'i8'), ('e2', 'u1')])
assert print_enum_array(arr) == [ assert m.print_enum_array(arr) == [
"e1=A,e2=X", "e1=A,e2=X",
"e1=B,e2=Y", "e1=B,e2=Y",
"e1=A,e2=X" "e1=A,e2=X"
] ]
assert arr['e1'].tolist() == [-1, 1, -1] assert arr['e1'].tolist() == [-1, 1, -1]
assert arr['e2'].tolist() == [1, 2, 1] assert arr['e2'].tolist() == [1, 2, 1]
assert create_enum_array(0).dtype == dtype assert m.create_enum_array(0).dtype == dtype
def test_complex_array(): def test_complex_array():
from pybind11_tests import create_complex_array, print_complex_array
from sys import byteorder from sys import byteorder
e = '<' if byteorder == 'little' else '>' e = '<' if byteorder == 'little' else '>'
arr = create_complex_array(3) arr = m.create_complex_array(3)
dtype = arr.dtype dtype = arr.dtype
assert dtype == np.dtype([('cflt', e + 'c8'), ('cdbl', e + 'c16')]) assert dtype == np.dtype([('cflt', e + 'c8'), ('cdbl', e + 'c16')])
assert print_complex_array(arr) == [ assert m.print_complex_array(arr) == [
"c:(0,0.25),(0.5,0.75)", "c:(0,0.25),(0.5,0.75)",
"c:(1,1.25),(1.5,1.75)", "c:(1,1.25),(1.5,1.75)",
"c:(2,2.25),(2.5,2.75)" "c:(2,2.25),(2.5,2.75)"
] ]
assert arr['cflt'].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j] assert arr['cflt'].tolist() == [0.0 + 0.25j, 1.0 + 1.25j, 2.0 + 2.25j]
assert arr['cdbl'].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j] assert arr['cdbl'].tolist() == [0.5 + 0.75j, 1.5 + 1.75j, 2.5 + 2.75j]
assert create_complex_array(0).dtype == dtype assert m.create_complex_array(0).dtype == dtype
def test_signature(doc): def test_signature(doc):
from pybind11_tests import create_rec_nested assert doc(m.create_rec_nested) == \
"create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
assert doc(create_rec_nested) == "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
def test_scalar_conversion(): def test_scalar_conversion():
from pybind11_tests import (create_rec_simple, f_simple,
create_rec_packed, f_packed,
create_rec_nested, f_nested,
create_enum_array)
n = 3 n = 3
arrays = [create_rec_simple(n), create_rec_packed(n), arrays = [m.create_rec_simple(n), m.create_rec_packed(n),
create_rec_nested(n), create_enum_array(n)] m.create_rec_nested(n), m.create_enum_array(n)]
funcs = [f_simple, f_packed, f_nested] funcs = [m.f_simple, m.f_packed, m.f_nested]
for i, func in enumerate(funcs): for i, func in enumerate(funcs):
for j, arr in enumerate(arrays): for j, arr in enumerate(arrays):
...@@ -308,14 +288,11 @@ def test_scalar_conversion(): ...@@ -308,14 +288,11 @@ def test_scalar_conversion():
def test_register_dtype(): def test_register_dtype():
from pybind11_tests import register_dtype
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
register_dtype() m.register_dtype()
assert 'dtype is already registered' in str(excinfo.value) assert 'dtype is already registered' in str(excinfo.value)
@pytest.requires_numpy @pytest.requires_numpy
def test_compare_buffer_info(): def test_compare_buffer_info():
from pybind11_tests import compare_buffer_info assert all(m.compare_buffer_info())
assert all(compare_buffer_info())
...@@ -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);
}); });
}); }
import pytest import pytest
from pybind11_tests import numpy_vectorize as m
pytestmark = pytest.requires_numpy pytestmark = pytest.requires_numpy
...@@ -7,11 +8,9 @@ with pytest.suppress(ImportError): ...@@ -7,11 +8,9 @@ with pytest.suppress(ImportError):
def test_vectorize(capture): def test_vectorize(capture):
from pybind11_tests import vectorized_func, vectorized_func2, vectorized_func3 assert np.isclose(m.vectorized_func3(np.array(3 + 7j)), [6 + 14j])
assert np.isclose(vectorized_func3(np.array(3 + 7j)), [6 + 14j]) for f in [m.vectorized_func, m.vectorized_func2]:
for f in [vectorized_func, vectorized_func2]:
with capture: with capture:
assert np.isclose(f(1, 2, 3), 6) assert np.isclose(f(1, 2, 3), 6)
assert capture == "my_func(x:int=1, y:float=2, z:float=3)" assert capture == "my_func(x:int=1, y:float=2, z:float=3)"
...@@ -103,23 +102,19 @@ def test_vectorize(capture): ...@@ -103,23 +102,19 @@ def test_vectorize(capture):
def test_type_selection(): def test_type_selection():
from pybind11_tests import selective_func assert m.selective_func(np.array([1], dtype=np.int32)) == "Int branch taken."
assert m.selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken."
assert selective_func(np.array([1], dtype=np.int32)) == "Int branch taken." assert m.selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken."
assert selective_func(np.array([1.0], dtype=np.float32)) == "Float branch taken."
assert selective_func(np.array([1.0j], dtype=np.complex64)) == "Complex float branch taken."
def test_docs(doc): def test_docs(doc):
from pybind11_tests import vectorized_func assert doc(m.vectorized_func) == """
assert doc(vectorized_func) == """
vectorized_func(arg0: numpy.ndarray[int32], arg1: numpy.ndarray[float32], arg2: numpy.ndarray[float64]) -> object vectorized_func(arg0: numpy.ndarray[int32], arg1: numpy.ndarray[float32], arg2: numpy.ndarray[float64]) -> object
""" # noqa: E501 line too long """ # noqa: E501 line too long
def test_trivial_broadcasting(): def test_trivial_broadcasting():
from pybind11_tests import vectorized_is_trivial, trivial, vectorized_func trivial, vectorized_is_trivial = m.trivial, m.vectorized_is_trivial
assert vectorized_is_trivial(1, 2, 3) == trivial.c_trivial assert vectorized_is_trivial(1, 2, 3) == trivial.c_trivial
assert vectorized_is_trivial(np.array(1), np.array(2), 3) == trivial.c_trivial assert vectorized_is_trivial(np.array(1), np.array(2), 3) == trivial.c_trivial
...@@ -153,51 +148,49 @@ def test_trivial_broadcasting(): ...@@ -153,51 +148,49 @@ def test_trivial_broadcasting():
assert vectorized_is_trivial(z1[1::4, 1::4], y2, 1) == trivial.f_trivial assert vectorized_is_trivial(z1[1::4, 1::4], y2, 1) == trivial.f_trivial
assert vectorized_is_trivial(y1[1::4, 1::4], z2, 1) == trivial.c_trivial assert vectorized_is_trivial(y1[1::4, 1::4], z2, 1) == trivial.c_trivial
assert vectorized_func(z1, z2, z3).flags.c_contiguous assert m.vectorized_func(z1, z2, z3).flags.c_contiguous
assert vectorized_func(y1, y2, y3).flags.f_contiguous assert m.vectorized_func(y1, y2, y3).flags.f_contiguous
assert vectorized_func(z1, 1, 1).flags.c_contiguous assert m.vectorized_func(z1, 1, 1).flags.c_contiguous
assert vectorized_func(1, y2, 1).flags.f_contiguous assert m.vectorized_func(1, y2, 1).flags.f_contiguous
assert vectorized_func(z1[1::4, 1::4], y2, 1).flags.f_contiguous assert m.vectorized_func(z1[1::4, 1::4], y2, 1).flags.f_contiguous
assert vectorized_func(y1[1::4, 1::4], z2, 1).flags.c_contiguous assert m.vectorized_func(y1[1::4, 1::4], z2, 1).flags.c_contiguous
def test_passthrough_arguments(doc): def test_passthrough_arguments(doc):
from pybind11_tests import vec_passthrough, NonPODClass assert doc(m.vec_passthrough) == (
"vec_passthrough(" + ", ".join([
assert doc(vec_passthrough) == ( "arg0: float",
"vec_passthrough(" "arg1: numpy.ndarray[float64]",
"arg0: float, arg1: numpy.ndarray[float64], arg2: numpy.ndarray[float64], " "arg2: numpy.ndarray[float64]",
"arg3: numpy.ndarray[int32], arg4: int, arg5: m.NonPODClass, arg6: numpy.ndarray[float64]" "arg3: numpy.ndarray[int32]",
") -> object") "arg4: int",
"arg5: m.numpy_vectorize.NonPODClass",
"arg6: numpy.ndarray[float64]"]) + ") -> object")
b = np.array([[10, 20, 30]], dtype='float64') b = np.array([[10, 20, 30]], dtype='float64')
c = np.array([100, 200]) # NOT a vectorized argument c = np.array([100, 200]) # NOT a vectorized argument
d = np.array([[1000], [2000], [3000]], dtype='int') d = np.array([[1000], [2000], [3000]], dtype='int')
g = np.array([[1000000, 2000000, 3000000]], dtype='int') # requires casting g = np.array([[1000000, 2000000, 3000000]], dtype='int') # requires casting
assert np.all( assert np.all(
vec_passthrough(1, b, c, d, 10000, NonPODClass(100000), g) == m.vec_passthrough(1, b, c, d, 10000, m.NonPODClass(100000), g) ==
np.array([[1111111, 2111121, 3111131], np.array([[1111111, 2111121, 3111131],
[1112111, 2112121, 3112131], [1112111, 2112121, 3112131],
[1113111, 2113121, 3113131]])) [1113111, 2113121, 3113131]]))
def test_method_vectorization(): def test_method_vectorization():
from pybind11_tests import VectorizeTestClass o = m.VectorizeTestClass(3)
o = VectorizeTestClass(3)
x = np.array([1, 2], dtype='int') x = np.array([1, 2], dtype='int')
y = np.array([[10], [20]], dtype='float32') y = np.array([[10], [20]], dtype='float32')
assert np.all(o.method(x, y) == [[14, 15], [24, 25]]) assert np.all(o.method(x, y) == [[14, 15], [24, 25]])
def test_array_collapse(): def test_array_collapse():
from pybind11_tests import vectorized_func assert not isinstance(m.vectorized_func(1, 2, 3), np.ndarray)
assert not isinstance(m.vectorized_func(np.array(1), 2, 3), np.ndarray)
assert not isinstance(vectorized_func(1, 2, 3), np.ndarray) z = m.vectorized_func([1], 2, 3)
assert not isinstance(vectorized_func(np.array(1), 2, 3), np.ndarray)
z = vectorized_func([1], 2, 3)
assert isinstance(z, np.ndarray) assert isinstance(z, np.ndarray)
assert z.shape == (1, ) assert z.shape == (1, )
z = vectorized_func(1, [[[2]]], 3) z = m.vectorized_func(1, [[[2]]], 3)
assert isinstance(z, np.ndarray) assert isinstance(z, np.ndarray)
assert z.shape == (1, 1, 1) assert z.shape == (1, 1, 1)
...@@ -11,17 +11,13 @@ ...@@ -11,17 +11,13 @@
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include <vector> #include <vector>
typedef std::vector<std::string> StringList; using StringList = std::vector<std::string>;
class ClassWithSTLVecProperty {
public:
StringList stringList;
};
/* IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures */ /* IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures */
PYBIND11_MAKE_OPAQUE(StringList); PYBIND11_MAKE_OPAQUE(StringList);
test_initializer opaque_types([](py::module &m) { TEST_SUBMODULE(opaque_types, m) {
// test_string_list
py::class_<StringList>(m, "StringList") py::class_<StringList>(m, "StringList")
.def(py::init<>()) .def(py::init<>())
.def("pop_back", &StringList::pop_back) .def("pop_back", &StringList::pop_back)
...@@ -33,6 +29,10 @@ test_initializer opaque_types([](py::module &m) { ...@@ -33,6 +29,10 @@ test_initializer opaque_types([](py::module &m) {
return py::make_iterator(v.begin(), v.end()); return py::make_iterator(v.begin(), v.end());
}, py::keep_alive<0, 1>()); }, py::keep_alive<0, 1>());
class ClassWithSTLVecProperty {
public:
StringList stringList;
};
py::class_<ClassWithSTLVecProperty>(m, "ClassWithSTLVecProperty") py::class_<ClassWithSTLVecProperty>(m, "ClassWithSTLVecProperty")
.def(py::init<>()) .def(py::init<>())
.def_readwrite("stringList", &ClassWithSTLVecProperty::stringList); .def_readwrite("stringList", &ClassWithSTLVecProperty::stringList);
...@@ -49,6 +49,7 @@ test_initializer opaque_types([](py::module &m) { ...@@ -49,6 +49,7 @@ test_initializer opaque_types([](py::module &m) {
return ret + "]"; return ret + "]";
}); });
// test_pointers
m.def("return_void_ptr", []() { return (void *) 0x1234; }); m.def("return_void_ptr", []() { return (void *) 0x1234; });
m.def("get_void_ptr_value", [](void *ptr) { return reinterpret_cast<std::intptr_t>(ptr); }); m.def("get_void_ptr_value", [](void *ptr) { return reinterpret_cast<std::intptr_t>(ptr); });
m.def("return_null_str", []() { return (char *) nullptr; }); m.def("return_null_str", []() { return (char *) nullptr; });
...@@ -59,4 +60,4 @@ test_initializer opaque_types([](py::module &m) { ...@@ -59,4 +60,4 @@ test_initializer opaque_types([](py::module &m) {
result->push_back("some value"); result->push_back("some value");
return std::unique_ptr<StringList>(result); return std::unique_ptr<StringList>(result);
}); });
}); }
import pytest import pytest
from pybind11_tests import opaque_types as m
from pybind11_tests import ConstructorStats, UserType
def test_string_list(): def test_string_list():
from pybind11_tests import StringList, ClassWithSTLVecProperty, print_opaque_list l = m.StringList()
l = StringList()
l.push_back("Element 1") l.push_back("Element 1")
l.push_back("Element 2") l.push_back("Element 2")
assert print_opaque_list(l) == "Opaque list: [Element 1, Element 2]" assert m.print_opaque_list(l) == "Opaque list: [Element 1, Element 2]"
assert l.back() == "Element 2" assert l.back() == "Element 2"
for i, k in enumerate(l, start=1): for i, k in enumerate(l, start=1):
assert k == "Element {}".format(i) assert k == "Element {}".format(i)
l.pop_back() l.pop_back()
assert print_opaque_list(l) == "Opaque list: [Element 1]" assert m.print_opaque_list(l) == "Opaque list: [Element 1]"
cvp = ClassWithSTLVecProperty() cvp = m.ClassWithSTLVecProperty()
assert print_opaque_list(cvp.stringList) == "Opaque list: []" assert m.print_opaque_list(cvp.stringList) == "Opaque list: []"
cvp.stringList = l cvp.stringList = l
cvp.stringList.push_back("Element 3") cvp.stringList.push_back("Element 3")
assert print_opaque_list(cvp.stringList) == "Opaque list: [Element 1, Element 3]" assert m.print_opaque_list(cvp.stringList) == "Opaque list: [Element 1, Element 3]"
def test_pointers(msg): def test_pointers(msg):
from pybind11_tests import (return_void_ptr, get_void_ptr_value, ExampleMandA, living_before = ConstructorStats.get(UserType).alive()
print_opaque_list, return_null_str, get_null_str_value, assert m.get_void_ptr_value(m.return_void_ptr()) == 0x1234
return_unique_ptr, ConstructorStats) assert m.get_void_ptr_value(UserType()) # Should also work for other C++ types
assert ConstructorStats.get(UserType).alive() == living_before
living_before = ConstructorStats.get(ExampleMandA).alive()
assert get_void_ptr_value(return_void_ptr()) == 0x1234
assert get_void_ptr_value(ExampleMandA()) # Should also work for other C++ types
assert ConstructorStats.get(ExampleMandA).alive() == living_before
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
get_void_ptr_value([1, 2, 3]) # This should not work m.get_void_ptr_value([1, 2, 3]) # This should not work
assert msg(excinfo.value) == """ assert msg(excinfo.value) == """
get_void_ptr_value(): incompatible function arguments. The following argument types are supported: get_void_ptr_value(): incompatible function arguments. The following argument types are supported:
1. (arg0: capsule) -> int 1. (arg0: capsule) -> int
...@@ -42,9 +38,9 @@ def test_pointers(msg): ...@@ -42,9 +38,9 @@ def test_pointers(msg):
Invoked with: [1, 2, 3] Invoked with: [1, 2, 3]
""" # noqa: E501 line too long """ # noqa: E501 line too long
assert return_null_str() is None assert m.return_null_str() is None
assert get_null_str_value(return_null_str()) is not None assert m.get_null_str_value(m.return_null_str()) is not None
ptr = return_unique_ptr() ptr = m.return_unique_ptr()
assert "StringList" in repr(ptr) assert "StringList" in repr(ptr)
assert print_opaque_list(ptr) == "Opaque list: [some value]" assert m.print_opaque_list(ptr) == "Opaque list: [some value]"
...@@ -16,22 +16,11 @@ public: ...@@ -16,22 +16,11 @@ public:
Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); } Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); }
Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); } Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); }
Vector2(Vector2 &&v) : x(v.x), y(v.y) { print_move_created(this); v.x = v.y = 0; } Vector2(Vector2 &&v) : x(v.x), y(v.y) { print_move_created(this); v.x = v.y = 0; }
Vector2 &operator=(const Vector2 &v) { x = v.x; y = v.y; print_copy_assigned(this); return *this; }
Vector2 &operator=(Vector2 &&v) { x = v.x; y = v.y; v.x = v.y = 0; print_move_assigned(this); return *this; }
~Vector2() { print_destroyed(this); } ~Vector2() { print_destroyed(this); }
std::string toString() const { std::string toString() const { return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; }
return "[" + std::to_string(x) + ", " + std::to_string(y) + "]";
}
void operator=(const Vector2 &v) {
print_copy_assigned(this);
x = v.x;
y = v.y;
}
void operator=(Vector2 &&v) {
print_move_assigned(this);
x = v.x; y = v.y; v.x = v.y = 0;
}
Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); } Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); }
Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); } Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); }
...@@ -64,30 +53,9 @@ int operator+(const C2 &, const C2 &) { return 22; } ...@@ -64,30 +53,9 @@ int operator+(const C2 &, const C2 &) { return 22; }
int operator+(const C2 &, const C1 &) { return 21; } int operator+(const C2 &, const C1 &) { return 21; }
int operator+(const C1 &, const C2 &) { return 12; } int operator+(const C1 &, const C2 &) { return 12; }
struct NestABase { TEST_SUBMODULE(operators, m) {
int value = -2;
};
struct NestA : NestABase {
int value = 3;
NestA& operator+=(int i) { value += i; return *this; }
};
struct NestB {
NestA a;
int value = 4;
NestB& operator-=(int i) { value -= i; return *this; }
};
struct NestC {
NestB b;
int value = 5;
NestC& operator*=(int i) { value *= i; return *this; }
};
test_initializer operator_overloading([](py::module &pm) {
auto m = pm.def_submodule("operators");
// test_operator_overloading
py::class_<Vector2>(m, "Vector2") py::class_<Vector2>(m, "Vector2")
.def(py::init<float, float>()) .def(py::init<float, float>())
.def(py::self + py::self) .def(py::self + py::self)
...@@ -113,6 +81,7 @@ test_initializer operator_overloading([](py::module &pm) { ...@@ -113,6 +81,7 @@ test_initializer operator_overloading([](py::module &pm) {
m.attr("Vector") = m.attr("Vector2"); m.attr("Vector") = m.attr("Vector2");
// test_operators_notimplemented
// #393: need to return NotSupported to ensure correct arithmetic operator behavior // #393: need to return NotSupported to ensure correct arithmetic operator behavior
py::class_<C1>(m, "C1") py::class_<C1>(m, "C1")
.def(py::init<>()) .def(py::init<>())
...@@ -124,29 +93,44 @@ test_initializer operator_overloading([](py::module &pm) { ...@@ -124,29 +93,44 @@ test_initializer operator_overloading([](py::module &pm) {
.def("__add__", [](const C2& c2, const C1& c1) { return c2 + c1; }) .def("__add__", [](const C2& c2, const C1& c1) { return c2 + c1; })
.def("__radd__", [](const C2& c2, const C1& c1) { return c1 + c2; }); .def("__radd__", [](const C2& c2, const C1& c1) { return c1 + c2; });
// test_nested
// #328: first member in a class can't be used in operators // #328: first member in a class can't be used in operators
struct NestABase { int value = -2; };
py::class_<NestABase>(m, "NestABase") py::class_<NestABase>(m, "NestABase")
.def(py::init<>()) .def(py::init<>())
.def_readwrite("value", &NestABase::value); .def_readwrite("value", &NestABase::value);
struct NestA : NestABase {
int value = 3;
NestA& operator+=(int i) { value += i; return *this; }
};
py::class_<NestA>(m, "NestA") py::class_<NestA>(m, "NestA")
.def(py::init<>()) .def(py::init<>())
.def(py::self += int()) .def(py::self += int())
.def("as_base", [](NestA &a) -> NestABase& { .def("as_base", [](NestA &a) -> NestABase& {
return (NestABase&) a; return (NestABase&) a;
}, py::return_value_policy::reference_internal); }, py::return_value_policy::reference_internal);
m.def("get_NestA", [](const NestA &a) { return a.value; });
struct NestB {
NestA a;
int value = 4;
NestB& operator-=(int i) { value -= i; return *this; }
};
py::class_<NestB>(m, "NestB") py::class_<NestB>(m, "NestB")
.def(py::init<>()) .def(py::init<>())
.def(py::self -= int()) .def(py::self -= int())
.def_readwrite("a", &NestB::a); .def_readwrite("a", &NestB::a);
m.def("get_NestB", [](const NestB &b) { return b.value; });
struct NestC {
NestB b;
int value = 5;
NestC& operator*=(int i) { value *= i; return *this; }
};
py::class_<NestC>(m, "NestC") py::class_<NestC>(m, "NestC")
.def(py::init<>()) .def(py::init<>())
.def(py::self *= int()) .def(py::self *= int())
.def_readwrite("b", &NestC::b); .def_readwrite("b", &NestC::b);
m.def("get_NestA", [](const NestA &a) { return a.value; });
m.def("get_NestB", [](const NestB &b) { return b.value; });
m.def("get_NestC", [](const NestC &c) { return c.value; }); m.def("get_NestC", [](const NestC &c) { return c.value; });
}); }
import pytest import pytest
from pybind11_tests import operators as m
from pybind11_tests import ConstructorStats from pybind11_tests import ConstructorStats
def test_operator_overloading(): def test_operator_overloading():
from pybind11_tests.operators import Vector2, Vector v1 = m.Vector2(1, 2)
v2 = m.Vector(3, -1)
v1 = Vector2(1, 2)
v2 = Vector(3, -1)
assert str(v1) == "[1.000000, 2.000000]" assert str(v1) == "[1.000000, 2.000000]"
assert str(v2) == "[3.000000, -1.000000]" assert str(v2) == "[3.000000, -1.000000]"
...@@ -36,7 +35,7 @@ def test_operator_overloading(): ...@@ -36,7 +35,7 @@ def test_operator_overloading():
v2 /= v1 v2 /= v1
assert str(v2) == "[2.000000, 8.000000]" assert str(v2) == "[2.000000, 8.000000]"
cstats = ConstructorStats.get(Vector2) cstats = ConstructorStats.get(m.Vector2)
assert cstats.alive() == 2 assert cstats.alive() == 2
del v1 del v1
assert cstats.alive() == 1 assert cstats.alive() == 1
...@@ -59,9 +58,8 @@ def test_operator_overloading(): ...@@ -59,9 +58,8 @@ def test_operator_overloading():
def test_operators_notimplemented(): def test_operators_notimplemented():
"""#393: need to return NotSupported to ensure correct arithmetic operator behavior""" """#393: need to return NotSupported to ensure correct arithmetic operator behavior"""
from pybind11_tests.operators import C1, C2
c1, c2 = C1(), C2() c1, c2 = m.C1(), m.C2()
assert c1 + c1 == 11 assert c1 + c1 == 11
assert c2 + c2 == 22 assert c2 + c2 == 22
assert c2 + c1 == 21 assert c2 + c1 == 21
...@@ -70,24 +68,23 @@ def test_operators_notimplemented(): ...@@ -70,24 +68,23 @@ def test_operators_notimplemented():
def test_nested(): def test_nested():
"""#328: first member in a class can't be used in operators""" """#328: first member in a class can't be used in operators"""
from pybind11_tests.operators import NestA, NestB, NestC, get_NestA, get_NestB, get_NestC
a = NestA() a = m.NestA()
b = NestB() b = m.NestB()
c = NestC() c = m.NestC()
a += 10 a += 10
assert get_NestA(a) == 13 assert m.get_NestA(a) == 13
b.a += 100 b.a += 100
assert get_NestA(b.a) == 103 assert m.get_NestA(b.a) == 103
c.b.a += 1000 c.b.a += 1000
assert get_NestA(c.b.a) == 1003 assert m.get_NestA(c.b.a) == 1003
b -= 1 b -= 1
assert get_NestB(b) == 3 assert m.get_NestB(b) == 3
c.b -= 3 c.b -= 3
assert get_NestB(c.b) == 1 assert m.get_NestB(c.b) == 1
c *= 7 c *= 7
assert get_NestC(c) == 35 assert m.get_NestC(c) == 35
abase = a.as_base() abase = a.as_base()
assert abase.value == -2 assert abase.value == -2
......
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