Skip to content
This repository was archived by the owner on Nov 1, 2023. It is now read-only.

Commit 867c648

Browse files
authored
Merge pull request #40 from robotpy/fix-sendable
Sendable::InitSendable: force builder to be a reference
2 parents 7022310 + 1facfdb commit 867c648

File tree

6 files changed

+184
-1
lines changed

6 files changed

+184
-1
lines changed

gen/Sendable.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,8 @@ classes:
88
shared_ptr: true
99
methods:
1010
InitSendable:
11+
virtual_xform: |
12+
[&](py::function fn) {
13+
auto builderHandle = py::cast(builder, py::return_value_policy::reference);
14+
fn(builderHandle);
15+
}

tests/cpp/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ extension = "module"
1010
depends = ["wpiutil"]
1111
sources = [
1212
"wpiutil_test/module.cpp",
13+
"wpiutil_test/sendable_test.cpp",
1314
]
1415

1516
[tool.robotpy-build.metadata]

tests/cpp/wpiutil_test/module.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,13 @@ wpi::json cast_json_val(std::function<wpi::json()> fn) {
144144
return fn();
145145
}
146146

147+
void sendable_test(py::module &m);
148+
147149

148150
RPYBUILD_PYBIND11_MODULE(m) {
149151

152+
sendable_test(m);
153+
150154
// array
151155
m.def("load_array_int", &load_array_int);
152156
m.def("load_array_int1", &load_array_int1);
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
2+
#include <robotpy_build.h>
3+
#include <pybind11/stl.h>
4+
#include <pybind11/functional.h>
5+
#include <wpi/sendable/SendableBuilder.h>
6+
#include <wpi/sendable/SendableRegistry.h>
7+
8+
class MySendableBuilder : public wpi::SendableBuilder {
9+
public:
10+
MySendableBuilder(py::dict keys) : keys(keys) {}
11+
12+
~MySendableBuilder() {
13+
// leak this so the python interpreter doesn't crash on shutdown
14+
keys.release();
15+
}
16+
17+
void SetSmartDashboardType(std::string_view type) override {}
18+
19+
void SetActuator(bool value) override {}
20+
21+
void SetSafeState(std::function<void()> func) override {}
22+
23+
void AddBooleanProperty(std::string_view key, std::function<bool()> getter,
24+
std::function<void(bool)> setter) override {}
25+
26+
void AddIntegerProperty(std::string_view key, std::function<int64_t()> getter,
27+
std::function<void(int64_t)> setter) override {}
28+
29+
void AddFloatProperty(std::string_view key, std::function<float()> getter,
30+
std::function<void(float)> setter) override {}
31+
32+
void AddDoubleProperty(std::string_view key, std::function<double()> getter,
33+
std::function<void(double)> setter) override {
34+
py::gil_scoped_acquire gil;
35+
py::object pykey = py::cast(key);
36+
keys[pykey] = std::make_tuple(getter, setter);
37+
}
38+
39+
void
40+
AddStringProperty(std::string_view key, std::function<std::string()> getter,
41+
std::function<void(std::string_view)> setter) override {}
42+
43+
void AddBooleanArrayProperty(
44+
std::string_view key, std::function<std::vector<int>()> getter,
45+
std::function<void(std::span<const int>)> setter) override {}
46+
47+
void AddIntegerArrayProperty(
48+
std::string_view key, std::function<std::vector<int64_t>()> getter,
49+
std::function<void(std::span<const int64_t>)> setter) override {}
50+
51+
void AddFloatArrayProperty(
52+
std::string_view key, std::function<std::vector<float>()> getter,
53+
std::function<void(std::span<const float>)> setter) override {}
54+
55+
void AddDoubleArrayProperty(
56+
std::string_view key, std::function<std::vector<double>()> getter,
57+
std::function<void(std::span<const double>)> setter) override {}
58+
59+
void AddStringArrayProperty(
60+
std::string_view key, std::function<std::vector<std::string>()> getter,
61+
std::function<void(std::span<const std::string>)> setter) override {}
62+
63+
void AddRawProperty(
64+
std::string_view key, std::string_view typeString,
65+
std::function<std::vector<uint8_t>()> getter,
66+
std::function<void(std::span<const uint8_t>)> setter) override {}
67+
68+
void AddSmallStringProperty(
69+
std::string_view key,
70+
std::function<std::string_view(wpi::SmallVectorImpl<char> &buf)> getter,
71+
std::function<void(std::string_view)> setter) override {}
72+
73+
void AddSmallBooleanArrayProperty(
74+
std::string_view key,
75+
std::function<std::span<const int>(wpi::SmallVectorImpl<int> &buf)>
76+
getter,
77+
std::function<void(std::span<const int>)> setter) override {}
78+
79+
void AddSmallIntegerArrayProperty(
80+
std::string_view key,
81+
std::function<
82+
std::span<const int64_t>(wpi::SmallVectorImpl<int64_t> &buf)>
83+
getter,
84+
std::function<void(std::span<const int64_t>)> setter) override {}
85+
86+
void AddSmallFloatArrayProperty(
87+
std::string_view key,
88+
std::function<std::span<const float>(wpi::SmallVectorImpl<float> &buf)>
89+
getter,
90+
std::function<void(std::span<const float>)> setter) override {}
91+
92+
void AddSmallDoubleArrayProperty(
93+
std::string_view key,
94+
std::function<std::span<const double>(wpi::SmallVectorImpl<double> &buf)>
95+
getter,
96+
std::function<void(std::span<const double>)> setter) override {}
97+
98+
void AddSmallStringArrayProperty(
99+
std::string_view key,
100+
std::function<
101+
std::span<const std::string>(wpi::SmallVectorImpl<std::string> &buf)>
102+
getter,
103+
std::function<void(std::span<const std::string>)> setter) override {}
104+
105+
void AddSmallRawProperty(
106+
std::string_view key, std::string_view typeString,
107+
std::function<std::span<uint8_t>(wpi::SmallVectorImpl<uint8_t> &buf)>
108+
getter,
109+
std::function<void(std::span<const uint8_t>)> setter) override {}
110+
111+
wpi::SendableBuilder::BackendKind GetBackendKind() const override {
112+
return wpi::SendableBuilder::BackendKind::kUnknown;
113+
}
114+
115+
bool IsPublished() const override { return false; }
116+
void Update() override {}
117+
void ClearProperties() override {}
118+
119+
py::dict keys;
120+
};
121+
122+
void Publish(wpi::SendableRegistry::UID sendableUid, py::dict keys) {
123+
auto builder = std::make_unique<MySendableBuilder>(keys);
124+
wpi::SendableRegistry::Publish(sendableUid, std::move(builder));
125+
}
126+
127+
void sendable_test(py::module &m) { m.def("publish", Publish); }

tests/test_sendable.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import typing
2+
import wpiutil
3+
from wpiutil_test import module
4+
5+
6+
class MySendable(wpiutil.Sendable):
7+
def __init__(self):
8+
super().__init__()
9+
wpiutil.SendableRegistry.add(self, "Test", 1)
10+
self.value = 0
11+
12+
def initSendable(self, builder: wpiutil.SendableBuilder):
13+
builder.addDoubleProperty("key", self._get, self._set)
14+
15+
def _set(self, value: float):
16+
self.value = value
17+
18+
def _get(self) -> float:
19+
return self.value
20+
21+
22+
def test_custom_sendable():
23+
ms = MySendable()
24+
25+
uid = wpiutil.SendableRegistry.getUniqueId(ms)
26+
keys = {}
27+
28+
module.publish(uid, keys)
29+
assert ms.value == 0
30+
31+
getter, setter = keys["key"]
32+
assert getter() == 0
33+
setter(1)
34+
assert getter() == 1
35+
assert ms.value == 1

wpiutil/src/main.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,22 @@
44
void setup_stack_trace_hook(py::object fn);
55
void cleanup_stack_trace_hook();
66

7+
namespace wpi::impl {
8+
void ResetSendableRegistry();
9+
} // namespace wpi::impl
10+
711
RPYBUILD_PYBIND11_MODULE(m) {
812
initWrapper(m);
913

1014
static int unused;
11-
py::capsule cleanup(&unused, [](void *) { cleanup_stack_trace_hook(); });
15+
py::capsule cleanup(&unused, [](void *) {
16+
{
17+
py::gil_scoped_release unlock;
18+
wpi::impl::ResetSendableRegistry();
19+
}
20+
21+
cleanup_stack_trace_hook();
22+
});
1223

1324
m.def("_setup_stack_trace_hook", &setup_stack_trace_hook);
1425
m.add_object("_st_cleanup", cleanup);

0 commit comments

Comments
 (0)