File indexing completed on 2025-02-16 05:12:14
0001 // Copyright (c) 2021 The Pybind Development Team. 0002 // All rights reserved. Use of this source code is governed by a 0003 // BSD-style license that can be found in the LICENSE file. 0004 0005 #pragma once 0006 0007 #include "../cast.h" 0008 #include "../pybind11.h" 0009 #include "../pytypes.h" 0010 0011 #include "../detail/common.h" 0012 #include "../detail/descr.h" 0013 0014 #include <string> 0015 0016 #ifdef __has_include 0017 # if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \ 0018 PY_VERSION_HEX >= 0x03060000 0019 # include <filesystem> 0020 # define PYBIND11_HAS_FILESYSTEM 1 0021 # endif 0022 #endif 0023 0024 #if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL) 0025 # error \ 0026 "#include <filesystem> is not available. (Use -DPYBIND11_HAS_FILESYSTEM_IS_OPTIONAL to ignore.)" 0027 #endif 0028 0029 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 0030 PYBIND11_NAMESPACE_BEGIN(detail) 0031 0032 #if defined(PYBIND11_HAS_FILESYSTEM) 0033 template<typename T> struct path_caster { 0034 0035 private: 0036 static PyObject* unicode_from_fs_native(const std::string& w) { 0037 #if !defined(PYPY_VERSION) 0038 return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size())); 0039 #else 0040 // PyPy mistakenly declares the first parameter as non-const. 0041 return PyUnicode_DecodeFSDefaultAndSize( 0042 const_cast<char*>(w.c_str()), ssize_t(w.size())); 0043 #endif 0044 } 0045 0046 static PyObject* unicode_from_fs_native(const std::wstring& w) { 0047 return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size())); 0048 } 0049 0050 public: 0051 static handle cast(const T& path, return_value_policy, handle) { 0052 if (auto py_str = unicode_from_fs_native(path.native())) { 0053 return module_::import("pathlib").attr("Path")(reinterpret_steal<object>(py_str)) 0054 .release(); 0055 } 0056 return nullptr; 0057 } 0058 0059 bool load(handle handle, bool) { 0060 // PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of 0061 // calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy 0062 // issue #3168) so we do it ourselves instead. 0063 PyObject* buf = PyOS_FSPath(handle.ptr()); 0064 if (!buf) { 0065 PyErr_Clear(); 0066 return false; 0067 } 0068 PyObject* native = nullptr; 0069 if constexpr (std::is_same_v<typename T::value_type, char>) { 0070 if (PyUnicode_FSConverter(buf, &native) != 0) { 0071 if (auto c_str = PyBytes_AsString(native)) { 0072 // AsString returns a pointer to the internal buffer, which 0073 // must not be free'd. 0074 value = c_str; 0075 } 0076 } 0077 } else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) { 0078 if (PyUnicode_FSDecoder(buf, &native) != 0) { 0079 if (auto c_str = PyUnicode_AsWideCharString(native, nullptr)) { 0080 // AsWideCharString returns a new string that must be free'd. 0081 value = c_str; // Copies the string. 0082 PyMem_Free(c_str); 0083 } 0084 } 0085 } 0086 Py_XDECREF(native); 0087 Py_DECREF(buf); 0088 if (PyErr_Occurred()) { 0089 PyErr_Clear(); 0090 return false; 0091 } 0092 return true; 0093 } 0094 0095 PYBIND11_TYPE_CASTER(T, const_name("os.PathLike")); 0096 }; 0097 0098 template<> struct type_caster<std::filesystem::path> 0099 : public path_caster<std::filesystem::path> {}; 0100 #endif // PYBIND11_HAS_FILESYSTEM 0101 0102 PYBIND11_NAMESPACE_END(detail) 0103 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)