mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-25 14:45:12 +00:00
Add pybind11::bytearray (#2799)
* Add initial implementation * Add few more methods * Add tests * Fix a typo * Use std::string constructor which takes size * Fix implicit sign conversion error * Add size method and test * Remove implicit conversion * Fix bytearray constructors and operator std::string() * Make implicit bytearray constructor explicit * Rerun tests * Add null check * Rerun tests * Rerun tests - 2 * Remove NULL check
This commit is contained in:
parent
cbae6d55c2
commit
417067eeb8
@ -1070,6 +1070,34 @@ inline str::str(const bytes& b) {
|
|||||||
m_ptr = obj.release().ptr();
|
m_ptr = obj.release().ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \addtogroup pytypes
|
||||||
|
/// @{
|
||||||
|
class bytearray : public object {
|
||||||
|
public:
|
||||||
|
PYBIND11_OBJECT_CVT(bytearray, object, PyByteArray_Check, PyByteArray_FromObject)
|
||||||
|
|
||||||
|
bytearray(const char *c, size_t n)
|
||||||
|
: object(PyByteArray_FromStringAndSize(c, (ssize_t) n), stolen_t{}) {
|
||||||
|
if (!m_ptr) pybind11_fail("Could not allocate bytearray object!");
|
||||||
|
}
|
||||||
|
|
||||||
|
bytearray()
|
||||||
|
: bytearray("", 0) {}
|
||||||
|
|
||||||
|
explicit bytearray(const std::string &s) : bytearray(s.data(), s.size()) { }
|
||||||
|
|
||||||
|
size_t size() const { return static_cast<size_t>(PyByteArray_Size(m_ptr)); }
|
||||||
|
|
||||||
|
explicit operator std::string() const {
|
||||||
|
char *buffer = PyByteArray_AS_STRING(m_ptr);
|
||||||
|
ssize_t size = PyByteArray_GET_SIZE(m_ptr);
|
||||||
|
return std::string(buffer, static_cast<size_t>(size));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Note: breathe >= 4.17.0 will fail to build docs if the below two constructors
|
||||||
|
// are included in the doxygen group; close here and reopen after as a workaround
|
||||||
|
/// @} pytypes
|
||||||
|
|
||||||
/// \addtogroup pytypes
|
/// \addtogroup pytypes
|
||||||
/// @{
|
/// @{
|
||||||
class none : public object {
|
class none : public object {
|
||||||
|
@ -92,6 +92,10 @@ TEST_SUBMODULE(pytypes, m) {
|
|||||||
m.def("bytes_from_string", []() { return py::bytes(std::string("foo")); });
|
m.def("bytes_from_string", []() { return py::bytes(std::string("foo")); });
|
||||||
m.def("bytes_from_str", []() { return py::bytes(py::str("bar", 3)); });
|
m.def("bytes_from_str", []() { return py::bytes(py::str("bar", 3)); });
|
||||||
|
|
||||||
|
// test bytearray
|
||||||
|
m.def("bytearray_from_string", []() { return py::bytearray(std::string("foo")); });
|
||||||
|
m.def("bytearray_size", []() { return py::bytearray("foo").size(); });
|
||||||
|
|
||||||
// test_capsule
|
// test_capsule
|
||||||
m.def("return_capsule_with_destructor", []() {
|
m.def("return_capsule_with_destructor", []() {
|
||||||
py::print("creating capsule");
|
py::print("creating capsule");
|
||||||
@ -210,6 +214,7 @@ TEST_SUBMODULE(pytypes, m) {
|
|||||||
m.def("default_constructors", []() {
|
m.def("default_constructors", []() {
|
||||||
return py::dict(
|
return py::dict(
|
||||||
"bytes"_a=py::bytes(),
|
"bytes"_a=py::bytes(),
|
||||||
|
"bytearray"_a=py::bytearray(),
|
||||||
"str"_a=py::str(),
|
"str"_a=py::str(),
|
||||||
"bool"_a=py::bool_(),
|
"bool"_a=py::bool_(),
|
||||||
"int"_a=py::int_(),
|
"int"_a=py::int_(),
|
||||||
@ -224,6 +229,7 @@ TEST_SUBMODULE(pytypes, m) {
|
|||||||
m.def("converting_constructors", [](py::dict d) {
|
m.def("converting_constructors", [](py::dict d) {
|
||||||
return py::dict(
|
return py::dict(
|
||||||
"bytes"_a=py::bytes(d["bytes"]),
|
"bytes"_a=py::bytes(d["bytes"]),
|
||||||
|
"bytearray"_a=py::bytearray(d["bytearray"]),
|
||||||
"str"_a=py::str(d["str"]),
|
"str"_a=py::str(d["str"]),
|
||||||
"bool"_a=py::bool_(d["bool"]),
|
"bool"_a=py::bool_(d["bool"]),
|
||||||
"int"_a=py::int_(d["int"]),
|
"int"_a=py::int_(d["int"]),
|
||||||
@ -240,6 +246,7 @@ TEST_SUBMODULE(pytypes, m) {
|
|||||||
// When converting between Python types, obj.cast<T>() should be the same as T(obj)
|
// When converting between Python types, obj.cast<T>() should be the same as T(obj)
|
||||||
return py::dict(
|
return py::dict(
|
||||||
"bytes"_a=d["bytes"].cast<py::bytes>(),
|
"bytes"_a=d["bytes"].cast<py::bytes>(),
|
||||||
|
"bytearray"_a=d["bytearray"].cast<py::bytearray>(),
|
||||||
"str"_a=d["str"].cast<py::str>(),
|
"str"_a=d["str"].cast<py::str>(),
|
||||||
"bool"_a=d["bool"].cast<py::bool_>(),
|
"bool"_a=d["bool"].cast<py::bool_>(),
|
||||||
"int"_a=d["int"].cast<py::int_>(),
|
"int"_a=d["int"].cast<py::int_>(),
|
||||||
|
@ -143,6 +143,11 @@ def test_bytes(doc):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bytearray(doc):
|
||||||
|
assert m.bytearray_from_string().decode() == "foo"
|
||||||
|
assert m.bytearray_size() == len("foo")
|
||||||
|
|
||||||
|
|
||||||
def test_capsule(capture):
|
def test_capsule(capture):
|
||||||
pytest.gc_collect()
|
pytest.gc_collect()
|
||||||
with capture:
|
with capture:
|
||||||
@ -223,7 +228,7 @@ def test_accessors():
|
|||||||
|
|
||||||
def test_constructors():
|
def test_constructors():
|
||||||
"""C++ default and converting constructors are equivalent to type calls in Python"""
|
"""C++ default and converting constructors are equivalent to type calls in Python"""
|
||||||
types = [bytes, str, bool, int, float, tuple, list, dict, set]
|
types = [bytes, bytearray, str, bool, int, float, tuple, list, dict, set]
|
||||||
expected = {t.__name__: t() for t in types}
|
expected = {t.__name__: t() for t in types}
|
||||||
if env.PY2:
|
if env.PY2:
|
||||||
# Note that bytes.__name__ == 'str' in Python 2.
|
# Note that bytes.__name__ == 'str' in Python 2.
|
||||||
@ -234,6 +239,7 @@ def test_constructors():
|
|||||||
|
|
||||||
data = {
|
data = {
|
||||||
bytes: b"41", # Currently no supported or working conversions.
|
bytes: b"41", # Currently no supported or working conversions.
|
||||||
|
bytearray: bytearray(b"41"),
|
||||||
str: 42,
|
str: 42,
|
||||||
bool: "Not empty",
|
bool: "Not empty",
|
||||||
int: "42",
|
int: "42",
|
||||||
|
Loading…
Reference in New Issue
Block a user