Skip to content

Commit 7b8c8f4

Browse files
committed
Splitting out pybind11/stl/filesystem.h.
To solve breakages like: https://github.com/deepmind/open_spiel/runs/2999582108 Mostly following the suggestion here: pybind#2730 (comment) Except using pybind11/stl/filesystem.h instead of pybind11/stlfs.h, as decided via chat. stl.h restored to the exact state before merging PR pybind#2730 via: ``` git checkout 733f8de stl.h ```
1 parent 8bee61b commit 7b8c8f4

File tree

5 files changed

+96
-82
lines changed

5 files changed

+96
-82
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ set(PYBIND11_HEADERS
125125
include/pybind11/pybind11.h
126126
include/pybind11/pytypes.h
127127
include/pybind11/stl.h
128-
include/pybind11/stl_bind.h)
128+
include/pybind11/stl_bind.h
129+
include/pybind11/stl/filesystem.h)
129130

130131
# Compare with grep and warn if mismatched
131132
if(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12)

include/pybind11/stl.h

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,11 @@
4141
# include <variant>
4242
# define PYBIND11_HAS_VARIANT 1
4343
# endif
44-
// std::filesystem::path
45-
# if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \
46-
PY_VERSION_HEX >= 0x03060000
47-
# include <filesystem>
48-
# define PYBIND11_HAS_FILESYSTEM 1
49-
# endif
5044
#elif defined(_MSC_VER) && defined(PYBIND11_CPP17)
5145
# include <optional>
5246
# include <variant>
5347
# define PYBIND11_HAS_OPTIONAL 1
5448
# define PYBIND11_HAS_VARIANT 1
55-
# if PY_VERSION_HEX >= 0x03060000
56-
# include <filesystem>
57-
# define PYBIND11_HAS_FILESYSTEM 1
58-
# endif
5949
#endif
6050

6151
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
@@ -387,77 +377,6 @@ template <typename... Ts>
387377
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> { };
388378
#endif
389379

390-
#if defined(PYBIND11_HAS_FILESYSTEM)
391-
template<typename T> struct path_caster {
392-
393-
private:
394-
static PyObject* unicode_from_fs_native(const std::string& w) {
395-
#if !defined(PYPY_VERSION)
396-
return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size()));
397-
#else
398-
// PyPy mistakenly declares the first parameter as non-const.
399-
return PyUnicode_DecodeFSDefaultAndSize(
400-
const_cast<char*>(w.c_str()), ssize_t(w.size()));
401-
#endif
402-
}
403-
404-
static PyObject* unicode_from_fs_native(const std::wstring& w) {
405-
return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size()));
406-
}
407-
408-
public:
409-
static handle cast(const T& path, return_value_policy, handle) {
410-
if (auto py_str = unicode_from_fs_native(path.native())) {
411-
return module::import("pathlib").attr("Path")(reinterpret_steal<object>(py_str))
412-
.release();
413-
}
414-
return nullptr;
415-
}
416-
417-
bool load(handle handle, bool) {
418-
// PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of
419-
// calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy
420-
// issue #3168) so we do it ourselves instead.
421-
PyObject* buf = PyOS_FSPath(handle.ptr());
422-
if (!buf) {
423-
PyErr_Clear();
424-
return false;
425-
}
426-
PyObject* native = nullptr;
427-
if constexpr (std::is_same_v<typename T::value_type, char>) {
428-
if (PyUnicode_FSConverter(buf, &native)) {
429-
if (auto c_str = PyBytes_AsString(native)) {
430-
// AsString returns a pointer to the internal buffer, which
431-
// must not be free'd.
432-
value = c_str;
433-
}
434-
}
435-
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
436-
if (PyUnicode_FSDecoder(buf, &native)) {
437-
if (auto c_str = PyUnicode_AsWideCharString(native, nullptr)) {
438-
// AsWideCharString returns a new string that must be free'd.
439-
value = c_str; // Copies the string.
440-
PyMem_Free(c_str);
441-
}
442-
}
443-
}
444-
Py_XDECREF(native);
445-
Py_DECREF(buf);
446-
if (PyErr_Occurred()) {
447-
PyErr_Clear();
448-
return false;
449-
} else {
450-
return true;
451-
}
452-
}
453-
454-
PYBIND11_TYPE_CASTER(T, _("os.PathLike"));
455-
};
456-
457-
template<> struct type_caster<std::filesystem::path>
458-
: public path_caster<std::filesystem::path> {};
459-
#endif
460-
461380
PYBIND11_NAMESPACE_END(detail)
462381

