// 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 "../pybind11.h" #include "../detail/common.h" #include "../detail/descr.h" #include "../cast.h" #include "../pytypes.h" #include #ifdef __has_include # if defined(PYBIND11_CPP17) # if __has_include() && \ PY_VERSION_HEX >= 0x03060000 # include # define PYBIND11_HAS_FILESYSTEM 1 # elif __has_include() # include # define PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM 1 # endif # endif #endif #if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) \ && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL) # error \ "Neither #include nor #include 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(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(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) { if (PyUnicode_FSConverter(buf, &native) != 0) { 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) { if (PyUnicode_FSDecoder(buf, &native) != 0) { 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, const_name("os.PathLike")); }; #endif // PYBIND11_HAS_FILESYSTEM || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) #if defined(PYBIND11_HAS_FILESYSTEM) template <> struct type_caster : public path_caster {}; #elif defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) template <> struct type_caster : public path_caster {}; #endif PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)