mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-11 08:03:55 +00:00
Merge branch 'master' into smart_holder
This commit is contained in:
commit
c03061fcff
@ -132,6 +132,7 @@ set(PYBIND11_HEADERS
|
||||
include/pybind11/smart_holder.h
|
||||
include/pybind11/stl.h
|
||||
include/pybind11/stl_bind.h
|
||||
include/pybind11/stl/filesystem.h
|
||||
include/pybind11/trampoline_self_life_support.h)
|
||||
|
||||
# Compare with grep and warn if mismatched
|
||||
|
@ -985,6 +985,21 @@ template <> inline void cast_safe<void>(object &&) {}
|
||||
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
|
||||
// The overloads could coexist, i.e. the #if is not strictly speaking needed,
|
||||
// but it is an easy minor optimization.
|
||||
#if defined(NDEBUG)
|
||||
inline cast_error cast_error_unable_to_convert_call_arg() {
|
||||
return cast_error(
|
||||
"Unable to convert call argument to Python object (compile in debug mode for details)");
|
||||
}
|
||||
#else
|
||||
inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name,
|
||||
const std::string &type) {
|
||||
return cast_error("Unable to convert call argument '" + name + "' of type '" + type
|
||||
+ "' to Python object");
|
||||
}
|
||||
#endif
|
||||
|
||||
template <return_value_policy policy = return_value_policy::automatic_reference>
|
||||
tuple make_tuple() { return tuple(0); }
|
||||
|
||||
@ -998,11 +1013,10 @@ template <return_value_policy policy = return_value_policy::automatic_reference,
|
||||
for (size_t i = 0; i < args.size(); i++) {
|
||||
if (!args[i]) {
|
||||
#if defined(NDEBUG)
|
||||
throw cast_error("make_tuple(): unable to convert arguments to Python object (compile in debug mode for details)");
|
||||
throw cast_error_unable_to_convert_call_arg();
|
||||
#else
|
||||
std::array<std::string, size> argtypes { {type_id<Args>()...} };
|
||||
throw cast_error("make_tuple(): unable to convert argument of type '" +
|
||||
argtypes[i] + "' to Python object");
|
||||
throw cast_error_unable_to_convert_call_arg(std::to_string(i), argtypes[i]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -1257,9 +1271,10 @@ private:
|
||||
auto o = reinterpret_steal<object>(detail::make_caster<T>::cast(std::forward<T>(x), policy, {}));
|
||||
if (!o) {
|
||||
#if defined(NDEBUG)
|
||||
argument_cast_error();
|
||||
throw cast_error_unable_to_convert_call_arg();
|
||||
#else
|
||||
argument_cast_error(std::to_string(args_list.size()), type_id<T>());
|
||||
throw cast_error_unable_to_convert_call_arg(
|
||||
std::to_string(args_list.size()), type_id<T>());
|
||||
#endif
|
||||
}
|
||||
args_list.append(o);
|
||||
@ -1287,9 +1302,9 @@ private:
|
||||
}
|
||||
if (!a.value) {
|
||||
#if defined(NDEBUG)
|
||||
argument_cast_error();
|
||||
throw cast_error_unable_to_convert_call_arg();
|
||||
#else
|
||||
argument_cast_error(a.name, a.type);
|
||||
throw cast_error_unable_to_convert_call_arg(a.name, a.type);
|
||||
#endif
|
||||
}
|
||||
m_kwargs[a.name] = a.value;
|
||||
@ -1328,17 +1343,6 @@ private:
|
||||
throw type_error("Got multiple values for keyword argument '" + name + "'");
|
||||
}
|
||||
|
||||
[[noreturn]] static void argument_cast_error() {
|
||||
throw cast_error("Unable to convert call argument to Python object "
|
||||
"(compile in debug mode for details)");
|
||||
}
|
||||
|
||||
[[noreturn]] static void argument_cast_error(const std::string &name,
|
||||
const std::string &type) {
|
||||
throw cast_error("Unable to convert call argument '" + name
|
||||
+ "' of type '" + type + "' to Python object");
|
||||
}
|
||||
|
||||
private:
|
||||
tuple m_args;
|
||||
dict m_kwargs;
|
||||
|
@ -41,21 +41,11 @@
|
||||
# include <variant>
|
||||
# define PYBIND11_HAS_VARIANT 1
|
||||
# endif
|
||||
// std::filesystem::path
|
||||
# if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \
|
||||
PY_VERSION_HEX >= 0x03060000
|
||||
# include <filesystem>
|
||||
# define PYBIND11_HAS_FILESYSTEM 1
|
||||
# endif
|
||||
#elif defined(_MSC_VER) && defined(PYBIND11_CPP17)
|
||||
# include <optional>
|
||||
# include <variant>
|
||||
# define PYBIND11_HAS_OPTIONAL 1
|
||||
# define PYBIND11_HAS_VARIANT 1
|
||||
# if PY_VERSION_HEX >= 0x03060000
|
||||
# include <filesystem>
|
||||
# define PYBIND11_HAS_FILESYSTEM 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
@ -387,77 +377,6 @@ template <typename... Ts>
|
||||
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> { };
|
||||
#endif
|
||||
|
||||
#if defined(PYBIND11_HAS_FILESYSTEM)
|
||||
template<typename T> struct path_caster {
|
||||
|
||||
private:
|
||||
static PyObject* unicode_from_fs_native(const std::string& w) {
|
||||
#if !defined(PYPY_VERSION)
|
||||
return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size()));
|
||||
#else
|
||||
// PyPy mistakenly declares the first parameter as non-const.
|
||||
return PyUnicode_DecodeFSDefaultAndSize(
|
||||
const_cast<char*>(w.c_str()), ssize_t(w.size()));
|
||||
#endif
|
||||
}
|
||||
|
||||
static PyObject* unicode_from_fs_native(const std::wstring& w) {
|
||||
return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size()));
|
||||
}
|
||||
|
||||
public:
|
||||
static handle cast(const T& path, return_value_policy, handle) {
|
||||
if (auto py_str = unicode_from_fs_native(path.native())) {
|
||||
return module::import("pathlib").attr("Path")(reinterpret_steal<object>(py_str))
|
||||
.release();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool load(handle handle, bool) {
|
||||
// PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of
|
||||
// calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy
|
||||
// issue #3168) so we do it ourselves instead.
|
||||
PyObject* buf = PyOS_FSPath(handle.ptr());
|
||||
if (!buf) {
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
PyObject* native = nullptr;
|
||||
if constexpr (std::is_same_v<typename T::value_type, char>) {
|
||||
if (PyUnicode_FSConverter(buf, &native)) {
|
||||
if (auto c_str = PyBytes_AsString(native)) {
|
||||
// AsString returns a pointer to the internal buffer, which
|
||||
// must not be free'd.
|
||||
value = c_str;
|
||||
}
|
||||
}
|
||||
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
|
||||
if (PyUnicode_FSDecoder(buf, &native)) {
|
||||
if (auto c_str = PyUnicode_AsWideCharString(native, nullptr)) {
|
||||
// AsWideCharString returns a new string that must be free'd.
|
||||
value = c_str; // Copies the string.
|
||||
PyMem_Free(c_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
Py_XDECREF(native);
|
||||
Py_DECREF(buf);
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(T, _("os.PathLike"));
|
||||
};
|
||||
|
||||
template<> struct type_caster<std::filesystem::path>
|
||||
: public path_caster<std::filesystem::path> {};
|
||||
#endif
|
||||
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
|
||||
|
103
include/pybind11/stl/filesystem.h
Normal file
103
include/pybind11/stl/filesystem.h
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright (c) 2021 The Pybind Development Team.
|
||||
// All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../cast.h"
|
||||
#include "../pybind11.h"
|
||||
#include "../pytypes.h"
|
||||
|
||||
#include "../detail/common.h"
|
||||
#include "../detail/descr.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef __has_include
|
||||
# if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \
|
||||
PY_VERSION_HEX >= 0x03060000
|
||||
# include <filesystem>
|
||||
# define PYBIND11_HAS_FILESYSTEM 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL)
|
||||
# error \
|
||||
"#include <filesystem> is not available. (Use -DPYBIND11_HAS_FILESYSTEM_IS_OPTIONAL to ignore.)"
|
||||
#endif
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
|
||||
#if defined(PYBIND11_HAS_FILESYSTEM)
|
||||
template<typename T> struct path_caster {
|
||||
|
||||
private:
|
||||
static PyObject* unicode_from_fs_native(const std::string& w) {
|
||||
#if !defined(PYPY_VERSION)
|
||||
return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size()));
|
||||
#else
|
||||
// PyPy mistakenly declares the first parameter as non-const.
|
||||
return PyUnicode_DecodeFSDefaultAndSize(
|
||||
const_cast<char*>(w.c_str()), ssize_t(w.size()));
|
||||
#endif
|
||||
}
|
||||
|
||||
static PyObject* unicode_from_fs_native(const std::wstring& w) {
|
||||
return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size()));
|
||||
}
|
||||
|
||||
public:
|
||||
static handle cast(const T& path, return_value_policy, handle) {
|
||||
if (auto py_str = unicode_from_fs_native(path.native())) {
|
||||
return module_::import("pathlib").attr("Path")(reinterpret_steal<object>(py_str))
|
||||
.release();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool load(handle handle, bool) {
|
||||
// PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of
|
||||
// calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy
|
||||
// issue #3168) so we do it ourselves instead.
|
||||
PyObject* buf = PyOS_FSPath(handle.ptr());
|
||||
if (!buf) {
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
PyObject* native = nullptr;
|
||||
if constexpr (std::is_same_v<typename T::value_type, char>) {
|
||||
if (PyUnicode_FSConverter(buf, &native)) {
|
||||
if (auto c_str = PyBytes_AsString(native)) {
|
||||
// AsString returns a pointer to the internal buffer, which
|
||||
// must not be free'd.
|
||||
value = c_str;
|
||||
}
|
||||
}
|
||||
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
|
||||
if (PyUnicode_FSDecoder(buf, &native)) {
|
||||
if (auto c_str = PyUnicode_AsWideCharString(native, nullptr)) {
|
||||
// AsWideCharString returns a new string that must be free'd.
|
||||
value = c_str; // Copies the string.
|
||||
PyMem_Free(c_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
Py_XDECREF(native);
|
||||
Py_DECREF(buf);
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(T, _("os.PathLike"));
|
||||
};
|
||||
|
||||
template<> struct type_caster<std::filesystem::path>
|
||||
: public path_caster<std::filesystem::path> {};
|
||||
#endif // PYBIND11_HAS_FILESYSTEM
|
||||
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
@ -53,6 +53,10 @@ detail_headers = {
|
||||
"include/pybind11/detail/typeid.h",
|
||||
}
|
||||
|
||||
stl_headers = {
|
||||
"include/pybind11/stl/filesystem.h",
|
||||
}
|
||||
|
||||
cmake_files = {
|
||||
"share/cmake/pybind11/FindPythonLibsNew.cmake",
|
||||
"share/cmake/pybind11/pybind11Common.cmake",
|
||||
@ -74,7 +78,7 @@ py_files = {
|
||||
"setup_helpers.pyi",
|
||||
}
|
||||
|
||||
headers = main_headers | detail_headers
|
||||
headers = main_headers | detail_headers | stl_headers
|
||||
src_files = headers | cmake_files
|
||||
all_files = src_files | py_files
|
||||
|
||||
@ -84,6 +88,7 @@ sdist_files = {
|
||||
"pybind11/include",
|
||||
"pybind11/include/pybind11",
|
||||
"pybind11/include/pybind11/detail",
|
||||
"pybind11/include/pybind11/stl",
|
||||
"pybind11/share",
|
||||
"pybind11/share/cmake",
|
||||
"pybind11/share/cmake/pybind11",
|
||||
|
@ -372,10 +372,10 @@ def test_print(capture):
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
m.print_failure()
|
||||
assert str(excinfo.value) == "make_tuple(): unable to convert " + (
|
||||
"argument of type 'UnregisteredType' to Python object"
|
||||
assert str(excinfo.value) == "Unable to convert call argument " + (
|
||||
"'1' of type 'UnregisteredType' to Python object"
|
||||
if debug_enabled
|
||||
else "arguments to Python object (compile in debug mode for details)"
|
||||
else "to Python object (compile in debug mode for details)"
|
||||
)
|
||||
|
||||
|
||||
|
@ -11,6 +11,11 @@
|
||||
#include "constructor_stats.h"
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
#ifndef PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL
|
||||
#define PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL
|
||||
#endif
|
||||
#include <pybind11/stl/filesystem.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
@ -33,8 +33,9 @@ class InstallHeadersNested(install_headers):
|
||||
|
||||
main_headers = glob.glob("pybind11/include/pybind11/*.h")
|
||||
detail_headers = glob.glob("pybind11/include/pybind11/detail/*.h")
|
||||
stl_headers = glob.glob("pybind11/include/pybind11/stl/*.h")
|
||||
cmake_files = glob.glob("pybind11/share/cmake/pybind11/*.cmake")
|
||||
headers = main_headers + detail_headers
|
||||
headers = main_headers + detail_headers + stl_headers
|
||||
|
||||
cmdclass = {"install_headers": InstallHeadersNested}
|
||||
$extra_cmd
|
||||
@ -58,6 +59,7 @@ setup(
|
||||
(base + "share/cmake/pybind11", cmake_files),
|
||||
(base + "include/pybind11", main_headers),
|
||||
(base + "include/pybind11/detail", detail_headers),
|
||||
(base + "include/pybind11/stl", stl_headers),
|
||||
],
|
||||
cmdclass=cmdclass,
|
||||
)
|
||||
|
@ -16,12 +16,14 @@ setup(
|
||||
"pybind11",
|
||||
"pybind11.include.pybind11",
|
||||
"pybind11.include.pybind11.detail",
|
||||
"pybind11.include.pybind11.stl",
|
||||
"pybind11.share.cmake.pybind11",
|
||||
],
|
||||
package_data={
|
||||
"pybind11": ["py.typed", "*.pyi"],
|
||||
"pybind11.include.pybind11": ["*.h"],
|
||||
"pybind11.include.pybind11.detail": ["*.h"],
|
||||
"pybind11.include.pybind11.stl": ["*.h"],
|
||||
"pybind11.share.cmake.pybind11": ["*.cmake"],
|
||||
},
|
||||
extras_require={
|
||||
|
Loading…
Reference in New Issue
Block a user