Skip to content

Commit 55c1c91

Browse files
committed
Don't return ndarray with empty shape through named indexers.
NumPy arrays with an empty shape cannot be assigned via the usual syntax. Fixes: #238. Related: #237. PiperOrigin-RevId: 441265437 Change-Id: Ib0de22c83f9babe9a97682dc5a32660c198ad68c
1 parent 0d5d1f5 commit 55c1c91

File tree

2 files changed

+25
-1
lines changed

2 files changed

+25
-1
lines changed

python/mujoco/bindings_test.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
<body>
4242
<inertial pos="0 0 0" mass="1" diaginertia="1 1 1"/>
4343
<site pos="0 0 -1" name="mysite" type="sphere"/>
44-
<joint type="hinge" axis="0 1 0"/>
44+
<joint name="myhinge" type="hinge" axis="0 1 0"/>
4545
</body>
4646
<body>
4747
<inertial pos="0 0 0" mass="1" diaginertia="1 1 1"/>
@@ -51,6 +51,9 @@
5151
<geom type="sphere" size="0.1"/>
5252
</body>
5353
</worldbody>
54+
<actuator>
55+
<position name="myactuator" joint="myhinge"/>
56+
</actuator>
5457
</mujoco>
5558
"""
5659

@@ -144,6 +147,22 @@ def test_array_keeps_struct_alive(self):
144147
del qpos_spring
145148
self.assertEqual(sys.getrefcount(capsule) - base_refcount, 1)
146149

150+
def test_named_indexing_actuator_ctrl(self):
151+
actuator_id = mujoco.mj_name2id(
152+
self.model, mujoco.mjtObj.mjOBJ_ACTUATOR, 'myactuator')
153+
self.assertIs(self.data.actuator('myactuator'),
154+
self.data.actuator(actuator_id))
155+
self.assertIs(self.data.actuator('myactuator').ctrl,
156+
self.data.actuator(actuator_id).ctrl)
157+
self.assertEqual(self.data.actuator('myactuator').ctrl.shape, (1,))
158+
159+
# Test that the indexer is returning a view into the underlying struct.
160+
ctrl_from_indexer = self.data.actuator('myactuator').ctrl
161+
self.data.ctrl[actuator_id] = 5
162+
np.testing.assert_array_equal(ctrl_from_indexer, [5])
163+
self.data.actuator('myactuator').ctrl = 7
164+
np.testing.assert_array_equal(self.data.ctrl[actuator_id], [7])
165+
147166
def test_named_indexing_geom_size(self):
148167
box_id = mujoco.mj_name2id(self.model, mujoco.mjtObj.mjOBJ_GEOM, 'mybox')
149168
self.assertIs(self.model.geom('mybox'), self.model.geom(box_id))

python/mujoco/indexers.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ py::array_t<T> MakeArray(T* base_ptr, int index, std::vector<int>&& shape,
102102
offset = m.tuple_adr[index];
103103
shape.insert(shape.begin(), m.tuple_size[index]);
104104
} else {
105+
// Do not return a NumPy array with shape () since these aren't very nice
106+
// to work with. Instead, always return singleton arrays with shape (1,).
107+
if (shape.empty()) {
108+
shape.push_back(1);
109+
}
105110
int size = 1;
106111
for (int s : shape) {
107112
size *= s;

0 commit comments

Comments
 (0)