Skip to content

Commit 5612a0c

Browse files
committed
generalized str::operator std::string() to accept 'bytes'(3.x)/'string'(2.7)
1 parent fc92d82 commit 5612a0c

File tree

2 files changed

+20
-11
lines changed

2 files changed

+20
-11
lines changed

include/pybind11/common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
8282
#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize
8383
#define PYBIND11_BYTES_AS_STRING PyBytes_AsString
84+
#define PYBIND11_BYTES_CHECK PyBytes_Check
8485
#define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
8586
#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
8687
#define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) PyLong_AsUnsignedLongLong(o)
@@ -98,6 +99,7 @@
9899
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize
99100
#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize
100101
#define PYBIND11_BYTES_AS_STRING PyString_AsString
102+
#define PYBIND11_BYTES_CHECK PyString_Check
101103
#define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o))
102104
#define PYBIND11_LONG_AS_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o))
103105
#define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) (PyInt_Check(o) ? (unsigned long long) PyLong_AsUnsignedLong(o) : PyLong_AsUnsignedLongLong(o))

include/pybind11/pytypes.h

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ struct list_accessor {
163163
return object(result, true);
164164
}
165165

166-
template <typename T> inline T cast() const { return operator object().cast<T>(); }
166+
template <typename T> T cast() const { return operator object().cast<T>(); }
167167
private:
168168
handle list;
169169
size_t index;
@@ -188,7 +188,7 @@ struct tuple_accessor {
188188
return object(result, true);
189189
}
190190

191-
template <typename T> inline T cast() const { return operator object().cast<T>(); }
191+
template <typename T> T cast() const { return operator object().cast<T>(); }
192192
private:
193193
handle tuple;
194194
size_t index;
@@ -225,6 +225,8 @@ inline bool PyIterable_Check(PyObject *obj) {
225225

226226
inline bool PyNone_Check(PyObject *o) { return o == Py_None; }
227227

228+
inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); }
229+
228230
NAMESPACE_END(detail)
229231

230232
#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, CvtStmt) \
@@ -316,21 +318,26 @@ inline iterator handle::end() const { return iterator(nullptr, false); }
316318

317319
class str : public object {
318320
public:
319-
PYBIND11_OBJECT_DEFAULT(str, object, PyUnicode_Check)
321+
PYBIND11_OBJECT_DEFAULT(str, object, detail::PyUnicode_Check_Permissive)
322+
320323
str(const std::string &s)
321324
: object(PyUnicode_FromStringAndSize(s.c_str(), s.length()), false) {
322325
if (!m_ptr) pybind11_fail("Could not allocate string object!");
323326
}
324327

325328
operator std::string() const {
326-
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
327-
return PyUnicode_AsUTF8(m_ptr);
328-
#else
329-
object temp(PyUnicode_AsUTF8String(m_ptr), false);
330-
if (temp.ptr() == nullptr)
331-
pybind11_fail("Unable to extract string contents!");
332-
return PYBIND11_BYTES_AS_STRING(temp.ptr());
333-
#endif
329+
object temp = *this;
330+
if (PyUnicode_Check(m_ptr)) {
331+
temp = object(PyUnicode_AsUTF8String(m_ptr), false);
332+
if (!temp)
333+
pybind11_fail("Unable to extract string contents! (encoding issue)");
334+
}
335+
char *buffer;
336+
ssize_t length;
337+
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length);
338+
if (err == -1)
339+
pybind11_fail("Unable to extract string contents! (invalid type)");
340+
return std::string(buffer, length);
334341
}
335342
};
336343

0 commit comments

Comments
 (0)