Working type casters for wide strings and wide characters
diff --git a/MANIFEST.in b/MANIFEST.in
index 7259680..33c22c8 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,2 +1 @@
-include setup.py
include include/pybind11/*.h
diff --git a/README.md b/README.md
index 6763c06..85172cc 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
[](http://pybind11.readthedocs.org/en/latest/?badge=latest)
[](https://travis-ci.org/pybind/pybind11)
-[](https://ci.appveyor.com/project/pybind/pybind11)
+[](https://ci.appveyor.com/project/wjakob/pybind11)
**pybind11** is a lightweight header-only library that exposes C++ types in Python
and vice versa, mainly to create Python bindings of existing C++ code. Its
@@ -92,8 +92,10 @@
Jonas Adler,
Sylvain Corlay,
Axel Huebl,
-Johan Mabille, and
-Tomasz Miąsko.
+@hulucc,
+Johan Mabille,
+Tomasz Miąsko, and
+Ben Pritchard.
### License
diff --git a/conda.recipe/bld.bat b/conda.recipe/bld.bat
new file mode 100644
index 0000000..b9cd616
--- /dev/null
+++ b/conda.recipe/bld.bat
@@ -0,0 +1,2 @@
+"%PYTHON%" setup.py install --single-version-externally-managed --record=record.txt
+if errorlevel 1 exit 1
diff --git a/conda.recipe/build.sh b/conda.recipe/build.sh
new file mode 100644
index 0000000..175d6f1
--- /dev/null
+++ b/conda.recipe/build.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+${PYTHON} setup.py install --single-version-externally-managed --record=record.txt;
+
diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml
new file mode 100644
index 0000000..218391f
--- /dev/null
+++ b/conda.recipe/meta.yaml
@@ -0,0 +1,26 @@
+package:
+ name: pybind11
+ version: {{ environ.get('GIT_DESCRIBE_TAG', '') }}
+
+build:
+ number: {{ environ.get('GIT_DESCRIBE_NUMBER', 0) }}
+ {% if environ.get('GIT_DESCRIBE_NUMBER', '0') == '0' %}string: py{{ environ.get('PY_VER').replace('.', '') }}_0
+ {% else %}string: py{{ environ.get('PY_VER').replace('.', '') }}_{{ environ.get('GIT_BUILD_STR', 'GIT_STUB') }}{% endif %}
+
+source:
+ git_url: ../
+
+requirements:
+ build:
+ - python
+
+ run:
+ - python
+
+test:
+ imports:
+ - pybind11
+
+about:
+ home: https://github.com/wjakob/pybind11/
+ summary: Seamless operability between C++11 and Python
diff --git a/docs/_static/theme_overrides.css b/docs/_static/theme_overrides.css
index d746829..f678ab5 100644
--- a/docs/_static/theme_overrides.css
+++ b/docs/_static/theme_overrides.css
@@ -1,7 +1,7 @@
.wy-table-responsive table td,
.wy-table-responsive table th {
- white-space: initial;
+ white-space: initial !important;
}
.rst-content table.docutils td {
- vertical-align: top;
+ vertical-align: top !important;
}
diff --git a/docs/advanced.rst b/docs/advanced.rst
index 1c2e4f4..f24d3b5 100644
--- a/docs/advanced.rst
+++ b/docs/advanced.rst
@@ -1007,11 +1007,20 @@
py::class_<MyClass>("MyClass")
.def("myFunction", py::arg_t<SomeType>("arg", SomeType(123), "SomeType(123)"));
+Sometimes it may be necessary to pass a null pointer value as a default
+argument. In this case, remember to cast it to the underlying type in question,
+like so:
+
+.. code-block:: cpp
+
+ py::class_<MyClass>("MyClass")
+ .def("myFunction", py::arg("arg") = (SomeType *) nullptr);
+
Partitioning code over multiple extension modules
=================================================
-It's straightforward to split binding code over multiple extension modules and
-reference types declared elsewhere. Everything "just" works without any special
+It's straightforward to split binding code over multiple extension modules, while
+referencing types that are declared elsewhere. Everything "just" works without any special
precautions. One exception to this rule occurs when wanting to extend a type declared
in another extension module. Recall the basic example from Section
:ref:`inheritance`.
@@ -1040,3 +1049,17 @@
.def(py::init<const std::string &>())
.def("bark", &Dog::bark);
+Alternatively, we can rely on the ``base`` tag, which performs an automated
+lookup of the corresponding Python type. However, this also requires invoking
+the ``import`` function once to ensure that the pybind11 binding code of the
+module ``basic`` has been executed.
+
+Naturally, both methods will fail when there are cyclic dependencies.
+
+.. code-block:: cpp
+
+ py::module::import("basic");
+
+ py::class_<Dog>(m, "Dog", py::base<Pet>())
+ .def(py::init<const std::string &>())
+ .def("bark", &Dog::bark);
diff --git a/docs/basics.rst b/docs/basics.rst
index 53a325e..cb8962c 100644
--- a/docs/basics.rst
+++ b/docs/basics.rst
@@ -241,10 +241,14 @@
+----------------------------+--------------------------+-----------------------+
| char | Character literal | pybind11/pybind11.h |
+----------------------------+--------------------------+-----------------------+
+| wchar_t | Wide character literal | pybind11/pybind11.h |
++----------------------------+--------------------------+-----------------------+
| const char * | UTF-8 string literal | pybind11/pybind11.h |
+----------------------------+--------------------------+-----------------------+
| std::string | STL dynamic UTF-8 string | pybind11/pybind11.h |
+----------------------------+--------------------------+-----------------------+
+| std::wstring | STL dynamic wide string | pybind11/pybind11.h |
++----------------------------+--------------------------+-----------------------+
| std::pair<T1, T2> | Pair of two custom types | pybind11/pybind11.h |
+----------------------------+--------------------------+-----------------------+
| std::tuple<....> | Arbitrary tuple of types | pybind11/pybind11.h |
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 9850e46..00fd2ea 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -3,14 +3,20 @@
Changelog
#########
-1.3 (not yet released)
+1.4 (not yet released)
+--------------------------
+* Transparent type conversion for ``std::wstring`` and ``wchar_t``
+
+1.3 (March 8, 2016)
--------------------------
* Added support for the Intel C++ compiler (v15+)
* Added support for the STL unordered set/map data structures
+* Added support for the STL linked list data structure
* NumPy-style broadcasting support in ``pybind11::vectorize``
* pybind11 now displays more verbose error messages when ``arg::operator=()`` fails.
-* Removed 'pybind11' python package whose purpose was never quite defined
+* pybind11 internal data structures now live in a version-dependent namespace to avoid ABI issues
+* Many, many bugfixes involving corner cases and advanced usage
1.2 (February 7, 2016)
--------------------------
diff --git a/docs/release.rst b/docs/release.rst
index 2296225..b5d18cf 100644
--- a/docs/release.rst
+++ b/docs/release.rst
@@ -1,12 +1,12 @@
To release a new version of pybind11:
-- Update version macros in `include/pybind11/common.h`
- Update `pybind11/_version.py` (set release version, remove 'dev')
- `git add` and `git commit`.
- `python setup.py sdist upload`.
- `python setup.py bdist_wheel upload`.
- `git tag -a X.X -m 'Release tag comment'`.
- Update `_version.py` (add 'dev' and increment minor).
+- Update version macros in `include/pybind11/common.h`
- `git add` and `git commit`. `git push`. `git push --tags`.
The remote for the last `git push --tags` should be the main repository for
diff --git a/example/example2.cpp b/example/example2.cpp
index 3282a85..b137f99 100644
--- a/example/example2.cpp
+++ b/example/example2.cpp
@@ -60,9 +60,9 @@
}
/* C++ STL data types are automatically casted */
- std::vector<std::string> get_list_2() {
- std::vector<std::string> list;
- list.push_back("value");
+ std::vector<std::wstring> get_list_2() {
+ std::vector<std::wstring> list;
+ list.push_back(L"value");
return list;
}
@@ -103,10 +103,10 @@
}
/* STL data types (such as vectors) are automatically casted from Python */
- void print_list_2(std::vector<std::string> &list) {
+ void print_list_2(std::vector<std::wstring> &list) {
int index = 0;
for (auto item : list)
- std::cout << "list item " << index++ << ": " << item << std::endl;
+ std::wcout << L"list item " << index++ << L": " << item << std::endl;
}
/* pybind automatically translates between C++11 and Python tuples */
diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h
index 1428d4c..f22b670 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -34,12 +34,13 @@
if (internals_ptr)
return *internals_ptr;
handle builtins(PyEval_GetBuiltins());
- capsule caps(builtins["__pybind11__"]);
+ const char *id = PYBIND11_INTERNALS_ID;
+ capsule caps(builtins[id]);
if (caps.check()) {
internals_ptr = caps;
} else {
internals_ptr = new internals();
- builtins["__pybind11__"] = capsule(internals_ptr);
+ builtins[id] = capsule(internals_ptr);
}
return *internals_ptr;
}
@@ -203,7 +204,7 @@
protected:
template <typename T = type, typename std::enable_if<detail::is_copy_constructible<T>::value, int>::type = 0>
static void *copy_constructor(const void *arg) {
- return new type(*((const type *) arg));
+ return (void *) new type(*((const type *) arg));
}
template <typename T = type, typename std::enable_if<!detail::is_copy_constructible<T>::value, int>::type = 0>
static void *copy_constructor(const void *) { return nullptr; }
@@ -358,8 +359,22 @@
if (!temp) { PyErr_Clear(); return false; }
load_src = temp;
}
- wchar_t *buffer = PyUnicode_AS_UNICODE(load_src.ptr());
- size_t length = PyUnicode_GET_SIZE(load_src.ptr());
+ wchar_t *buffer = nullptr;
+ ssize_t length = -1;
+#if PY_MAJOR_VERSION >= 3
+ buffer = PyUnicode_AsWideCharString(load_src.ptr(), &length);
+#else
+ temp = object(
+ sizeof(wchar_t) == sizeof(short)
+ ? PyUnicode_AsUTF16String(load_src.ptr())
+ : PyUnicode_AsUTF32String(load_src.ptr()), false);
+ if (temp) {
+ int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), (char **) &buffer, &length);
+ if (err == -1) { buffer = nullptr; } // TypeError
+ length = length / sizeof(wchar_t) - 1; ++buffer; // Skip BOM
+ }
+#endif
+ if (!buffer) { PyErr_Clear(); return false; }
value = std::wstring(buffer, length);
return true;
}
@@ -371,22 +386,8 @@
PYBIND11_TYPE_CASTER(std::wstring, _(PYBIND11_STRING_NAME));
};
-template <> class type_caster<char> {
+template <> class type_caster<char> : public type_caster<std::string> {
public:
- bool load(handle src, bool) {
- object temp;
- handle load_src = src;
- if (PyUnicode_Check(load_src.ptr())) {
- temp = object(PyUnicode_AsUTF8String(load_src.ptr()), false);
- if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError
- load_src = temp;
- }
- const char *ptr = PYBIND11_BYTES_AS_STRING(load_src.ptr());
- if (!ptr) { PyErr_Clear(); return false; } // TypeError
- value = std::string(ptr);
- return true;
- }
-
static handle cast(const char *src, return_value_policy /* policy */, handle /* parent */) {
return PyUnicode_FromString(src);
}
@@ -404,22 +405,8 @@
std::string value;
};
-template <> class type_caster<wchar_t> {
+template <> class type_caster<wchar_t> : public type_caster<std::wstring> {
public:
- bool load(handle src, bool) {
- object temp;
- handle load_src = src;
- if (!PyUnicode_Check(load_src.ptr())) {
- temp = object(PyUnicode_FromObject(load_src.ptr()), false);
- if (!temp) { PyErr_Clear(); return false; }
- load_src = temp;
- }
- wchar_t *buffer = PyUnicode_AS_UNICODE(load_src.ptr());
- size_t length = PyUnicode_GET_SIZE(load_src.ptr());
- value = std::wstring(buffer, length);
- return true;
- }
-
static handle cast(const wchar_t *src, return_value_policy /* policy */, handle /* parent */) {
return PyUnicode_FromWideChar(src, wcslen(src));
}
@@ -556,12 +543,14 @@
using type_caster<type>::copy_constructor;
bool load(handle src, bool convert) {
- if (!src || !typeinfo)
+ if (!src || !typeinfo) {
return false;
-
- if (PyType_IsSubtype(Py_TYPE(src.ptr()), typeinfo->type)) {
+ } else if (src.ptr() == Py_None) {
+ value = nullptr;
+ return true;
+ } else if (PyType_IsSubtype(Py_TYPE(src.ptr()), typeinfo->type)) {
auto inst = (instance<type, holder_type> *) src.ptr();
- value = inst->value;
+ value = (void *) inst->value;
holder = inst->holder;
return true;
}
@@ -621,7 +610,7 @@
detail::type_caster<typename detail::intrinsic_type<T>::type> conv;
if (!conv.load(handle, true))
throw cast_error("Unable to cast Python object to C++ type");
- return conv;
+ return (T) conv;
}
template <typename T> inline object cast(const T &value, return_value_policy policy = return_value_policy::automatic, handle parent = handle()) {
diff --git a/include/pybind11/common.h b/include/pybind11/common.h
index e4cb9be..3cefa93 100644
--- a/include/pybind11/common.h
+++ b/include/pybind11/common.h
@@ -31,7 +31,7 @@
#endif
#define PYBIND11_VERSION_MAJOR 1
-#define PYBIND11_VERSION_MINOR 3
+#define PYBIND11_VERSION_MINOR 4
/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode
#if defined(_MSC_VER)
@@ -110,6 +110,10 @@
#endif
#define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code
+#define PYBIND11_STRINGIFY(x) #x
+#define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x)
+#define PYBIND11_INTERNALS_ID "__pybind11_" \
+ PYBIND11_TOSTRING(PYBIND11_VERSION_MAJOR) "_" PYBIND11_TOSTRING(PYBIND11_VERSION_MINOR) "__"
#define PYBIND11_PLUGIN(name) \
static PyObject *pybind11_init(); \
diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h
index c78f1e2..4cf8ead 100644
--- a/include/pybind11/pybind11.h
+++ b/include/pybind11/pybind11.h
@@ -864,7 +864,7 @@
template <typename T>
static void init_holder_helper(instance_type *inst, const holder_type * /* unused */, const std::enable_shared_from_this<T> * /* dummy */) {
try {
- new (&inst->holder) holder_type(inst->value->shared_from_this());
+ new (&inst->holder) holder_type(std::static_pointer_cast<type>(inst->value->shared_from_this()));
} catch (const std::bad_weak_ptr &) {
new (&inst->holder) holder_type(inst->value);
}
diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h
index fca1ab8..97ccdbc 100644
--- a/include/pybind11/stl.h
+++ b/include/pybind11/stl.h
@@ -72,7 +72,7 @@
if (!kconv.load(it.first.ptr(), convert) ||
!vconv.load(it.second.ptr(), convert))
return false;
- value[(Key) kconv] = (Value) vconv;
+ value.emplace((Key) kconv, (Value) vconv);
}
return true;
}
diff --git a/pybind11/_version.py b/pybind11/_version.py
index 6e1c20f..8c37a3f 100644
--- a/pybind11/_version.py
+++ b/pybind11/_version.py
@@ -1,2 +1,2 @@
-version_info = (1, 3, 'dev0')
+version_info = (1, 4, 'dev0')
__version__ = '.'.join(map(str, version_info))
diff --git a/setup.py b/setup.py
index d8c5987..362b753 100644
--- a/setup.py
+++ b/setup.py
@@ -41,7 +41,6 @@
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
- 'Programming Language :: Python :: 3.6',
'License :: OSI Approved :: BSD License',
],
keywords='C++11, Python bindings',