463382
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {

include/pybind11/stl/filesystem.h

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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+
5+
#pragma once
6+
7+
#include "../detail/common.h"
8+
9+
#ifdef __has_include
10+
# if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \
11+
PY_VERSION_HEX >= 0x03060000
12+
# include <filesystem>
13+
# define PYBIND11_HAS_FILESYSTEM 1
14+
# endif
15+
#endif
16+
17+
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
18+
PYBIND11_NAMESPACE_BEGIN(detail)
19+
20+
#if defined(PYBIND11_HAS_FILESYSTEM)
21+
template<typename T> struct path_caster {
22+
23+
private:
24+
static PyObject* unicode_from_fs_native(const std::string& w) {
25+
#if !defined(PYPY_VERSION)
26+
return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size()));
27+
#else
28+
// PyPy mistakenly declares the first parameter as non-const.
29+
return PyUnicode_DecodeFSDefaultAndSize(
30+
const_cast<char*>(w.c_str()), ssize_t(w.size()));
31+
#endif
32+
}
33+
34+
static PyObject* unicode_from_fs_native(const std::wstring& w) {
35+
return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size()));
36+
}
37+
38+
public:
39+
static handle cast(const T& path, return_value_policy, handle) {
40+
if (auto py_str = unicode_from_fs_native(path.native())) {
41+
return module::import("pathlib").attr("Path")(reinterpret_steal<object>(py_str))
42+
.release();
43+
}
44+
return nullptr;
45+
}
46+
47+
bool load(handle handle, bool) {
48+
// PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of
49+
// calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy
50+
// issue #3168) so we do it ourselves instead.
51+
PyObject* buf = PyOS_FSPath(handle.ptr());
52+
if (!buf) {
53+
PyErr_Clear();
54+
return false;
55+
}
56+
PyObject* native = nullptr;
57+
if constexpr (std::is_same_v<typename T::value_type, char>) {
58+
if (PyUnicode_FSConverter(buf, &native)) {
59+
if (auto c_str = PyBytes_AsString(native)) {
60+
// AsString returns a pointer to the internal buffer, which
61+
// must not be free'd.
62+
value = c_str;
63+
}
64+
}
65+
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
66+
if (PyUnicode_FSDecoder(buf, &native)) {
67+
if (auto c_str = PyUnicode_AsWideCharString(native, nullptr)) {
68+
// AsWideCharString returns a new string that must be free'd.
69+
value = c_str; // Copies the string.
70+
PyMem_Free(c_str);
71+
}
72+
}
73+
}
74+
Py_XDECREF(native);
75+
Py_DECREF(buf);
76+
if (PyErr_Occurred()) {
77+
PyErr_Clear();
78+
return false;
79+
} else {
80+
return true;
81+
}
82+
}
83+
84+
PYBIND11_TYPE_CASTER(T, _("os.PathLike"));
85+
};
86+
87+
template<> struct type_caster<std::filesystem::path>
88+
: public path_caster<std::filesystem::path> {};
89+
#endif // PYBIND11_HAS_FILESYSTEM
90+
91+
PYBIND11_NAMESPACE_END(detail)
92+
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

tests/extra_python_package/test_files.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"include/pybind11/pytypes.h",
3535
"include/pybind11/stl.h",
3636
"include/pybind11/stl_bind.h",
37+
"include/pybind11/stl/filesystem.h",
3738
}
3839

3940
detail_headers = {

tests/test_stl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "pybind11_tests.h"
1111
#include "constructor_stats.h"
1212
#include <pybind11/stl.h>
13+
#include <pybind11/stl/filesystem.h>
1314

1415
#include <vector>
1516
#include <string>

0 commit comments

Comments
 (0)