filesystem.h 4.2 KB

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