Commit 27e8e106 authored by Wenzel Jakob's avatar Wenzel Jakob
Browse files

added new type pybind11::bytes, cleanup of various macros (fixes #49)

parent 2dfbadee
......@@ -801,9 +801,9 @@ For instance, the following statement iterates over a Python ``dict``:
}
Available types include :class:`handle`, :class:`object`, :class:`bool_`,
:class:`int_`, :class:`float_`, :class:`str`, :class:`tuple`, :class:`list`,
:class:`dict`, :class:`slice`, :class:`capsule`, :class:`function`,
:class:`buffer`, :class:`array`, and :class:`array_t`.
:class:`int_`, :class:`float_`, :class:`str`, :class:`bytes`, :class:`tuple`,
:class:`list`, :class:`dict`, :class:`slice`, :class:`capsule`,
:class:`function`, :class:`buffer`, :class:`array`, and :class:`array_t`.
In this kind of mixed code, it is often necessary to convert arbitrary C++
types to Python, which can be done using :func:`cast`:
......
......@@ -72,24 +72,12 @@ public:
std::cout << "key: " << item.first << ", value=" << item.second << std::endl;
}
/* STL data types are automatically casted from Python */
void print_dict_2(const std::map<std::string, std::string> &dict) {
for (auto item : dict)
std::cout << "key: " << item.first << ", value=" << item.second << std::endl;
}
/* Easily iterate over a setionary using a C++11 range-based for loop */
/* Easily iterate over a set using a C++11 range-based for loop */
void print_set(py::set set) {
for (auto item : set)
std::cout << "key: " << item << std::endl;
}
/* STL data types are automatically casted from Python */
void print_set_2(const std::set<std::string> &set) {
for (auto item : set)
std::cout << "key: " << item << std::endl;
}
/* Easily iterate over a list using a C++11 range-based for loop */
void print_list(py::list list) {
int index = 0;
......@@ -97,7 +85,19 @@ public:
std::cout << "list item " << index++ << ": " << item << std::endl;
}
/* STL data types are automatically casted from Python */
/* STL data types (such as maps) are automatically casted from Python */
void print_dict_2(const std::map<std::string, std::string> &dict) {
for (auto item : dict)
std::cout << "key: " << item.first << ", value=" << item.second << std::endl;
}
/* STL data types (such as sets) are automatically casted from Python */
void print_set_2(const std::set<std::string> &set) {
for (auto item : set)
std::cout << "key: " << item << std::endl;
}
/* STL data types (such as vectors) are automatically casted from Python */
void print_list_2(std::vector<std::string> &list) {
int index = 0;
for (auto item : list)
......
/*
example/example4.cpp -- global constants and functions, enumerations
example/example4.cpp -- global constants and functions, enumerations, raw byte strings
Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
......@@ -40,6 +40,17 @@ float test_function3(int i) {
return i / 2.f;
}
py::bytes return_bytes() {
const char *data = "\x01\x00\x02\x00";
return py::bytes(std::string(data, 4));
}
void print_bytes(py::bytes bytes) {
std::string value = (std::string) bytes;
for (size_t i = 0; i < value.length(); ++i)
std::cout << "bytes[" << i << "]=" << (int) value[i] << std::endl;
}
void init_ex4(py::module &m) {
m.def("test_function", &test_function1);
m.def("test_function", &test_function2);
......@@ -57,4 +68,7 @@ void init_ex4(py::module &m) {
.value("EFirstMode", Example4::EFirstMode)
.value("ESecondMode", Example4::ESecondMode)
.export_values();
m.def("return_bytes", &return_bytes);
m.def("print_bytes", &print_bytes);
}
......@@ -8,6 +8,8 @@ from example import some_constant
from example import EMyEnumeration
from example import EFirstEntry
from example import Example4
from example import return_bytes
from example import print_bytes
print(EMyEnumeration)
print(EMyEnumeration.EFirstEntry)
......@@ -23,3 +25,5 @@ print(Example4.EMode)
print(Example4.EMode.EFirstMode)
print(Example4.EFirstMode)
Example4.test_function(Example4.EFirstMode)
print_bytes(return_bytes())
......@@ -14,3 +14,7 @@ None
EMode.EFirstMode
EMode.EFirstMode
Example4::test_function(enum=1)
bytes[0]=1
bytes[1]=0
bytes[2]=2
bytes[3]=0
......@@ -21,6 +21,7 @@ def sanitize(lines):
line = shorten_floats.sub(r'\1', line)
line = line.replace('__builtin__', 'builtins')
line = line.replace('example.', '')
line = line.replace('unicode', 'str')
line = line.replace('method of builtins.PyCapsule instance', '')
line = line.strip()
if sys.platform == 'win32':
......
......@@ -19,12 +19,6 @@
NAMESPACE_BEGIN(pybind11)
NAMESPACE_BEGIN(detail)
#if PY_MAJOR_VERSION >= 3
#define PYBIND11_AS_STRING PyBytes_AsString
#else
#define PYBIND11_AS_STRING PyString_AsString
#endif
class type_caster_custom {
public:
PYBIND11_NOINLINE type_caster_custom(const std::type_info *type_info) {
......@@ -185,9 +179,9 @@ public:
py_value = (py_type) PyLong_AsUnsignedLong(src);
} else {
if (std::is_signed<T>::value)
py_value = (py_type) detail::PyLong_AsLongLong_(src);
py_value = (py_type) PYBIND11_LONG_AS_LONGLONG(src);
else
py_value = (py_type) detail::PyLong_AsUnsignedLongLong_(src);
py_value = (py_type) PYBIND11_LONG_AS_UNSIGNED_LONGLONG(src);
}
if ((py_value == (py_type) -1 && PyErr_Occurred()) ||
......@@ -265,35 +259,41 @@ public:
template <> class type_caster<std::string> {
public:
bool load(PyObject *src, bool) {
#if PY_MAJOR_VERSION < 3
if (PyString_Check(src)) { value = PyString_AsString(src); return true; }
#endif
object temp(PyUnicode_AsUTF8String(src), false);
const char *ptr = nullptr;
if (temp)
ptr = PYBIND11_AS_STRING(temp.ptr());
if (!ptr) { PyErr_Clear(); return false; }
value = ptr;
object temp;
PyObject *load_src = src;
if (PyUnicode_Check(src)) {
temp = object(PyUnicode_AsUTF8String(src), false);
if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError
load_src = temp.ptr();
}
char *buffer;
ssize_t length;
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(load_src, &buffer, &length);
if (err == -1) { PyErr_Clear(); return false; } // TypeError
value = std::string(buffer, length);
return true;
}
static PyObject *cast(const std::string &src, return_value_policy /* policy */, PyObject * /* parent */) {
return PyUnicode_FromString(src.c_str());
return PyUnicode_FromStringAndSize(src.c_str(), src.length());
}
PYBIND11_TYPE_CASTER(std::string, _("str"));
PYBIND11_TYPE_CASTER(std::string, _(PYBIND11_STRING_NAME));
};
template <> class type_caster<char> {
public:
bool load(PyObject *src, bool) {
#if PY_MAJOR_VERSION < 3
if (PyString_Check(src)) { value = PyString_AsString(src); return true; }
#endif
object temp(PyUnicode_AsUTF8String(src), false);
const char *ptr = nullptr;
if (temp)
ptr = PYBIND11_AS_STRING(temp.ptr());
if (!ptr) { PyErr_Clear(); return false; }
value = ptr;
object temp;
PyObject *load_src = src;
if (PyUnicode_Check(src)) {
temp = object(PyUnicode_AsUTF8String(src), false);
if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError
load_src = temp.ptr();
}
const char *ptr = PYBIND11_BYTES_AS_STRING(load_src);
if (!ptr) { PyErr_Clear(); return false; } // TypeError
value = std::string(ptr);
return true;
}
......@@ -306,10 +306,10 @@ public:
return PyUnicode_DecodeLatin1(str, 1, nullptr);
}
static PYBIND11_DESCR name() { return type_descr(_("str")); }
operator char*() { return (char *) value.c_str(); }
operator char() { if (value.length() > 0) return value[0]; else return '\0'; }
static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); }
protected:
std::string value;
};
......
......@@ -85,6 +85,29 @@
} \
PyObject *pybind11_init()
#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
#define PYBIND11_BYTES_CHECK PyBytes_Check
#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize
#define PYBIND11_BYTES_AS_STRING PyBytes_AsString
#define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
#define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) PyLong_AsUnsignedLongLong(o)
#define PYBIND11_STRING_NAME "str"
#define PYBIND11_SLICE_OBJECT PyObject
#else
#define PYBIND11_BYTES_CHECK PyString_Check
#define PYBIND11_BYTES_FROM_STRING PyString_FromString
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize
#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize
#define PYBIND11_BYTES_AS_STRING PyString_AsString
#define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o))
#define PYBIND11_LONG_AS_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o))
#define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) (PyInt_Check(o) ? (unsigned long long) PyLong_AsUnsignedLong(o) : PyLong_AsUnsignedLongLong(o))
#define PYBIND11_STRING_NAME "unicode"
#define PYBIND11_SLICE_OBJECT PySliceObject
#endif
NAMESPACE_BEGIN(pybind11)
......
......@@ -337,7 +337,7 @@ private:
if (a.descr)
a.descr = strdup(a.descr);
else if (a.value)
a.descr = strdup(((object) handle(a.value).attr("__repr__")).call().str());
a.descr = strdup(((std::string) ((object) handle(a.value).attr("__repr__")).call().str()).c_str());
}
auto const &registered_types = detail::get_internals().registered_types;
......@@ -367,7 +367,7 @@ private:
} else if (c == '%') {
const std::type_info *t = types[type_index++];
if (!t)
throw std::runtime_error("Internal error while generating type signature (1)");
throw std::runtime_error("Internal error while parsing type signature (1)");
auto it = registered_types.find(t);
if (it != registered_types.end()) {
signature += it->second.type->tp_name;
......@@ -381,7 +381,7 @@ private:
}
}
if (type_depth != 0 && types[type_index ] != nullptr)
throw std::runtime_error("Internal error while generating type signature (2)");
throw std::runtime_error("Internal error while parsing type signature (2)");
#if !defined(PYBIND11_CPP14)
delete[] types;
......@@ -694,8 +694,8 @@ protected:
view->format = const_cast<char *>(info->format.c_str());
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
view->ndim = info->ndim;
view->strides = (Py_ssize_t *)&info->strides[0];
view->shape = (Py_ssize_t *) &info->shape[0];
view->strides = (ssize_t *) &info->strides[0];
view->shape = (ssize_t *) &info->shape[0];
}
Py_INCREF(view->obj);
return 0;
......@@ -903,7 +903,7 @@ public:
void export_values() {
PyObject *dict = ((PyTypeObject *) this->m_ptr)->tp_dict;
PyObject *key, *value;
Py_ssize_t pos = 0;
ssize_t pos = 0;
while (PyDict_Next(dict, &pos, &key, &value))
if (PyObject_IsInstance(value, this->m_ptr))
m_parent.attr(key) = value;
......@@ -983,9 +983,10 @@ inline function get_overload(const void *this_ptr, const char *name) {
cache.insert(key);
return function();
}
PyFrameObject *frame = PyThreadState_Get()->frame;
pybind11::str caller = pybind11::handle(frame->f_code->co_name).str();
if (strcmp((const char *) caller, name) == 0)
if ((std::string) caller == name)
return function();
return overload;
}
......
......@@ -215,30 +215,6 @@ private:
ssize_t pos = 0;
};
#if PY_MAJOR_VERSION >= 3
inline long long PyLong_AsLongLong_(PyObject *o) { return PyLong_AsLongLong(o); }
inline unsigned long long PyLong_AsUnsignedLongLong_(PyObject *o) { return PyLong_AsUnsignedLongLong(o); }
inline bool PyLong_Check_(PyObject *o) { return PyLong_Check(o); }
#else
inline long long PyLong_AsLongLong_(PyObject *o) {
if (PyInt_Check(o)) /// workaround: PyLong_AsLongLong doesn't accept 'int' on Python 2.x
return (long long) PyLong_AsLong(o);
else
return PyLong_AsLongLong(o);
}
inline unsigned long long PyLong_AsUnsignedLongLong_(PyObject *o) {
if (PyInt_Check(o)) /// workaround: PyLong_AsUnsignedLongLong doesn't accept 'int' on Python 2.x
return (unsigned long long) PyLong_AsUnsignedLong(o);
else
return PyLong_AsUnsignedLongLong(o);
}
inline bool PyLong_Check_(PyObject *o) {
return PyInt_Check(o) || PyLong_Check(o);
}
#endif
NAMESPACE_END(detail)
inline detail::accessor handle::operator[](handle key) const { return detail::accessor(ptr(), key.ptr(), false); }
......@@ -266,21 +242,18 @@ inline iterator handle::end() const { return iterator(nullptr); }
class str : public object {
public:
PYBIND11_OBJECT_DEFAULT(str, object, PyUnicode_Check)
str(const char *s) : object(PyUnicode_FromString(s), false) { }
operator const char *() const {
str(const std::string &s) : object(PyUnicode_FromStringAndSize(s.c_str(), s.length()), false) { }
operator std::string() const {
#if PY_MAJOR_VERSION >= 3
return PyUnicode_AsUTF8(m_ptr);
#else
m_temp = object(PyUnicode_AsUTF8String(m_ptr), false);
if (m_temp.ptr() == nullptr)
return nullptr;
return PyString_AsString(m_temp.ptr());
object temp(PyUnicode_AsUTF8String(m_ptr), false);
if (temp.ptr() == nullptr)
throw std::runtime_error("Unable to extract string contents!");
return PyString_AsString(temp.ptr());
#endif
}
private:
#if PY_MAJOR_VERSION < 3
mutable object m_temp;
#endif
};
inline pybind11::str handle::str() const {
......@@ -292,6 +265,23 @@ inline pybind11::str handle::str() const {
return pybind11::str(str, false);
}
class bytes : public object {
public:
PYBIND11_OBJECT_DEFAULT(bytes, object, PYBIND11_BYTES_CHECK)
bytes(const std::string &s)
: object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(s.data(), s.size()), false) { }
operator std::string() const {
char *buffer;
ssize_t length;
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length);
if (err == -1)
throw std::runtime_error("Unable to extract bytes contents!");
return std::string(buffer, length);
}
};
class bool_ : public object {
public:
PYBIND11_OBJECT_DEFAULT(bool_, object, PyBool_Check)
......@@ -301,7 +291,7 @@ public:
class int_ : public object {
public:
PYBIND11_OBJECT_DEFAULT(int_, object, detail::PyLong_Check_)
PYBIND11_OBJECT_DEFAULT(int_, object, PYBIND11_LONG_CHECK)
template <typename T,
typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
int_(T value) {
......@@ -328,9 +318,9 @@ public:
return (T) PyLong_AsUnsignedLong(m_ptr);
} else {
if (std::is_signed<T>::value)
return (T) detail::PyLong_AsLongLong_(m_ptr);
return (T) PYBIND11_LONG_AS_LONGLONG(m_ptr);
else
return (T) detail::PyLong_AsUnsignedLongLong_(m_ptr);
return (T) PYBIND11_LONG_AS_UNSIGNED_LONGLONG(m_ptr);
}
}
};
......@@ -352,13 +342,8 @@ public:
m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr());
}
bool compute(ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step, ssize_t *slicelength) const {
return PySlice_GetIndicesEx(
#if PY_MAJOR_VERSION >= 3
m_ptr,
#else
(PySliceObject *) m_ptr,
#endif
length, start, stop, step, slicelength) == 0;
return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr, length,
start, stop, step, slicelength) == 0;
}
};
......@@ -377,7 +362,7 @@ public:
class tuple : public object {
public:
PYBIND11_OBJECT(tuple, object, PyTuple_Check)
tuple(size_t size = 0) : object(PyTuple_New((Py_ssize_t) size), false) { }
tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), false) { }
size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
detail::tuple_accessor operator[](size_t index) const { return detail::tuple_accessor(ptr(), index); }
};
......@@ -466,11 +451,11 @@ inline std::string error_string() {
return "";
if (tstate->curexc_type) {
errorString += (const char *) handle(tstate->curexc_type).str();
errorString += (std::string) handle(tstate->curexc_type).str();
errorString += ": ";
}
if (tstate->curexc_value)
errorString += (const char *) handle(tstate->curexc_value).str();
errorString += (std::string) handle(tstate->curexc_value).str();
return errorString;
}
......
......@@ -131,7 +131,7 @@ public:
NAMESPACE_END(detail)
inline std::ostream &operator<<(std::ostream &os, const object &obj) { os << (const char *) obj.str(); return os; }
inline std::ostream &operator<<(std::ostream &os, const object &obj) { os << (std::string) obj.str(); return os; }
NAMESPACE_END(pybind11)
......
Supports Markdown
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