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 @@
#include "pybind11_tests.h"
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
TEST_SUBMODULE(enums, m) {
// test_unscoped_enum
enum UnscopedEnum {
EOne = 1,
ETwo
};
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())
.value("EOne", EOne)
.value("ETwo", ETwo)
.export_values();
// test_scoped_enum
enum class ScopedEnum {
Two = 2,
Three
};
py::enum_<ScopedEnum>(m, "ScopedEnum", py::arithmetic())
.value("Two", ScopedEnum::Two)
.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())
.value("Read", Flags::Read)
.value("Write", Flags::Write)
.value("Execute", Flags::Execute)
.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");
exenum_class.def_static("test_function", &ClassWithUnscopedEnum::test_function);
py::enum_<ClassWithUnscopedEnum::EMode>(exenum_class, "EMode")
......@@ -66,7 +64,8 @@ test_initializer enums([](py::module &m) {
.value("ESecondMode", ClassWithUnscopedEnum::ESecondMode)
.export_values();
// test_enum_to_int
m.def("test_enum_to_int", [](int) { });
m.def("test_enum_to_uint", [](uint32_t) { });
m.def("test_enum_to_long_long", [](long long) { });
});
}
import pytest
from pybind11_tests import enums as m
def test_unscoped_enum():
from pybind11_tests import UnscopedEnum, EOne
assert str(UnscopedEnum.EOne) == "UnscopedEnum.EOne"
assert str(UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"
assert str(EOne) == "UnscopedEnum.EOne"
assert str(m.UnscopedEnum.EOne) == "UnscopedEnum.EOne"
assert str(m.UnscopedEnum.ETwo) == "UnscopedEnum.ETwo"
assert str(m.EOne) == "UnscopedEnum.EOne"
# __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
with pytest.raises(AttributeError):
UnscopedEnum.__members__ = {}
m.UnscopedEnum.__members__ = {}
# __members__ returns a copy
foo = UnscopedEnum.__members__
foo = m.UnscopedEnum.__members__
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
y = UnscopedEnum.ETwo
y = m.UnscopedEnum.ETwo
assert y == 2
assert y != 3
assert int(UnscopedEnum.ETwo) == 2
assert str(UnscopedEnum(2)) == "UnscopedEnum.ETwo"
assert int(m.UnscopedEnum.ETwo) == 2
assert str(m.UnscopedEnum(2)) == "UnscopedEnum.ETwo"
# order
assert UnscopedEnum.EOne < UnscopedEnum.ETwo
assert UnscopedEnum.EOne < 2
assert UnscopedEnum.ETwo > UnscopedEnum.EOne
assert UnscopedEnum.ETwo > 1
assert UnscopedEnum.ETwo <= 2
assert UnscopedEnum.ETwo >= 2
assert UnscopedEnum.EOne <= UnscopedEnum.ETwo
assert UnscopedEnum.EOne <= 2
assert UnscopedEnum.ETwo >= UnscopedEnum.EOne
assert UnscopedEnum.ETwo >= 1
assert not (UnscopedEnum.ETwo < UnscopedEnum.EOne)
assert not (2 < UnscopedEnum.EOne)
assert m.UnscopedEnum.EOne < m.UnscopedEnum.ETwo
assert m.UnscopedEnum.EOne < 2
assert m.UnscopedEnum.ETwo > m.UnscopedEnum.EOne
assert m.UnscopedEnum.ETwo > 1
assert m.UnscopedEnum.ETwo <= 2
assert m.UnscopedEnum.ETwo >= 2
assert m.UnscopedEnum.EOne <= m.UnscopedEnum.ETwo
assert m.UnscopedEnum.EOne <= 2
assert m.UnscopedEnum.ETwo >= m.UnscopedEnum.EOne
assert m.UnscopedEnum.ETwo >= 1
assert not (m.UnscopedEnum.ETwo < m.UnscopedEnum.EOne)
assert not (2 < m.UnscopedEnum.EOne)
def test_scoped_enum():
from pybind11_tests import ScopedEnum, test_scoped_enum
assert test_scoped_enum(ScopedEnum.Three) == "ScopedEnum::Three"
z = ScopedEnum.Two
assert test_scoped_enum(z) == "ScopedEnum::Two"
assert m.test_scoped_enum(m.ScopedEnum.Three) == "ScopedEnum::Three"
z = m.ScopedEnum.Two
assert m.test_scoped_enum(z) == "ScopedEnum::Two"
# expected TypeError exceptions for scoped enum ==/!= int comparisons
with pytest.raises(TypeError):
......@@ -54,23 +53,21 @@ def test_scoped_enum():
assert z != 3
# order
assert ScopedEnum.Two < ScopedEnum.Three
assert ScopedEnum.Three > ScopedEnum.Two
assert ScopedEnum.Two <= ScopedEnum.Three
assert ScopedEnum.Two <= ScopedEnum.Two
assert ScopedEnum.Two >= ScopedEnum.Two
assert ScopedEnum.Three >= ScopedEnum.Two
assert m.ScopedEnum.Two < m.ScopedEnum.Three
assert m.ScopedEnum.Three > m.ScopedEnum.Two
assert m.ScopedEnum.Two <= m.ScopedEnum.Three
assert m.ScopedEnum.Two <= m.ScopedEnum.Two
assert m.ScopedEnum.Two >= m.ScopedEnum.Two
assert m.ScopedEnum.Three >= m.ScopedEnum.Two
def test_implicit_conversion():
from pybind11_tests import ClassWithUnscopedEnum
assert str(ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode"
assert str(ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode"
assert str(m.ClassWithUnscopedEnum.EMode.EFirstMode) == "EMode.EFirstMode"
assert str(m.ClassWithUnscopedEnum.EFirstMode) == "EMode.EFirstMode"
f = ClassWithUnscopedEnum.test_function
first = ClassWithUnscopedEnum.EFirstMode
second = ClassWithUnscopedEnum.ESecondMode
f = m.ClassWithUnscopedEnum.test_function
first = m.ClassWithUnscopedEnum.EFirstMode
second = m.ClassWithUnscopedEnum.ESecondMode
assert f(first) == 1
......@@ -95,21 +92,19 @@ def test_implicit_conversion():
def test_binary_operators():
from pybind11_tests import Flags
assert int(Flags.Read) == 4
assert int(Flags.Write) == 2
assert int(Flags.Execute) == 1
assert int(Flags.Read | Flags.Write | Flags.Execute) == 7
assert int(Flags.Read | Flags.Write) == 6
assert int(Flags.Read | Flags.Execute) == 5
assert int(Flags.Write | Flags.Execute) == 3
assert int(Flags.Write | 1) == 3
state = Flags.Read | Flags.Write
assert (state & Flags.Read) != 0
assert (state & Flags.Write) != 0
assert (state & Flags.Execute) == 0
assert int(m.Flags.Read) == 4
assert int(m.Flags.Write) == 2
assert int(m.Flags.Execute) == 1
assert int(m.Flags.Read | m.Flags.Write | m.Flags.Execute) == 7
assert int(m.Flags.Read | m.Flags.Write) == 6
assert int(m.Flags.Read | m.Flags.Execute) == 5
assert int(m.Flags.Write | m.Flags.Execute) == 3
assert int(m.Flags.Write | 1) == 3
state = m.Flags.Read | m.Flags.Write
assert (state & m.Flags.Read) != 0
assert (state & m.Flags.Write) != 0
assert (state & m.Flags.Execute) == 0
assert (state & 1) == 0
state2 = ~state
......@@ -118,12 +113,9 @@ def test_binary_operators():
def test_enum_to_int():
from pybind11_tests import Flags, ClassWithUnscopedEnum
from pybind11_tests import test_enum_to_int, test_enum_to_uint, test_enum_to_long_long
test_enum_to_int(Flags.Read)
test_enum_to_int(ClassWithUnscopedEnum.EMode.EFirstMode)
test_enum_to_uint(Flags.Read)
test_enum_to_uint(ClassWithUnscopedEnum.EMode.EFirstMode)
test_enum_to_long_long(Flags.Read)
test_enum_to_long_long(ClassWithUnscopedEnum.EMode.EFirstMode)
m.test_enum_to_int(m.Flags.Read)
m.test_enum_to_int(m.ClassWithUnscopedEnum.EMode.EFirstMode)
m.test_enum_to_uint(m.Flags.Read)
m.test_enum_to_uint(m.ClassWithUnscopedEnum.EMode.EFirstMode)
m.test_enum_to_long_long(m.Flags.Read)
m.test_enum_to_long_long(m.ClassWithUnscopedEnum.EMode.EFirstMode)
......@@ -11,7 +11,9 @@
#include <pybind11/eval.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__"));
m.def("test_eval_statements", [global]() {
......@@ -86,4 +88,4 @@ test_initializer eval([](py::module &m) {
}
return false;
});
});
}
import os
from pybind11_tests import eval_ as m
def test_evals(capture):
from pybind11_tests import (test_eval_statements, test_eval, test_eval_single_statement,
test_eval_file, test_eval_failure, test_eval_file_failure)
with capture:
assert test_eval_statements()
assert m.test_eval_statements()
assert capture == "Hello World!"
assert test_eval()
assert test_eval_single_statement()
assert m.test_eval()
assert m.test_eval_single_statement()
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 test_eval_file_failure()
assert m.test_eval_failure()
assert m.test_eval_file_failure()
......@@ -10,84 +10,62 @@
#include "pybind11_tests.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) {
std::string ret = "{";
for (int i : entries)
ret += std::to_string(i) + " ";
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);
// test_named_arguments
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!"));
/* A fancier default argument */
std::vector<int> list;
list.push_back(13);
list.push_back(17);
m.def("kw_func4", &kw_func4, py::arg("myList") = list);
m.def("args_function", &args_function);
m.def("args_kwargs_function", &args_kwargs_function);
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);
std::vector<int> list{{13, 17}};
m.def("kw_func4", [](const std::vector<int> &entries) {
std::string ret = "{";
for (int i : entries)
ret += std::to_string(i) + " ";
ret.back() = '}';
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);
// 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")
.def("foo0", &KWClass::foo)
.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
from pybind11_tests import (kw_func0, kw_func1, kw_func2, kw_func3, kw_func4, args_function,
args_kwargs_function, kw_func_udl, kw_func_udl_z, KWClass)
from pybind11_tests import kwargs_and_defaults as m
def test_function_signatures(doc):
assert doc(kw_func0) == "kw_func0(arg0: int, arg1: int) -> str"
assert doc(kw_func1) == "kw_func1(x: int, y: int) -> str"
assert doc(kw_func2) == "kw_func2(x: int=100, y: int=200) -> str"
assert doc(kw_func3) == "kw_func3(data: str='Hello world!') -> None"
assert doc(kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> str"
assert doc(kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> str"
assert doc(kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> str"
assert doc(args_function) == "args_function(*args) -> tuple"
assert doc(args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple"
assert doc(KWClass.foo0) == "foo0(self: m.KWClass, arg0: int, arg1: float) -> None"
assert doc(KWClass.foo1) == "foo1(self: m.KWClass, x: int, y: float) -> None"
assert doc(m.kw_func0) == "kw_func0(arg0: int, arg1: int) -> str"
assert doc(m.kw_func1) == "kw_func1(x: int, y: int) -> str"
assert doc(m.kw_func2) == "kw_func2(x: int=100, y: int=200) -> str"
assert doc(m.kw_func3) == "kw_func3(data: str='Hello world!') -> None"
assert doc(m.kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> str"
assert doc(m.kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> str"
assert doc(m.kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> str"
assert doc(m.args_function) == "args_function(*args) -> tuple"
assert doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple"
assert doc(m.KWClass.foo0) == \
"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):
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 kw_func1(5, y=10) == "x=5, y=10"
assert kw_func1(y=10, x=5) == "x=5, y=10"
assert m.kw_func1(5, 10) == "x=5, y=10"
assert m.kw_func1(5, y=10) == "x=5, y=10"
assert m.kw_func1(y=10, x=5) == "x=5, y=10"
assert kw_func2() == "x=100, y=200"
assert kw_func2(5) == "x=5, y=200"
assert kw_func2(x=5) == "x=5, y=200"
assert kw_func2(y=10) == "x=100, y=10"
assert kw_func2(5, 10) == "x=5, y=10"
assert kw_func2(x=5, y=10) == "x=5, y=10"
assert m.kw_func2() == "x=100, y=200"
assert m.kw_func2(5) == "x=5, y=200"
assert m.kw_func2(x=5) == "x=5, y=200"
assert m.kw_func2(y=10) == "x=100, y=10"
assert m.kw_func2(5, 10) == "x=5, y=10"
assert m.kw_func2(x=5, y=10) == "x=5, y=10"
with pytest.raises(TypeError) as excinfo:
# noinspection PyArgumentList
kw_func2(x=5, y=10, z=12)
m.kw_func2(x=5, y=10, z=12)
assert excinfo.match(
r'(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$))' + '{3}$')
assert kw_func4() == "{13 17}"
assert kw_func4(myList=[1, 2, 3]) == "{1 2 3}"
assert m.kw_func4() == "{13 17}"
assert m.kw_func4(myList=[1, 2, 3]) == "{1 2 3}"
assert 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(x=5, y=10) == "x=5, y=10"
assert m.kw_func_udl_z(x=5) == "x=5, y=0"
def test_arg_and_kwargs():
args = 'arg1_value', 'arg2_value', 3
assert args_function(*args) == args
assert m.args_function(*args) == args
args = 'a1', 'a2'
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):
from pybind11_tests import (mixed_plus_args, mixed_plus_kwargs, mixed_plus_args_kwargs,
mixed_plus_args_kwargs_defaults)
mpa = mixed_plus_args
mpk = mixed_plus_kwargs
mpak = mixed_plus_args_kwargs
mpakd = mixed_plus_args_kwargs_defaults
mpa = m.mixed_plus_args
mpk = m.mixed_plus_kwargs
mpak = m.mixed_plus_args_kwargs
mpakd = m.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) == (1, 2.5, ())
......
......@@ -26,40 +26,43 @@ public:
void operator=(const ExampleMandA &e) { print_copy_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 add2(ExampleMandA &other) { value += other.value; } // passing by reference
void add3(const ExampleMandA &other) { value += other.value; } // passing by const reference
void add4(ExampleMandA *other) { value += other->value; } // passing by pointer
void add5(const ExampleMandA *other) { value += other->value; } // passing by const pointer
void add6(int other) { value += other; } // passing by value
void add7(int &other) { value += other; } // passing by reference
void add8(const int &other) { value += other; } // passing by const reference
void add9(int *other) { value += *other; } // passing by pointer
void add10(const int *other) { value += *other; } // passing by const pointer
ExampleMandA self1() { return *this; } // return by value
ExampleMandA &self2() { return *this; } // return by reference
const ExampleMandA &self3() { return *this; } // return by const reference
ExampleMandA *self4() { return this; } // return by pointer
const ExampleMandA *self5() { return this; } // return by const pointer
int internal1() { return value; } // return by value
int &internal2() { return value; } // return by reference
const int &internal3() { return value; } // return by const reference
int *internal4() { return &value; } // return by pointer
const int *internal5() { return &value; } // return by const pointer
void add1(ExampleMandA other) { value += other.value; } // passing by value
void add2(ExampleMandA &other) { value += other.value; } // passing by reference
void add3(const ExampleMandA &other) { value += other.value; } // passing by const reference
void add4(ExampleMandA *other) { value += other->value; } // passing by pointer
void add5(const ExampleMandA *other) { value += other->value; } // passing by const pointer
void add6(int other) { value += other; } // passing by value
void add7(int &other) { value += other; } // passing by reference
void add8(const int &other) { value += other; } // passing by const reference
void add9(int *other) { value += *other; } // passing by pointer
void add10(const int *other) { value += *other; } // passing by const pointer
ExampleMandA self1() { return *this; } // return by value
ExampleMandA &self2() { return *this; } // return by reference
const ExampleMandA &self3() { return *this; } // return by const reference
ExampleMandA *self4() { return this; } // return by pointer
const ExampleMandA *self5() { return this; } // return by const pointer
int internal1() { return value; } // return by value
int &internal2() { return value; } // return by reference
const int &internal3() { return value; } // return by const reference
int *internal4() { return &value; } // return by 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(float, int) { return "(float, int)"; }
py::str overloaded(int, int) { return "(int, int)"; }
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(float, int) const { return "(float, int) const"; }
py::str overloaded(int, int) const { return "(int, int) 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;
};
......@@ -74,41 +77,28 @@ struct TestProperties {
static int static_get() { return static_value; }
static void static_set(int v) { static_value = v; }
};
int TestProperties::static_value = 1;
struct TestPropertiesOverride : TestProperties {
int value = 99;
static int static_value;
};
int TestPropertiesOverride::static_value = 99;
struct SimpleValue { int value = 1; };
struct TestPropRVP {
SimpleValue v1;
SimpleValue v2;
static SimpleValue sv1;
static SimpleValue sv2;
const SimpleValue &get1() const { return v1; }
const SimpleValue &get2() const { return v2; }
SimpleValue get_rvalue() const { return v2; }
void set1(int v) { v1.value = v; }
void set2(int v) { v2.value = v; }
UserType v1{1};
UserType v2{1};
static UserType sv1;
static UserType sv2;
const UserType &get1() const { return v1; }
const UserType &get2() const { return v2; }
UserType get_rvalue() const { return v2; }
void set1(int v) { v1.set(v); }
void set2(int v) { v2.set(v); }
};
SimpleValue TestPropRVP::sv1{};
SimpleValue TestPropRVP::sv2{};
class DynamicClass {
public:
DynamicClass() { print_default_created(this); }
~DynamicClass() { print_destroyed(this); }
};
class CppDerivedDynamicClass : public DynamicClass { };
UserType TestPropRVP::sv1(1);
UserType TestPropRVP::sv2(1);
// py::arg/py::arg_v testing: these arguments just record their argument when invoked
class ArgInspector1 { public: std::string arg = "(default arg inspector 1)"; };
......@@ -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
class NoneTester { public: int answer = 42; };
int none1(const NoneTester &obj) { return obj.answer; }
......@@ -215,7 +202,8 @@ public:
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");
emna.def(py::init<>())
.def(py::init<int>())
......@@ -241,43 +229,52 @@ test_initializer methods_and_attributes([](py::module &m) {
.def("internal4", &ExampleMandA::internal4)
.def("internal5", &ExampleMandA::internal5)
#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<float, int>(&ExampleMandA::overloaded))
.def("overloaded", py::overload_cast<int, int>(&ExampleMandA::overloaded))
.def("overloaded", 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<float, 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_))
#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::*)(float, 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_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::*)(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::*)(float, float) const>(&ExampleMandA::overloaded))
#endif
// test_no_mixed_overloads
// Raise error if trying to mix static/non-static overloads on the same name:
.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))
.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", []() {
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests").attr("ExampleMandA"));
emna.def_static("overload_mixed2", static_cast<py::str ( *)( )>(&ExampleMandA::overloaded))
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 ( *)(float )>(&ExampleMandA::overloaded))
.def ("overload_mixed2", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded));
})
.def("__str__", &ExampleMandA::toString)
.def_readwrite("value", &ExampleMandA::value);
// test_copy_method
// Issue #443: can't call copied methods in Python 3
emna.attr("add2b") = emna.attr("add2");
// test_properties, test_static_properties, test_static_cls
py::class_<TestProperties>(m, "TestProperties")
.def(py::init<>())
.def_readonly("def_readonly", &TestProperties::value)
......@@ -300,15 +297,13 @@ test_initializer methods_and_attributes([](py::module &m) {
.def_readonly("def_readonly", &TestPropertiesOverride::value)
.def_readonly_static("def_readonly_static", &TestPropertiesOverride::static_value);
py::class_<SimpleValue>(m, "SimpleValue")
.def_readwrite("value", &SimpleValue::value);
auto static_get1 = [](py::object) -> const SimpleValue & { return TestPropRVP::sv1; };
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 static_get1 = [](py::object) -> const UserType & { return TestPropRVP::sv1; };
auto static_get2 = [](py::object) -> const UserType & { return TestPropRVP::sv2; };
auto static_set1 = [](py::object, int v) { TestPropRVP::sv1.set(v); };
auto static_set2 = [](py::object, int v) { TestPropRVP::sv2.set(v); };
auto rvp_copy = py::return_value_policy::copy;
// test_property_return_value_policies
py::class_<TestPropRVP>(m, "TestPropRVP")
.def(py::init<>())
.def_property_readonly("ro_ref", &TestPropRVP::get1)
......@@ -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_copy", static_get2, static_set2, rvp_copy)
.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_static("static_rvalue", [](py::object) { return SimpleValue(); });
.def_property_readonly_static("static_rvalue", [](py::object) { return UserType(1); });
// test_metaclass_override
struct MetaclassOverride { };
py::class_<MetaclassOverride>(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type))
.def_property_readonly_static("readonly", [](py::object) { return 1; });
#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())
.def(py::init());
class CppDerivedDynamicClass : public DynamicClass { };
py::class_<CppDerivedDynamicClass, DynamicClass>(m, "CppDerivedDynamicClass")
.def(py::init());
#endif
// test_noconvert_args
//
// 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
// some conversion).
......@@ -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_only", [](int i) { return i / 2; }, py::arg("i").noconvert());
// test_bad_arg_default
// Issue/PR #648: bad arg default debugging output
#if !defined(NDEBUG)
m.attr("debug_enabled") = true;
......@@ -371,13 +378,14 @@ test_initializer methods_and_attributes([](py::module &m) {
#endif
m.def("bad_arg_def_named", []{
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", []{
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")
.def(py::init<>());
m.def("no_none1", &none1, py::arg().none(false));
......@@ -391,6 +399,7 @@ test_initializer methods_and_attributes([](py::module &m) {
m.def("ok_none4", &none4, py::arg().none(true));
m.def("ok_none5", &none5);
// test_str_issue
// Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
py::class_<StrIssue>(m, "StrIssue")
.def(py::init<int>())
......@@ -399,6 +408,8 @@ test_initializer methods_and_attributes([](py::module &m) {
return "StrIssue[" + std::to_string(si.val) + "]"; }
);
// test_unregistered_base_implementations
//
// 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
// 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) {
.def_readwrite("rw_value", &RegisteredDerived::rw_value)
.def_readonly("ro_value", &RegisteredDerived::ro_value)
// These should trigger a static_assert if uncommented
//.def_readwrite("fails", &SimpleValue::value) // should trigger a static_assert if uncommented
//.def_readonly("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", &UserType::value) // should trigger a static_assert if uncommented
.def_property("rw_value_prop", &RegisteredDerived::get_int, &RegisteredDerived::set_int)
.def_property_readonly("ro_value_prop", &RegisteredDerived::get_double)
// This one is in the registered class:
......@@ -432,4 +443,4 @@ test_initializer methods_and_attributes([](py::module &m) {
m.def("custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); },
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);
});
}
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():
instance1 = ExampleMandA()
instance2 = ExampleMandA(32)
instance1 = m.ExampleMandA()
instance2 = m.ExampleMandA(32)
instance1.add1(instance2)
instance1.add2(instance2)
......@@ -31,10 +32,13 @@ def test_methods_and_attributes():
assert instance1.internal4() == 320
assert instance1.internal5() == 320
assert instance1.overloaded() == "()"
assert instance1.overloaded(0) == "(int)"
assert instance1.overloaded(1, 1.0) == "(int, float)"
assert instance1.overloaded(2.0, 2) == "(float, int)"
assert instance1.overloaded(3, 3) == "(int, int)"
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(6.0, 6) == "(float, int) const"
assert instance1.overloaded_const(7, 7) == "(int, int) const"
......@@ -48,7 +52,7 @@ def test_methods_and_attributes():
instance1.value = 100
assert str(instance1) == "ExampleMandA[value=100]"
cstats = ConstructorStats.get(ExampleMandA)
cstats = ConstructorStats.get(m.ExampleMandA)
assert cstats.alive() == 2
del instance1, instance2
assert cstats.alive() == 0
......@@ -60,10 +64,25 @@ def test_methods_and_attributes():
assert cstats.move_assignments == 0
def test_properties():
from pybind11_tests import TestProperties
def test_copy_method():
"""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
with pytest.raises(AttributeError):
......@@ -80,122 +99,97 @@ def test_properties():
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():
from pybind11_tests import TestProperties as Type
assert Type.def_readonly_static == 1
assert m.TestProperties.def_readonly_static == 1
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)
Type.def_readwrite_static = 2
assert Type.def_readwrite_static == 2
m.TestProperties.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:
Type.def_property_readonly_static = 3
m.TestProperties.def_property_readonly_static = 3
assert "can't set attribute" in str(excinfo)
Type.def_property_static = 3
assert Type.def_property_static == 3
m.TestProperties.def_property_static = 3
assert m.TestProperties.def_property_static == 3
# Static property read and write via instance
instance = Type()
instance = m.TestProperties()
Type.def_readwrite_static = 0
assert Type.def_readwrite_static == 0
m.TestProperties.def_readwrite_static = 0
assert m.TestProperties.def_readwrite_static == 0
assert instance.def_readwrite_static == 0
instance.def_readwrite_static = 2
assert Type.def_readwrite_static == 2
assert m.TestProperties.def_readwrite_static == 2
assert instance.def_readwrite_static == 2
# It should be possible to override properties in derived classes
from pybind11_tests import TestPropertiesOverride as TypeOverride
assert TypeOverride().def_readonly == 99
assert TypeOverride.def_readonly_static == 99
assert m.TestPropertiesOverride().def_readonly == 99
assert m.TestPropertiesOverride.def_readonly_static == 99
def test_static_cls():
"""Static property getter and setters expect the type object as the their only argument"""
from pybind11_tests import TestProperties as Type
instance = Type()
assert Type.static_cls is Type
assert instance.static_cls is Type
instance = m.TestProperties()
assert m.TestProperties.static_cls is m.TestProperties
assert instance.static_cls is m.TestProperties
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
def test_metaclass_override():
"""Overriding pybind11's default metaclass changes the behavior of `static_property`"""
from pybind11_tests import MetaclassOverride
assert type(ExampleMandA).__name__ == "pybind11_type"
assert type(MetaclassOverride).__name__ == "type"
assert type(m.ExampleMandA).__name__ == "pybind11_type"
assert type(m.MetaclassOverride).__name__ == "type"
assert MetaclassOverride.readonly == 1
assert type(MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property"
assert m.MetaclassOverride.readonly == 1
assert type(m.MetaclassOverride.__dict__["readonly"]).__name__ == "pybind11_static_property"
# Regular `type` replaces the property instead of calling `__set__()`
MetaclassOverride.readonly = 2
assert MetaclassOverride.readonly == 2
assert isinstance(MetaclassOverride.__dict__["readonly"], int)
m.MetaclassOverride.readonly = 2
assert m.MetaclassOverride.readonly == 2
assert isinstance(m.MetaclassOverride.__dict__["readonly"], int)
def test_no_mixed_overloads():
from pybind11_tests import debug_enabled
with pytest.raises(RuntimeError) as excinfo:
ExampleMandA.add_mixed_overloads1()
m.ExampleMandA.add_mixed_overloads1()
assert (str(excinfo.value) ==
"overloading a method with both static and instance methods is not supported; " +
("compile in debug mode for more details" if not debug_enabled else
"error while attempting to bind static method ExampleMandA.overload_mixed1"
"() -> str")
"(arg0: float) -> str")
)
with pytest.raises(RuntimeError) as excinfo:
ExampleMandA.add_mixed_overloads2()
m.ExampleMandA.add_mixed_overloads2()
assert (str(excinfo.value) ==
"overloading a method with both static and instance methods is not supported; " +
("compile in debug mode for more details" if not debug_enabled else
"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"])
def test_property_return_value_policies(access):
from pybind11_tests import TestPropRVP
if not access.startswith("static"):
obj = TestPropRVP()
obj = m.TestPropRVP()
else:
obj = TestPropRVP
obj = m.TestPropRVP
ref = getattr(obj, access + "_ref")
assert ref.value == 1
......@@ -216,30 +210,20 @@ def test_property_return_value_policies(access):
def test_property_rvalue_policy():
"""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
`reference(_internal)` to `move`. The following would not work otherwise."""
instance = TestPropRVP()
instance = m.TestPropRVP()
o = instance.rvalue
assert o.value == 1
def test_property_rvalue_policy_static():
"""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
os = m.TestPropRVP.static_rvalue
assert os.value == 1
# https://bitbucket.org/pypy/pypy/issues/2447
@pytest.unsupported_on_pypy
def test_dynamic_attributes():
from pybind11_tests import DynamicClass, CppDerivedDynamicClass
instance = DynamicClass()
instance = m.DynamicClass()
assert not hasattr(instance, "foo")
assert "foo" not in dir(instance)
......@@ -259,16 +243,16 @@ def test_dynamic_attributes():
instance.__dict__ = []
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
del instance
assert cstats.alive() == 0
# Derived classes should work as well
class PythonDerivedDynamicClass(DynamicClass):
class PythonDerivedDynamicClass(m.DynamicClass):
pass
for cls in CppDerivedDynamicClass, PythonDerivedDynamicClass:
for cls in m.CppDerivedDynamicClass, PythonDerivedDynamicClass:
derived = cls()
derived.foobar = 100
assert derived.foobar == 100
......@@ -281,20 +265,18 @@ def test_dynamic_attributes():
# https://bitbucket.org/pypy/pypy/issues/2447
@pytest.unsupported_on_pypy
def test_cyclic_gc():
from pybind11_tests import DynamicClass
# One object references itself
instance = DynamicClass()
instance = m.DynamicClass()
instance.circular_reference = instance
cstats = ConstructorStats.get(DynamicClass)
cstats = ConstructorStats.get(m.DynamicClass)
assert cstats.alive() == 1
del instance
assert cstats.alive() == 0
# Two object reference each other
i1 = DynamicClass()
i2 = DynamicClass()
i1 = m.DynamicClass()
i2 = m.DynamicClass()
i1.cycle = i2
i2.cycle = i1
......@@ -304,8 +286,6 @@ def test_cyclic_gc():
def test_noconvert_args(msg):
import pybind11_tests as m
a = m.ArgInspector()
assert msg(a.f("hi")) == """
loading ArgInspector1 argument WITH conversion allowed. Argument value = hi
......@@ -369,23 +349,23 @@ def test_noconvert_args(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:
bad_arg_def_named()
m.bad_arg_def_named()
assert msg(excinfo.value) == (
"arg(): could not convert default argument 'a: NotRegistered' in function 'should_fail' "
"into a Python object (type not registered yet?)"
"arg(): could not convert default argument 'a: UnregisteredType' in function "
"'should_fail' into a Python object (type not registered yet?)"
if debug_enabled else
"arg(): could not convert default argument into a Python object (type not registered "
"yet?). Compile in debug mode for more information."
)
with pytest.raises(RuntimeError) as excinfo:
bad_arg_def_unnamed()
m.bad_arg_def_unnamed()
assert msg(excinfo.value) == (
"arg(): could not convert default argument 'NotRegistered' in function 'should_fail' "
"into a Python object (type not registered yet?)"
"arg(): could not convert default argument 'UnregisteredType' in function "
"'should_fail' into a Python object (type not registered yet?)"
if debug_enabled else
"arg(): could not convert default argument into a Python object (type not registered "
"yet?). Compile in debug mode for more information."
......@@ -393,76 +373,69 @@ def test_bad_arg_default(msg):
def test_accepts_none(msg):
from pybind11_tests import (NoneTester,
no_none1, no_none2, no_none3, no_none4, no_none5,
ok_none1, ok_none2, ok_none3, ok_none4, ok_none5)
a = NoneTester()
assert no_none1(a) == 42
assert no_none2(a) == 42
assert no_none3(a) == 42
assert no_none4(a) == 42
assert no_none5(a) == 42
assert ok_none1(a) == 42
assert ok_none2(a) == 42
assert ok_none3(a) == 42
assert ok_none4(a) == 42
assert ok_none5(a) == 42
a = m.NoneTester()
assert m.no_none1(a) == 42
assert m.no_none2(a) == 42
assert m.no_none3(a) == 42
assert m.no_none4(a) == 42
assert m.no_none5(a) == 42
assert m.ok_none1(a) == 42
assert m.ok_none2(a) == 42
assert m.ok_none3(a) == 42
assert m.ok_none4(a) == 42
assert m.ok_none5(a) == 42
with pytest.raises(TypeError) as excinfo:
no_none1(None)
m.no_none1(None)
assert "incompatible function arguments" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo:
no_none2(None)
m.no_none2(None)
assert "incompatible function arguments" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo:
no_none3(None)
m.no_none3(None)
assert "incompatible function arguments" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo:
no_none4(None)
m.no_none4(None)
assert "incompatible function arguments" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo:
no_none5(None)
m.no_none5(None)
assert "incompatible function arguments" in str(excinfo.value)
# The first one still raises because you can't pass None as a lvalue reference arg:
with pytest.raises(TypeError) as excinfo:
assert ok_none1(None) == -1
assert m.ok_none1(None) == -1
assert msg(excinfo.value) == """
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
"""
# The rest take the argument as pointer or holder, and accept None:
assert ok_none2(None) == -1
assert ok_none3(None) == -1
assert ok_none4(None) == -1
assert ok_none5(None) == -1
assert m.ok_none2(None) == -1
assert m.ok_none3(None) == -1
assert m.ok_none4(None) == -1
assert m.ok_none5(None) == -1
def test_str_issue(msg):
"""#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:
str(StrIssue("no", "such", "constructor"))
str(m.StrIssue("no", "such", "constructor"))
assert msg(excinfo.value) == """
__init__(): incompatible constructor arguments. The following argument types are supported:
1. m.StrIssue(arg0: int)
2. m.StrIssue()
1. m.methods_and_attributes.StrIssue(arg0: int)
2. m.methods_and_attributes.StrIssue()
Invoked with: 'no', 'such', 'constructor'
"""
def test_unregistered_base_implementations():
from pybind11_tests import RegisteredDerived
a = RegisteredDerived()
a = m.RegisteredDerived()
a.do_nothing()
assert a.rw_value == 42
assert a.ro_value == 1.25
......@@ -480,11 +453,8 @@ def test_unregistered_base_implementations():
def test_custom_caster_destruction():
"""
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.
"""
import pybind11_tests as m
"""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."""
cstats = m.destruction_tester_cstats()
# This one *doesn't* have take_ownership: the pointer should be used but not destroyed:
......
......@@ -11,42 +11,38 @@
#include "pybind11_tests.h"
#include "constructor_stats.h"
std::string submodule_func() {
return "submodule_func()";
}
class A {
public:
A(int v) : v(v) { print_created(this, v); }
~A() { print_destroyed(this); }
A(const A&) { print_copy_created(this); }
A& operator=(const A &copy) { print_copy_assigned(this); v = copy.v; return *this; }
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);
TEST_SUBMODULE(modules, m) {
// test_nested_modules
py::module m_sub = m.def_submodule("subsubmodule");
m_sub.def("submodule_func", []() { return "submodule_func()"; });
// test_reference_internal
class A {
public:
A(int v) : v(v) { print_created(this, v); }
~A() { print_destroyed(this); }
A(const A&) { print_copy_created(this); }
A& operator=(const A &copy) { print_copy_assigned(this); v = copy.v; return *this; }
std::string toString() { return "A[" + std::to_string(v) + "]"; }
private:
int v;
};
py::class_<A>(m_sub, "A")
.def(py::init<int>())
.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")
.def(py::init<>())
.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) {
m.attr("OD") = py::module::import("collections").attr("OrderedDict");
// test_duplicate_registration
// Registering two things with the same name
m.def("duplicate_registration", []() {
class Dupe1 { };
......@@ -98,4 +95,4 @@ test_initializer modules([](py::module &m) {
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():
import pybind11_tests
from pybind11_tests.submodule import submodule_func
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():
from pybind11_tests import ConstructorStats
from pybind11_tests.submodule import A, B
b = B()
b = ms.B()
assert str(b.get_a1()) == "A[1]"
assert str(b.a1) == "A[1]"
assert str(b.get_a2()) == "A[2]"
assert str(b.a2) == "A[2]"
b.a1 = A(42)
b.a2 = A(43)
b.a1 = ms.A(42)
b.a2 = ms.A(43)
assert str(b.get_a1()) == "A[42]"
assert str(b.a1) == "A[42]"
assert str(b.get_a2()) == "A[43]"
assert str(b.a2) == "A[43]"
astats, bstats = ConstructorStats.get(A), ConstructorStats.get(B)
astats, bstats = ConstructorStats.get(ms.A), ConstructorStats.get(ms.B)
assert astats.alive() == 2
assert bstats.alive() == 1
del b
......@@ -47,7 +49,7 @@ def test_reference_internal():
def test_importing():
from pybind11_tests import OD
from pybind11_tests.modules import OD
from collections import OrderedDict
assert OD is OrderedDict
......@@ -66,6 +68,5 @@ def test_pydoc():
def test_duplicate_registration():
"""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) {
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) {
auto ptr = (uint8_t *) a.mutable_data(index...);
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) {
return l.release();
}
test_initializer numpy_array([](py::module &m) {
auto sm = m.def_submodule("array");
TEST_SUBMODULE(numpy_array, sm) {
try { py::module::import("numpy"); }
catch (...) { return; }
// test_array_attributes
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, ssize_t dim) { return a.shape(dim); });
......@@ -96,25 +84,25 @@ test_initializer numpy_array([](py::module &m) {
sm.def("nbytes", [](const arr& a) { return a.nbytes(); });
sm.def("owndata", [](const arr& a) { return a.owndata(); });
def_index_fn(data, const arr&);
def_index_fn(data_t, const arr_t&);
// test_index_offset
def_index_fn(index_at, const arr&);
def_index_fn(index_at_t, const arr_t&);
def_index_fn(offset_at, const arr&);
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_t, arr_t&);
def_index_fn(at_t, const arr_t&);
def_index_fn(mutate_at_t, arr_t&);
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 });
});
// test_make_c_f_array
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 }); });
// test_wrap
sm.def("wrap", [](py::array a) {
return py::array(
a.dtype(),
......@@ -125,12 +113,12 @@ test_initializer numpy_array([](py::module &m) {
);
});
// test_numpy_view
struct ArrayClass {
int data[2] = { 1, 2 };
ArrayClass() { py::print("ArrayClass()"); }
~ArrayClass() { py::print("~ArrayClass()"); }
};
py::class_<ArrayClass>(sm, "ArrayClass")
.def(py::init<>())
.def("numpy_view", [](py::object &obj) {
......@@ -140,16 +128,18 @@ test_initializer numpy_array([](py::module &m) {
}
);
// test_cast_numpy_int64_to_uint64
sm.def("function_taking_uint64", [](uint64_t) { });
// test_isinstance
sm.def("isinstance_untyped", [](py::object yes, py::object no) {
return py::isinstance<py::array>(yes) && !py::isinstance<py::array>(no);
});
sm.def("isinstance_typed", [](py::object o) {
return py::isinstance<py::array_t<double>>(o) && !py::isinstance<py::array_t<int>>(o);
});
// test_constructors
sm.def("default_constructors", []() {
return py::dict(
"array"_a=py::array(),
......@@ -157,7 +147,6 @@ test_initializer numpy_array([](py::module &m) {
"array_t<double>"_a=py::array_t<double>()
);
});
sm.def("converting_constructors", [](py::object o) {
return py::dict(
"array"_a=py::array(o),
......@@ -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<float>) { return "float"; });
sm.def("overloaded", [](py::array_t<int>) { return "int"; });
......@@ -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<double>) { return "double"; });
// test_greedy_string_overload
// Issue 685: ndarray shouldn't go to std::string overload
sm.def("issue685", [](std::string) { return "string"; });
sm.def("issue685", [](py::array) { return "array"; });
sm.def("issue685", [](py::object) { return "other"; });
// test_array_unchecked_fixed_dims
sm.def("proxy_add2", [](py::array_t<double> a, double v) {
auto r = a.mutable_unchecked<2>();
for (ssize_t i = 0; i < r.shape(0); i++)
......@@ -238,6 +229,7 @@ test_initializer numpy_array([](py::module &m) {
return auxiliaries(r, r2);
});
// test_array_unchecked_dyn_dims
// Same as the above, but without a compile-time dimensions specification:
sm.def("proxy_add2_dyn", [](py::array_t<double> a, double v) {
auto r = a.mutable_unchecked();
......@@ -264,19 +256,21 @@ test_initializer numpy_array([](py::module &m) {
return auxiliaries(a, a);
});
// test_array_failures
// 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_t_fail_test", []() { return py::array_t<double>(py::object()); });
// 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); });
// test_initializer_list
// 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_list", []() { return py::array_t<float>({ 1, 2 }); });
sm.def("array_initializer_list", []() { 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_list1", []() { return py::array_t<float>(1); }); // { 1 } also works, but clang warns about it
sm.def("array_initializer_list2", []() { return py::array_t<float>({ 1, 2 }); });
sm.def("array_initializer_list3", []() { return py::array_t<float>({ 1, 2, 3 }); });
sm.def("array_initializer_list4", []() { return py::array_t<float>({ 1, 2, 3, 4 }); });
// test_array_resize
// reshape array to 2D without changing size
sm.def("array_reshape2", [](py::array_t<double> a) {
const ssize_t dim_sz = (ssize_t)std::sqrt(a.size());
......@@ -290,6 +284,7 @@ test_initializer numpy_array([](py::module &m) {
a.resize({N, N, N}, refcheck);
});
// test_array_create_and_resize
// return 2D array with Nrows = Ncols = N
sm.def("create_and_resize", [](size_t N) {
py::array_t<double> a;
......@@ -297,4 +292,4 @@ test_initializer numpy_array([](py::module &m) {
std::fill(a.mutable_data(), a.mutable_data() + a.size(), 42.);
return a;
});
});
}
This diff is collapsed.
......@@ -156,90 +156,6 @@ py::array_t<S, 0> create_recarray(size_t n) {
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>
py::list print_recarray(py::array_t<S, 0> arr) {
const auto req = arr.request();
......@@ -253,45 +169,6 @@ py::list print_recarray(py::array_t<S, 0> arr) {
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) {
using arr_t = py::array_t<int32_t, 0>;
......@@ -367,51 +244,9 @@ py::list test_dtype_ctors() {
return list;
}
struct TrailingPaddingStruct {
int32_t a;
char b;
};
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;
}
TEST_SUBMODULE(numpy_dtypes, m) {
try { py::module::import("numpy"); }
catch (...) { return; }
// typeinfo may be registered before the dtype descriptor for scalar casts to work...
py::class_<SimpleStruct>(m, "SimpleStruct");
......@@ -425,8 +260,6 @@ test_initializer numpy_dtypes([](py::module &m) {
PYBIND11_NUMPY_DTYPE(ArrayStruct, a, b, c, d);
PYBIND11_NUMPY_DTYPE(EnumStruct, e1, e2);
PYBIND11_NUMPY_DTYPE(ComplexStruct, cflt, cdbl);
PYBIND11_NUMPY_DTYPE(TrailingPaddingStruct, a, b);
PYBIND11_NUMPY_DTYPE(CompareStruct, x, y, z);
// ... or after
py::class_<PackedStruct>(m, "PackedStruct");
......@@ -438,35 +271,181 @@ test_initializer numpy_dtypes([](py::module &m) {
// struct NotPOD { std::string v; NotPOD() : v("hi") {}; };
// PYBIND11_NUMPY_DTYPE(NotPOD, v);
// test_recarray, test_scalar_conversion
m.def("create_rec_simple", &create_recarray<SimpleStruct>);
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_nested", &create_partial_nested);
m.def("print_format_descriptors", &print_format_descriptors);
m.def("create_rec_partial_nested", [](size_t n) {
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_packed", &print_recarray<PackedStruct>);
m.def("print_rec_nested", &print_recarray<NestedStruct>);
m.def("print_dtypes", &print_dtypes);
m.def("get_format_unbound", &get_format_unbound);
m.def("create_string_array", &create_string_array);
// test_format_descriptors
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("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("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("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>);
// test_array_constructors
m.def("test_array_ctors", &test_array_ctors);
m.def("test_dtype_ctors", &test_dtype_ctors);
m.def("test_dtype_methods", &test_dtype_methods);
m.def("compare_buffer_info", &test_compare_buffer_info);
m.def("trailing_padding_dtype", &trailing_padding_dtype);
m.def("buffer_to_dtype", &buffer_to_dtype);
// test_compare_buffer_info
struct CompareStruct {
bool x;
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_packed", [](PackedStruct s) { return s.uint_ * 10; });
m.def("f_nested", [](NestedStruct s) { return s.a.uint_ * 10; });
m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); });
});
#undef PYBIND11_PACKED
// test_register_dtype
m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); });
}
This diff is collapsed.
......@@ -16,22 +16,11 @@ double my_func(int x, float y, double z) {
return (float) x*y*z;
}
std::complex<double> my_func3(std::complex<double> c) {
return c * std::complex<double>(2.f);
}
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_SUBMODULE(numpy_vectorize, m) {
try { py::module::import("numpy"); }
catch (...) { return; }
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)
m.def("vectorized_func", py::vectorize(my_func));
......@@ -43,16 +32,24 @@ test_initializer numpy_vectorize([](py::module &m) {
);
// 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<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."; });
// test_passthrough_arguments
// Passthrough test: references and non-pod types should be automatically passed through (in the
// 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>());
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) {
......@@ -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");
vtc .def(py::init<int>())
.def_readwrite("value", &VectorizeTestClass::value);
......@@ -67,6 +70,7 @@ test_initializer numpy_vectorize([](py::module &m) {
// Automatic vectorizing of methods
vtc.def("method", py::vectorize(&VectorizeTestClass::method));
// test_trivial_broadcasting
// Internal optimization test for whether the input is trivially broadcastable:
py::enum_<py::detail::broadcast_trivial>(m, "trivial")
.value("f_trivial", py::detail::broadcast_trivial::f_trivial)
......@@ -82,4 +86,4 @@ test_initializer numpy_vectorize([](py::module &m) {
std::array<py::buffer_info, 3> buffers {{ arg1.request(), arg2.request(), arg3.request() }};
return py::detail::broadcast(buffers, ndim, shape);
});
});
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment