mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-16 21:57:55 +00:00
Fix Python 3 bytes
conversion to std::string/char*
The Unicode support added in 2.1 (PR #624) inadvertently broke accepting `bytes` as std::string/char* arguments. This restores it with a separate path that does a plain conversion (i.e. completely bypassing all the encoding/decoding code), but only for single-byte string types.
This commit is contained in:
parent
ce494d65de
commit
a7f704b39b
@ -693,9 +693,9 @@ struct type_caster<std::basic_string<CharT, Traits, Allocator>, enable_if_t<is_s
|
||||
return false;
|
||||
} else if (!PyUnicode_Check(load_src.ptr())) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return false;
|
||||
// The below is a guaranteed failure in Python 3 when PyUnicode_Check returns false
|
||||
return load_bytes(load_src);
|
||||
#else
|
||||
// The below is a guaranteed failure in Python 3 when PyUnicode_Check returns false
|
||||
if (!PYBIND11_BYTES_CHECK(load_src.ptr()))
|
||||
return false;
|
||||
temp = reinterpret_steal<object>(PyUnicode_FromObject(load_src.ptr()));
|
||||
@ -740,6 +740,28 @@ private:
|
||||
return PyUnicode_Decode(buffer, nbytes, UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
// In Python 3, when loading into a std::string or char*, accept a bytes object as-is (i.e.
|
||||
// without any encoding/decoding attempt). For other C++ char sizes this is a no-op. Python 2,
|
||||
// which supports loading a unicode from a str, doesn't take this path.
|
||||
template <typename C = CharT>
|
||||
bool load_bytes(enable_if_t<sizeof(C) == 1, handle> src) {
|
||||
if (PYBIND11_BYTES_CHECK(src.ptr())) {
|
||||
// We were passed a Python 3 raw bytes; accept it into a std::string or char*
|
||||
// without any encoding attempt.
|
||||
const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr());
|
||||
if (bytes) {
|
||||
value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
template <typename C = CharT>
|
||||
bool load_bytes(enable_if_t<sizeof(C) != 1, handle>) { return false; }
|
||||
#endif
|
||||
};
|
||||
|
||||
// Type caster for C-style strings. We basically use a std::string type caster, but also add the
|
||||
|
@ -473,6 +473,9 @@ test_initializer python_types([](py::module &m) {
|
||||
m.def("ord_char32", [](char32_t c) -> uint32_t { return c; });
|
||||
m.def("ord_wchar", [](wchar_t c) -> int { return c; });
|
||||
|
||||
m.def("strlen", [](char *s) { return strlen(s); });
|
||||
m.def("string_length", [](std::string s) { return s.length(); });
|
||||
|
||||
m.def("return_none_string", []() -> std::string * { return nullptr; });
|
||||
m.def("return_none_char", []() -> const char * { return nullptr; });
|
||||
m.def("return_none_bool", []() -> bool * { return nullptr; });
|
||||
|
@ -511,6 +511,20 @@ def test_single_char_arguments():
|
||||
assert str(excinfo.value) == toolong_message
|
||||
|
||||
|
||||
def test_bytes_to_string():
|
||||
"""Tests the ability to pass bytes to C++ string-accepting functions. Note that this is
|
||||
one-way: the only way to return bytes to Python is via the pybind11::bytes class."""
|
||||
# Issue #816
|
||||
from pybind11_tests import strlen, string_length
|
||||
import sys
|
||||
byte = bytes if sys.version_info[0] < 3 else str
|
||||
|
||||
assert strlen(byte("hi")) == 2
|
||||
assert string_length(byte("world")) == 5
|
||||
assert string_length(byte("a\x00b")) == 3
|
||||
assert strlen(byte("a\x00b")) == 1 # C-string limitation
|
||||
|
||||
|
||||
def test_builtins_cast_return_none():
|
||||
"""Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None"""
|
||||
import pybind11_tests as m
|
||||
|
Loading…
Reference in New Issue
Block a user