amulet-pybind11-extensions 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- amulet/pybind11_extensions/__init__.py +3 -0
- amulet/pybind11_extensions/_version.py +21 -0
- amulet/pybind11_extensions/amulet_pybind11_extensionsConfig.cmake +8 -0
- amulet/pybind11_extensions/builtins.hpp +54 -0
- amulet/pybind11_extensions/collections.hpp +183 -0
- amulet/pybind11_extensions/compatibility.hpp +55 -0
- amulet/pybind11_extensions/contextlib.hpp +71 -0
- amulet/pybind11_extensions/hash.hpp +31 -0
- amulet/pybind11_extensions/iterator.hpp +37 -0
- amulet/pybind11_extensions/mapping.hpp +276 -0
- amulet/pybind11_extensions/mutable_mapping.hpp +244 -0
- amulet/pybind11_extensions/nogil_holder.hpp +36 -0
- amulet/pybind11_extensions/numpy.hpp +28 -0
- amulet/pybind11_extensions/py_module.hpp +37 -0
- amulet/pybind11_extensions/pybind11.hpp +16 -0
- amulet/pybind11_extensions/sequence.hpp +173 -0
- amulet/pybind11_extensions/types.hpp +15 -0
- amulet_pybind11_extensions-1.0.0.dist-info/METADATA +28 -0
- amulet_pybind11_extensions-1.0.0.dist-info/RECORD +22 -0
- amulet_pybind11_extensions-1.0.0.dist-info/WHEEL +5 -0
- amulet_pybind11_extensions-1.0.0.dist-info/licenses/LICENSE +21 -0
- amulet_pybind11_extensions-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
# This file was generated by 'versioneer.py' (0.29) from
|
|
3
|
+
# revision-control system data, or from the parent directory name of an
|
|
4
|
+
# unpacked source archive. Distribution tarballs contain a pre-generated copy
|
|
5
|
+
# of this file.
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
version_json = '''
|
|
10
|
+
{
|
|
11
|
+
"date": "2025-05-07T14:02:54+0100",
|
|
12
|
+
"dirty": false,
|
|
13
|
+
"error": null,
|
|
14
|
+
"full-revisionid": "2ce41a7d7c1118b04f1bf6035e2304b5dc8077b6",
|
|
15
|
+
"version": "1.0.0"
|
|
16
|
+
}
|
|
17
|
+
''' # END VERSION_JSON
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_versions():
|
|
21
|
+
return json.loads(version_json)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
if (NOT TARGET amulet_pybind11_extensions)
|
|
2
|
+
set(amulet_pybind11_extensions_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/../..")
|
|
3
|
+
|
|
4
|
+
add_library(amulet_pybind11_extensions IMPORTED INTERFACE)
|
|
5
|
+
set_target_properties(amulet_pybind11_extensions PROPERTIES
|
|
6
|
+
INTERFACE_INCLUDE_DIRECTORIES "${amulet_pybind11_extensions_INCLUDE_DIR}"
|
|
7
|
+
)
|
|
8
|
+
endif()
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <pybind11/pybind11.h>
|
|
3
|
+
#include <pybind11/detail/descr.h>
|
|
4
|
+
|
|
5
|
+
// Type hints for builtin types.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
namespace Amulet {
|
|
9
|
+
namespace pybind11_extensions {
|
|
10
|
+
// Type hint for a native python object.
|
|
11
|
+
namespace detail {
|
|
12
|
+
template<size_t N>
|
|
13
|
+
struct FixedString {
|
|
14
|
+
char buf[N + 1]{};
|
|
15
|
+
constexpr FixedString(char const* s) {
|
|
16
|
+
for (unsigned i = 0; i != N; ++i) buf[i] = s[i];
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
template<unsigned N>
|
|
20
|
+
FixedString(char const (&)[N])->FixedString<N - 1>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// A python object with a user defined string type hint for an arbitrary python object.
|
|
24
|
+
// This is useful if a C++ function needs to interact with a native python object.
|
|
25
|
+
template <detail::FixedString T>
|
|
26
|
+
class PyObjectStr : public pybind11::object {
|
|
27
|
+
PYBIND11_OBJECT_DEFAULT(PyObjectStr, object, PyObject_Type)
|
|
28
|
+
using object::object;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// A python object with a type hint from a C++ object.
|
|
32
|
+
// This is useful if you don't want to cast the python object to the C++ object and want to keep the type hint.
|
|
33
|
+
template <typename cppT>
|
|
34
|
+
class PyObjectCpp : public pybind11::object {
|
|
35
|
+
PYBIND11_OBJECT_DEFAULT(PyObjectCpp, object, PyObject_Type)
|
|
36
|
+
using object::object;
|
|
37
|
+
};
|
|
38
|
+
} // namespace pybind11_extensions
|
|
39
|
+
} // namespace Amulet
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
namespace pybind11 {
|
|
43
|
+
namespace detail {
|
|
44
|
+
template <Amulet::pybind11_extensions::detail::FixedString T>
|
|
45
|
+
struct handle_type_name<Amulet::pybind11_extensions::PyObjectStr<T>> {
|
|
46
|
+
static constexpr auto name = pybind11::detail::const_name(T.buf);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
template <typename cppT>
|
|
50
|
+
struct handle_type_name<Amulet::pybind11_extensions::PyObjectCpp<cppT>> {
|
|
51
|
+
static constexpr auto name = make_caster<cppT>::name;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <iterator>
|
|
3
|
+
#include <ranges>
|
|
4
|
+
|
|
5
|
+
#include <pybind11/pybind11.h>
|
|
6
|
+
|
|
7
|
+
// I have found cases where I want to accept or return a python object matching a collections.abc class.
|
|
8
|
+
// This extension adds subclasses of py::object with type hints for the collections.abc classes.
|
|
9
|
+
// This allows C++ functions to accept or return python objects that match the collection.abc classes.
|
|
10
|
+
// Note that these are handled in the same way as py::object thus there is no type validation.
|
|
11
|
+
|
|
12
|
+
namespace Amulet {
|
|
13
|
+
namespace pybind11_extensions {
|
|
14
|
+
namespace collections {
|
|
15
|
+
template <typename T>
|
|
16
|
+
class Iterator : public pybind11::object {
|
|
17
|
+
public:
|
|
18
|
+
PYBIND11_OBJECT_DEFAULT(Iterator, object, PyIter_Check)
|
|
19
|
+
|
|
20
|
+
using iterator_category = std::input_iterator_tag;
|
|
21
|
+
using difference_type = pybind11::ssize_t;
|
|
22
|
+
using value_type = T;
|
|
23
|
+
|
|
24
|
+
Iterator& operator++()
|
|
25
|
+
{
|
|
26
|
+
advance();
|
|
27
|
+
return *this;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
Iterator operator++(int)
|
|
31
|
+
{
|
|
32
|
+
auto rv = *this;
|
|
33
|
+
advance();
|
|
34
|
+
return rv;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
T operator*() const
|
|
38
|
+
{
|
|
39
|
+
return obj().template cast<T>();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
std::unique_ptr<T> operator->() const
|
|
43
|
+
{
|
|
44
|
+
return std::make_unique<T>(obj().template cast<T>());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static Iterator sentinel() { return {}; }
|
|
48
|
+
|
|
49
|
+
friend bool operator==(const Iterator& a, const Iterator& b) { return a.obj().ptr() == b.obj().ptr(); }
|
|
50
|
+
friend bool operator!=(const Iterator& a, const Iterator& b) { return a.obj().ptr() != b.obj().ptr(); }
|
|
51
|
+
|
|
52
|
+
private:
|
|
53
|
+
void advance()
|
|
54
|
+
{
|
|
55
|
+
value = pybind11::reinterpret_steal<pybind11::object>(PyIter_Next(m_ptr));
|
|
56
|
+
if (value.ptr() == nullptr && PyErr_Occurred()) {
|
|
57
|
+
throw pybind11::error_already_set();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const pybind11::object& obj() const
|
|
62
|
+
{
|
|
63
|
+
if (m_ptr && !value.ptr()) {
|
|
64
|
+
auto& self = const_cast<Iterator&>(*this);
|
|
65
|
+
self.advance();
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private:
|
|
71
|
+
pybind11::object value = {};
|
|
72
|
+
};
|
|
73
|
+
static_assert(std::input_iterator<Iterator<int>>);
|
|
74
|
+
|
|
75
|
+
template <typename T>
|
|
76
|
+
class Iterable : public pybind11::object {
|
|
77
|
+
PYBIND11_OBJECT_DEFAULT(Iterable, object, pybind11::detail::PyIterable_Check)
|
|
78
|
+
|
|
79
|
+
Iterator<T> begin() const
|
|
80
|
+
{
|
|
81
|
+
return Iterator<T>(pybind11::object::begin());
|
|
82
|
+
}
|
|
83
|
+
Iterator<T> end() const
|
|
84
|
+
{
|
|
85
|
+
return Iterator<T>(pybind11::object::end());
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
static_assert(std::ranges::input_range<Iterable<int>>);
|
|
89
|
+
static_assert(std::convertible_to<std::ranges::range_value_t<Iterable<int>>, const int&>);
|
|
90
|
+
|
|
91
|
+
template <typename T>
|
|
92
|
+
class Sequence : public pybind11::object {
|
|
93
|
+
PYBIND11_OBJECT_DEFAULT(Sequence, object, PySequence_Check)
|
|
94
|
+
|
|
95
|
+
Iterator<T> begin() const
|
|
96
|
+
{
|
|
97
|
+
return Iterator<T>(pybind11::object::begin());
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
Iterator<T> end() const
|
|
101
|
+
{
|
|
102
|
+
return Iterator<T>(pybind11::object::end());
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
Py_ssize_t size() const
|
|
106
|
+
{
|
|
107
|
+
return PyObject_Size(ptr());
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
template <typename K, typename V>
|
|
112
|
+
class Mapping : public pybind11::object {
|
|
113
|
+
PYBIND11_OBJECT_DEFAULT(Mapping, object, PyMapping_Check)
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
template <typename K, typename V>
|
|
117
|
+
class MutableMapping : public pybind11::object {
|
|
118
|
+
PYBIND11_OBJECT_DEFAULT(MutableMapping, object, PyMapping_Check)
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
template <typename K>
|
|
122
|
+
class KeysView : public pybind11::object {
|
|
123
|
+
PYBIND11_OBJECT_DEFAULT(KeysView, object, PyObject_Type)
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
template <typename V>
|
|
127
|
+
class ValuesView : public pybind11::object {
|
|
128
|
+
PYBIND11_OBJECT_DEFAULT(ValuesView, object, PyObject_Type)
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
template <typename K, typename V>
|
|
132
|
+
class ItemsView : public pybind11::object {
|
|
133
|
+
PYBIND11_OBJECT_DEFAULT(ItemsView, object, PyObject_Type)
|
|
134
|
+
};
|
|
135
|
+
} // namespace collections
|
|
136
|
+
} // namespace pybind11_extensions
|
|
137
|
+
} // namespace Amulet
|
|
138
|
+
|
|
139
|
+
namespace pybind11 {
|
|
140
|
+
namespace detail {
|
|
141
|
+
template <typename T>
|
|
142
|
+
struct handle_type_name<Amulet::pybind11_extensions::collections::Iterator<T>> {
|
|
143
|
+
static constexpr auto name = const_name("collections.abc.Iterator[") + make_caster<T>::name + const_name("]");
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
template <typename T>
|
|
147
|
+
struct handle_type_name<Amulet::pybind11_extensions::collections::Iterable<T>> {
|
|
148
|
+
static constexpr auto name = const_name("collections.abc.Iterable[") + make_caster<T>::name + const_name("]");
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
template <typename T>
|
|
152
|
+
struct handle_type_name<Amulet::pybind11_extensions::collections::Sequence<T>> {
|
|
153
|
+
static constexpr auto name = const_name("collections.abc.Sequence[") + make_caster<T>::name + const_name("]");
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
template <typename K, typename V>
|
|
157
|
+
struct handle_type_name<Amulet::pybind11_extensions::collections::Mapping<K, V>> {
|
|
158
|
+
static constexpr auto name = const_name("collections.abc.Mapping[") + make_caster<K>::name + const_name(", ") + make_caster<V>::name + const_name("]");
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
template <typename K, typename V>
|
|
162
|
+
struct handle_type_name<Amulet::pybind11_extensions::collections::MutableMapping<K, V>> {
|
|
163
|
+
static constexpr auto name = const_name("collections.abc.MutableMapping[") + make_caster<K>::name + const_name(", ")
|
|
164
|
+
+ make_caster<V>::name + const_name("]");
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
template <typename K>
|
|
168
|
+
struct handle_type_name<Amulet::pybind11_extensions::collections::KeysView<K>> {
|
|
169
|
+
static constexpr auto name = const_name("collections.abc.KeysView[") + make_caster<K>::name + const_name("]");
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
template <typename V>
|
|
173
|
+
struct handle_type_name<Amulet::pybind11_extensions::collections::ValuesView<V>> {
|
|
174
|
+
static constexpr auto name = const_name("collections.abc.ValuesView[") + make_caster<V>::name + const_name("]");
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
template <typename K, typename V>
|
|
178
|
+
struct handle_type_name<Amulet::pybind11_extensions::collections::ItemsView<K, V>> {
|
|
179
|
+
static constexpr auto name = const_name("collections.abc.ItemsView[") + make_caster<K>::name + const_name(", ")
|
|
180
|
+
+ make_caster<V>::name + const_name("]");
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <filesystem>
|
|
4
|
+
#include <string>
|
|
5
|
+
|
|
6
|
+
#include <pybind11/pybind11.h>
|
|
7
|
+
|
|
8
|
+
static std::string get_version_top(std::string version)
|
|
9
|
+
{
|
|
10
|
+
return version.substr(0, version.find('.', version.find('.') + 1));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
namespace Amulet {
|
|
14
|
+
namespace pybind11_extensions {
|
|
15
|
+
|
|
16
|
+
inline void init_compiler_config(pybind11::module m)
|
|
17
|
+
{
|
|
18
|
+
pybind11::dict compiler_config;
|
|
19
|
+
compiler_config["pybind11_version"] = PYBIND11_VERSION;
|
|
20
|
+
compiler_config["compiler_id"] = COMPILER_ID;
|
|
21
|
+
compiler_config["compiler_version"] = COMPILER_VERSION;
|
|
22
|
+
m.attr("compiler_config") = compiler_config;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
inline void check_compatibility(pybind11::module a, pybind11::module b)
|
|
26
|
+
{
|
|
27
|
+
std::string a_name = a.attr("__name__").cast<std::string>();
|
|
28
|
+
std::string b_name = b.attr("__name__").cast<std::string>();
|
|
29
|
+
pybind11::dict a_config = a.attr("compiler_config");
|
|
30
|
+
pybind11::dict b_config = b.attr("compiler_config");
|
|
31
|
+
|
|
32
|
+
std::string a_pybind11_version = a_config["pybind11_version"].cast<std::string>();
|
|
33
|
+
std::string b_pybind11_version = b_config["pybind11_version"].cast<std::string>();
|
|
34
|
+
if (a_pybind11_version != b_pybind11_version) {
|
|
35
|
+
throw std::runtime_error(
|
|
36
|
+
"pybind11 version mismatch. " + a_name + " is compiled for pybind11==" + a_pybind11_version + " and " + b_name + " is compiled for pybind11==" + b_pybind11_version);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
std::string a_compiler_id = a_config["compiler_id"].cast<std::string>();
|
|
40
|
+
std::string b_compiler_id = b_config["compiler_id"].cast<std::string>();
|
|
41
|
+
if (a_compiler_id != b_compiler_id) {
|
|
42
|
+
throw std::runtime_error(
|
|
43
|
+
"compiler mismatch. " + a_name + " is compiled by " + a_compiler_id + " and " + b_name + " is compiled by " + b_compiler_id);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
std::string a_compiler_version = a_config["compiler_version"].cast<std::string>();
|
|
47
|
+
std::string b_compiler_version = b_config["compiler_version"].cast<std::string>();
|
|
48
|
+
if (get_version_top(a_compiler_version) != get_version_top(b_compiler_version)) {
|
|
49
|
+
throw std::runtime_error(
|
|
50
|
+
"compiler version mismatch. " + a_name + " is compiled by " + a_compiler_id + " " + a_compiler_version + " and " + b_name + " is compiled by " + b_compiler_id + " " + b_compiler_version);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
} // namespace pybind11_extensions
|
|
55
|
+
} // namespace Amulet
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <pybind11/pybind11.h>
|
|
4
|
+
#include <pybind11/stl.h>
|
|
5
|
+
|
|
6
|
+
#include <functional>
|
|
7
|
+
#include <optional>
|
|
8
|
+
#include <type_traits>
|
|
9
|
+
|
|
10
|
+
#include <amulet/pybind11_extensions/pybind11.hpp>
|
|
11
|
+
|
|
12
|
+
namespace Amulet {
|
|
13
|
+
namespace pybind11_extensions {
|
|
14
|
+
namespace contextlib {
|
|
15
|
+
template <typename T, typename ExitT = std::optional<bool>>
|
|
16
|
+
class ContextManager : public pybind11::object {
|
|
17
|
+
PYBIND11_OBJECT_DEFAULT(ContextManager, object, PyObject_Type)
|
|
18
|
+
using object::object;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
namespace detail {
|
|
22
|
+
template <typename T, typename ExitT = std::optional<bool>>
|
|
23
|
+
class ContextManager {
|
|
24
|
+
public:
|
|
25
|
+
std::function<T()> enter;
|
|
26
|
+
std::function<ExitT(pybind11::object, pybind11::object, pybind11::object)> exit;
|
|
27
|
+
ContextManager(
|
|
28
|
+
std::function<T()> enter,
|
|
29
|
+
std::function<ExitT(pybind11::object, pybind11::object, pybind11::object)> exit)
|
|
30
|
+
: enter(enter)
|
|
31
|
+
, exit(exit)
|
|
32
|
+
{
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
template <typename T, typename ExitT = std::optional<bool>>
|
|
38
|
+
auto make_context_manager(
|
|
39
|
+
std::function<T()> enter,
|
|
40
|
+
std::function<ExitT(pybind11::object, pybind11::object, pybind11::object)> exit) -> ContextManager<T, ExitT>
|
|
41
|
+
{
|
|
42
|
+
using ContextManagerT = detail::ContextManager<T, ExitT>;
|
|
43
|
+
if (!pybind11_extensions::is_class_bound<ContextManagerT>()) {
|
|
44
|
+
pybind11::class_<ContextManagerT>(pybind11::handle(), "ContextManager", pybind11::module_local())
|
|
45
|
+
.def(
|
|
46
|
+
"__enter__",
|
|
47
|
+
[](const ContextManagerT& self) -> T {
|
|
48
|
+
return self.enter();
|
|
49
|
+
})
|
|
50
|
+
.def(
|
|
51
|
+
"__exit__",
|
|
52
|
+
[](const ContextManagerT& self, pybind11::object exc_type, pybind11::object exc_val, pybind11::object exc_tb) -> ExitT {
|
|
53
|
+
return self.exit(exc_type, exc_val, exc_tb);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return pybind11::cast(ContextManagerT(enter, exit));
|
|
57
|
+
}
|
|
58
|
+
} // namespace contextlib
|
|
59
|
+
} // namespace pybind11_extensions
|
|
60
|
+
} // namespace Amulet
|
|
61
|
+
|
|
62
|
+
namespace pybind11 {
|
|
63
|
+
namespace detail {
|
|
64
|
+
template <typename T, typename ExitT>
|
|
65
|
+
struct handle_type_name<Amulet::pybind11_extensions::contextlib::ContextManager<T, ExitT>> {
|
|
66
|
+
static constexpr auto name = const_name("contextlib.AbstractContextManager[")
|
|
67
|
+
+ make_caster<std::conditional_t<std::is_same_v<void, T>, pybind11::none, T>>::name
|
|
68
|
+
+ const_name(", ") + make_caster<ExitT>::name + const_name("]");
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <pybind11/pybind11.h>
|
|
4
|
+
|
|
5
|
+
namespace Amulet {
|
|
6
|
+
namespace pybind11_extensions {
|
|
7
|
+
|
|
8
|
+
template <typename clsT>
|
|
9
|
+
void def_hash_identity(clsT cls)
|
|
10
|
+
{
|
|
11
|
+
auto PyId = pybind11::module::import("builtins").attr("id");
|
|
12
|
+
cls.def(
|
|
13
|
+
"__hash__",
|
|
14
|
+
[PyId](pybind11::object self) -> pybind11::int_ {
|
|
15
|
+
return PyId(self);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
template <typename clsT>
|
|
20
|
+
void def_unhashable(clsT cls)
|
|
21
|
+
{
|
|
22
|
+
auto cls_name = cls.attr("__name__").template cast<std::string>();
|
|
23
|
+
cls.def(
|
|
24
|
+
"__hash__",
|
|
25
|
+
[cls_name](pybind11::object self) -> size_t {
|
|
26
|
+
throw pybind11::type_error("unhashable type: '" + cls_name + "'");
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
} // namespace pybind11_extensions
|
|
31
|
+
} // namespace Amulet
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <pybind11/pybind11.h>
|
|
3
|
+
|
|
4
|
+
#include <amulet/pybind11_extensions/pybind11.hpp>
|
|
5
|
+
#include <amulet/pybind11_extensions/builtins.hpp>
|
|
6
|
+
#include <amulet/pybind11_extensions/collections.hpp>
|
|
7
|
+
|
|
8
|
+
namespace Amulet {
|
|
9
|
+
namespace pybind11_extensions {
|
|
10
|
+
|
|
11
|
+
// Create a python iterator around a C++ class that implements method next()
|
|
12
|
+
// Next must throw py::stop_iteration() to signal the end of the iterator.
|
|
13
|
+
template <
|
|
14
|
+
pybind11::return_value_policy Policy = pybind11::return_value_policy::automatic,
|
|
15
|
+
typename Iterator,
|
|
16
|
+
typename... Extra>
|
|
17
|
+
auto make_iterator(Iterator it, Extra&&... extra) -> pybind11_extensions::collections::Iterator<decltype(it.next())>
|
|
18
|
+
{
|
|
19
|
+
if (!is_class_bound<Iterator>()) {
|
|
20
|
+
pybind11::class_<Iterator>(pybind11::handle(), "iterator", pybind11::module_local())
|
|
21
|
+
.def(
|
|
22
|
+
"__iter__",
|
|
23
|
+
[](
|
|
24
|
+
pybind11_extensions::PyObjectCpp<Iterator>& self) -> pybind11_extensions::PyObjectCpp<Iterator>& { return self; })
|
|
25
|
+
.def(
|
|
26
|
+
"__next__",
|
|
27
|
+
[](Iterator& self) -> decltype(it.next()) {
|
|
28
|
+
return self.next();
|
|
29
|
+
},
|
|
30
|
+
std::forward<Extra>(extra)...,
|
|
31
|
+
Policy);
|
|
32
|
+
}
|
|
33
|
+
return pybind11::cast(std::forward<Iterator>(it));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
} // namespace pybind11_extensions
|
|
37
|
+
} // namespace Amulet
|