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