filesystem.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // Copyright (c) 2021 The Pybind Development Team.
  2. // All rights reserved. Use of this source code is governed by a
  3. // BSD-style license that can be found in the LICENSE file.
  4. #pragma once
  5. #include <pybind11/cast.h>
  6. #include <pybind11/detail/common.h>
  7. #include <pybind11/detail/descr.h>
  8. #include <pybind11/pybind11.h>
  9. #include <pybind11/pytypes.h>
  10. #include <string>
  11. #if defined(PYBIND11_HAS_FILESYSTEM)
  12. # include <filesystem>
  13. #elif defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
  14. # include <experimental/filesystem>
  15. #else
  16. # error "Neither #include <filesystem> nor #include <experimental/filesystem is available."
  17. #endif
  18. PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
  19. PYBIND11_NAMESPACE_BEGIN(detail)
  20. #ifdef PYPY_VERSION
  21. # define PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(...) (__VA_ARGS__)
  22. #else
  23. # define PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(...) \
  24. (reinterpret_cast<void *>(__VA_ARGS__))
  25. #endif
  26. #if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
  27. template <typename T>
  28. struct path_caster {
  29. private:
  30. static PyObject *unicode_from_fs_native(const std::string &w) {
  31. # if !defined(PYPY_VERSION)
  32. return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size()));
  33. # else
  34. // PyPy mistakenly declares the first parameter as non-const.
  35. return PyUnicode_DecodeFSDefaultAndSize(const_cast<char *>(w.c_str()), ssize_t(w.size()));
  36. # endif
  37. }
  38. static PyObject *unicode_from_fs_native(const std::wstring &w) {
  39. return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size()));
  40. }
  41. public:
  42. static handle cast(const T &path, return_value_policy, handle) {
  43. if (auto py_str = unicode_from_fs_native(path.native())) {
  44. return module_::import("pathlib")
  45. .attr("Path")(reinterpret_steal<object>(py_str))
  46. .release();
  47. }
  48. return nullptr;
  49. }
  50. bool load(handle handle, bool) {
  51. // PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of
  52. // calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy
  53. // issue #3168) so we do it ourselves instead.
  54. PyObject *buf = PyOS_FSPath(handle.ptr());
  55. if (!buf) {
  56. PyErr_Clear();
  57. return false;
  58. }
  59. PyObject *native = nullptr;
  60. if constexpr (std::is_same_v<typename T::value_type, char>) {
  61. if (PyUnicode_FSConverter(buf, PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(&native))
  62. != 0) {
  63. if (auto *c_str = PyBytes_AsString(native)) {
  64. // AsString returns a pointer to the internal buffer, which
  65. // must not be free'd.
  66. value = c_str;
  67. }
  68. }
  69. } else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
  70. if (PyUnicode_FSDecoder(buf, PYBIND11_REINTERPRET_CAST_VOID_PTR_IF_NOT_PYPY(&native))
  71. != 0) {
  72. if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) {
  73. // AsWideCharString returns a new string that must be free'd.
  74. value = c_str; // Copies the string.
  75. PyMem_Free(c_str);
  76. }
  77. }
  78. }
  79. Py_XDECREF(native);
  80. Py_DECREF(buf);
  81. if (PyErr_Occurred()) {
  82. PyErr_Clear();
  83. return false;
  84. }
  85. return true;
  86. }
  87. PYBIND11_TYPE_CASTER(T, io_name("os.PathLike | str | bytes", "pathlib.Path"));
  88. };
  89. #endif // PYBIND11_HAS_FILESYSTEM || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
  90. #if defined(PYBIND11_HAS_FILESYSTEM)
  91. template <>
  92. struct type_caster<std::filesystem::path> : public path_caster<std::filesystem::path> {};
  93. #elif defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
  94. template <>
  95. struct type_caster<std::experimental::filesystem::path>
  96. : public path_caster<std::experimental::filesystem::path> {};
  97. #endif
  98. PYBIND11_NAMESPACE_END(detail)
  99. PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)