Skip to content

Commit aff976d

Browse files
committed
Remove compilation warning with InstanceHandle_t (#262)
* Refs #23753. Take into account dependencies for rebuild Signed-off-by: Ricardo González Moreno <ricardo@richiware.dev> * Refs #23753. Fix warning Signed-off-by: Ricardo González Moreno <ricardo@richiware.dev> * Refs #23753. Remove swig warnings Signed-off-by: Ricardo González Moreno <ricardo@richiware.dev> * Refs #23753. Add unit tests Signed-off-by: Ricardo González Moreno <ricardo@richiware.dev> * Refs #23753. Apply suggestions Signed-off-by: Ricardo González Moreno <ricardo@richiware.dev> --------- Signed-off-by: Ricardo González Moreno <ricardo@richiware.dev> (cherry picked from commit 6ee4ca5)
1 parent 3685455 commit aff976d

File tree

4 files changed

+301
-40
lines changed

4 files changed

+301
-40
lines changed

fastdds_python/src/swig/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ set(${PROJECT_NAME}_MODULE
2727
set(${PROJECT_NAME}_FILES
2828
${${PROJECT_NAME}_MODULE}.i
2929
)
30+
set_property(SOURCE ${${PROJECT_NAME}_FILE} PROPERTY USE_SWIG_DEPENDENCIES TRUE)
3031

3132
SET_SOURCE_FILES_PROPERTIES(
3233
${${PROJECT_NAME}_FILES}

fastdds_python/src/swig/fastdds/rtps/common/InstanceHandle.i

Lines changed: 149 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
// limitations under the License.
1414

1515
%{
16+
#include <stdexcept>
17+
#include <vector>
18+
1619
#include "fastdds/rtps/common/InstanceHandle.h"
1720

1821
// Define a hash method in global scope for InstanceHandle_t types
@@ -26,60 +29,119 @@ long hash(const eprosima::fastrtps::rtps::InstanceHandle_t& handle)
2629
}
2730
return ret;
2831
}
29-
3032
%}
3133

3234
// SWIG does not support type conversion operators correctly unless converted to a normal method
3335
%rename(get_guid) eprosima::fastrtps::rtps::InstanceHandle_t::operator const GUID_t&;
3436

35-
%ignore eprosima::fastrtps::rtps::InstanceHandleValue_t::operator [] const;
36-
%ignore eprosima::fastrtps::rtps::operator <<(std::ostream&, const InstanceHandle_t&);
37-
%ignore eprosima::fastrtps::rtps::operator >>(std::istream&, InstanceHandle_t&);
38-
%rename(read_pointer_cast) eprosima::fastrtps::rtps::InstanceHandleValue_t::operator const octet* () const;
39-
%rename(write_pointer_cast) eprosima::fastrtps::rtps::InstanceHandleValue_t::operator octet* ();
40-
41-
%typemap(in) eprosima::fastrtps::rtps::InstanceHandleValue_t*(eprosima::fastrtps::rtps::InstanceHandleValue_t temp)
42-
{
43-
if (PyTuple_Check($input))
44-
{
45-
eprosima::fastrtps::rtps::octet* buf = temp;
46-
if (!PyArg_ParseTuple($input, "BBBBBBBBBBBBBBBB",
47-
buf, buf+1, buf+2, buf+3, buf+4, buf+5, buf+6, buf+7, buf+8,
48-
buf+9, buf+10, buf+11, buf+12, buf+13, buf+14, buf+15))
37+
%ignore eprosima::fastdds::rtps::InstanceHandleValue_t::operator [] const;
38+
%ignore eprosima::fastdds::rtps::InstanceHandleValue_t::operator [];
39+
%ignore eprosima::fastdds::rtps::operator <<(std::ostream&, const InstanceHandle_t&);
40+
%ignore eprosima::fastdds::rtps::operator >>(std::istream&, InstanceHandle_t&);
41+
%ignore eprosima::fastdds::rtps::InstanceHandleValue_t::operator const octet* () const;
42+
%ignore eprosima::fastdds::rtps::InstanceHandleValue_t::operator octet* ();
43+
44+
%extend eprosima::fastdds::rtps::InstanceHandleValue_t {
45+
46+
// Constructor from a sequence of 16 bytes (tuple/list/bytes/bytearray)
47+
InstanceHandleValue_t(PyObject* seq) {
48+
eprosima::fastdds::rtps::InstanceHandleValue_t* self = new eprosima::fastdds::rtps::InstanceHandleValue_t();
49+
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
50+
51+
// Fast-path: bytes
52+
if (PyBytes_Check(seq)) {
53+
if (PyBytes_GET_SIZE(seq) == 16)
54+
{
55+
const char* b = PyBytes_AS_STRING(seq);
56+
for (int i = 0; i < 16; ++i) (*self)[i] = (uint8_t)(unsigned char)b[i];
57+
}
58+
else
59+
{
60+
delete self;
61+
self = nullptr;
62+
PyErr_SetString(PyExc_ValueError, "Expected 16 bytes");
63+
}
64+
}
65+
// Fast-path: bytearray
66+
else if (PyByteArray_Check(seq))
4967
{
50-
PyErr_SetString(PyExc_TypeError, "tuple must have 16 elements");
51-
SWIG_fail;
68+
if (PyByteArray_GET_SIZE(seq) == 16)
69+
{
70+
const char* b = PyByteArray_AS_STRING(seq);
71+
for (int i = 0; i < 16; ++i) (*self)[i] = (uint8_t)(unsigned char)b[i];
72+
}
73+
else
74+
{
75+
delete self;
76+
self = nullptr;
77+
PyErr_SetString(PyExc_ValueError, "Expected 16 bytes");
78+
}
5279
}
53-
$1 = &temp;
54-
}
55-
else
56-
{
57-
PyErr_SetString(PyExc_TypeError, "expected a tuple.");
58-
SWIG_fail;
80+
else
81+
{
82+
// Generic fallback: iterable from 16 ints 0..255
83+
PyObject* it = PyObject_GetIter(seq);
84+
size_t count {0};
85+
if (it)
86+
{
87+
PyObject* item {nullptr};
88+
while ((item = PyIter_Next(it)) && count < 16)
89+
{
90+
long val = PyLong_AsLong(item);
91+
Py_DECREF(item);
92+
if (val == -1 && PyErr_Occurred())
93+
{
94+
delete self;
95+
self = nullptr;
96+
PyErr_SetString(PyExc_TypeError, "Sequence must contain integers");
97+
break;
98+
}
99+
else if (val < 0 || val > 255)
100+
{
101+
delete self;
102+
self = nullptr;
103+
PyErr_SetString(PyExc_ValueError, "Each value must be in 0..255");
104+
break;
105+
}
106+
107+
(*self)[count] = static_cast<uint8_t>(val);
108+
++count;
109+
}
110+
Py_DECREF(it);
111+
if ((nullptr != item || count != 16) && nullptr != self)
112+
{
113+
delete self;
114+
self = nullptr;
115+
PyErr_SetString(PyExc_ValueError, "Expected 16 elements");
116+
}
117+
}
118+
else
119+
{
120+
delete self;
121+
self = nullptr;
122+
PyErr_SetString(PyExc_TypeError, "Expected a sequence of 16 integers (0..255) or 16-byte object");
123+
}
124+
}
125+
126+
SWIG_PYTHON_THREAD_END_BLOCK;
127+
128+
return self;
59129
}
60-
}
61130

62-
%typemap(out) eprosima::fastrtps::rtps::InstanceHandleValue_t*
63-
{
64-
constexpr size_t ih_size = std::tuple_size<eprosima::fastrtps::rtps::KeyHash_t>::value;
65-
PyObject* python_tuple = PyTuple_New(ih_size);
131+
size_t __len__() const { return 16; }
66132

67-
if (python_tuple)
68-
{
69-
for(size_t count = 0; count < ih_size; ++count)
70-
{
71-
PyTuple_SetItem(python_tuple, count, PyInt_FromLong((*$1)[count]));
72-
}
133+
uint8_t __getitem__(size_t i) const {
134+
if (i >= 16) throw std::out_of_range("index out of range");
135+
return $self->operator[](i);
73136
}
74137

75-
$result = python_tuple;
138+
void __setitem__(size_t i, uint8_t v) {
139+
if (i >= 16) throw std::out_of_range("index out of range");
140+
$self->operator[](i) = v;
141+
}
76142
}
77143

78-
// Template for std::vector<InstanceHandle_t>
79-
%template(InstanceHandleVector) std::vector<eprosima::fastrtps::rtps::InstanceHandle_t>;
80-
%typemap(doctype) std::vector<eprosima::fastrtps::rtps::InstanceHandle_t>"InstanceHandleVector";
81-
82-
%include "fastdds/rtps/common/InstanceHandle.h"
144+
%ignore eprosima::fastdds::rtps::InstanceHandle_t::value;
83145

84146
// Declare the comparison operators as internal to the class
85147
%extend eprosima::fastrtps::rtps::InstanceHandle_t {
@@ -106,4 +168,51 @@ long hash(const eprosima::fastrtps::rtps::InstanceHandle_t& handle)
106168
{
107169
return hash(*$self);
108170
}
171+
172+
// Setter from sequence (tuple/list/bytes/bytearray)
173+
void from_sequence(PyObject* seq) {
174+
// Reuse the constructor to validate and copy
175+
eprosima::fastdds::rtps::InstanceHandleValue_t* tmp = new_eprosima_fastdds_rtps_InstanceHandleValue_t(seq);
176+
if (nullptr != tmp)
177+
{
178+
for (int i = 0; i < 16; ++i) $self->value[i] = (*tmp)[i];
179+
delete tmp; // avoid memory leak
180+
}
181+
}
182+
183+
// Getter: return a tuple of 16 ints (0..255)
184+
PyObject* to_sequence() const {
185+
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
186+
187+
PyObject* python_tuple = PyTuple_New(16);
188+
189+
if (python_tuple)
190+
{
191+
for(size_t count = 0; count < 16; ++count)
192+
{
193+
PyTuple_SetItem(python_tuple, count, PyInt_FromLong($self->value[count]));
194+
}
195+
}
196+
197+
SWIG_PYTHON_THREAD_END_BLOCK;
198+
199+
return python_tuple;
200+
}
109201
}
202+
203+
// Template for std::vector<InstanceHandle_t>
204+
%template(InstanceHandleVector) std::vector<eprosima::fastdds::rtps::InstanceHandle_t>;
205+
%typemap(doctype) std::vector<eprosima::fastdds::rtps::InstanceHandle_t>"InstanceHandleVector";
206+
207+
%include "fastdds/rtps/common/InstanceHandle.h"
208+
209+
%pythoncode %{
210+
def _ihv_get_value(self):
211+
return self.to_sequence()
212+
213+
def _ihv_set_value(self, seq):
214+
self.from_sequence(seq)
215+
216+
InstanceHandle_t.value = property(_ihv_get_value, _ihv_set_value,
217+
doc="16-byte value as list/tuple/bytes/bytearray")
218+
%}

fastdds_python/test/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,17 @@ if (${fastcdr_VERSION_MAJOR} EQUAL 1)
2020
set(fastcdr_version_argument "v1")
2121
endif()
2222

23+
# Unit tests
24+
add_test(NAME unit_tests
25+
COMMAND
26+
${Python3_EXECUTABLE}
27+
-m pytest
28+
-vrP
29+
WORKING_DIRECTORY
30+
${CMAKE_CURRENT_SOURCE_DIR}/unittest
31+
)
2332

33+
# DDS Api tests
2434
add_test(NAME api_tests
2535
COMMAND
2636
${Python3_EXECUTABLE}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import fastdds
2+
import pytest
3+
import sys
4+
5+
6+
def test_create_instance_handle_from_bytes():
7+
ih = fastdds.InstanceHandle_t()
8+
ih.value = b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
9+
assert (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) == ih.value
10+
11+
12+
def test_create_instance_handle_from_bytearray():
13+
ih = fastdds.InstanceHandle_t()
14+
ih.value = bytearray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
15+
assert (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) == ih.value
16+
17+
18+
def test_create_instance_handle_from_tuple():
19+
ih = fastdds.InstanceHandle_t()
20+
ih.value = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)
21+
assert (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) == ih.value
22+
23+
24+
def test_create_instance_handle_from_list():
25+
ih = fastdds.InstanceHandle_t()
26+
ih.value = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
27+
assert (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) == ih.value
28+
29+
30+
def test_create_instance_handle_from_bytes_with_less_elements():
31+
ih = fastdds.InstanceHandle_t()
32+
with pytest.raises(SystemError) as exception:
33+
ih.value = b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
34+
repr = exception.getrepr()
35+
assert str(repr).split("\n")[0] == "ValueError: Expected 16 bytes"
36+
37+
38+
def test_create_instance_handle_from_bytes_with_more_elements():
39+
ih = fastdds.InstanceHandle_t()
40+
with pytest.raises(SystemError) as exception:
41+
ih.value = (
42+
b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12"
43+
)
44+
repr = exception.getrepr()
45+
assert str(repr).split("\n")[0] == "ValueError: Expected 16 bytes"
46+
47+
48+
def test_create_instance_handle_from_bytearray_with_less_elements():
49+
ih = fastdds.InstanceHandle_t()
50+
with pytest.raises(SystemError) as exception:
51+
ih.value = bytearray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
52+
repr = exception.getrepr()
53+
assert str(repr).split("\n")[0] == "ValueError: Expected 16 bytes"
54+
55+
56+
def test_create_instance_handle_from_bytearray_with_more_elements():
57+
ih = fastdds.InstanceHandle_t()
58+
with pytest.raises(SystemError) as exception:
59+
ih.value = bytearray(
60+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
61+
)
62+
repr = exception.getrepr()
63+
assert str(repr).split("\n")[0] == "ValueError: Expected 16 bytes"
64+
65+
66+
def test_create_instance_handle_from_tuple_with_less_elements():
67+
ih = fastdds.InstanceHandle_t()
68+
with pytest.raises(SystemError) as exception:
69+
ih.value = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
70+
repr = exception.getrepr()
71+
assert str(repr).split("\n")[0] == "ValueError: Expected 16 elements"
72+
73+
74+
def test_create_instance_handle_from_tuple_with_more_elements():
75+
ih = fastdds.InstanceHandle_t()
76+
with pytest.raises(SystemError) as exception:
77+
ih.value = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)
78+
repr = exception.getrepr()
79+
assert str(repr).split("\n")[0] == "ValueError: Expected 16 elements"
80+
81+
82+
def test_create_instance_handle_from_list_with_less_elements():
83+
ih = fastdds.InstanceHandle_t()
84+
with pytest.raises(SystemError) as exception:
85+
ih.value = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
86+
repr = exception.getrepr()
87+
assert str(repr).split("\n")[0] == "ValueError: Expected 16 elements"
88+
89+
90+
def test_create_instance_handle_from_list_with_more_elements():
91+
ih = fastdds.InstanceHandle_t()
92+
with pytest.raises(SystemError) as exception:
93+
ih.value = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
94+
repr = exception.getrepr()
95+
assert str(repr).split("\n")[0] == "ValueError: Expected 16 elements"
96+
97+
98+
def test_create_instance_handle_from_bytearray_with_with_negative_number():
99+
ih = fastdds.InstanceHandle_t()
100+
with pytest.raises(ValueError) as exception:
101+
ih.value = bytearray([1, 2, 3, 4, 5, 6, 7, 8, 9, -10, 11, 12, 13, 14, 15, 16])
102+
assert str(exception.value) == "byte must be in range(0, 256)"
103+
104+
105+
def test_create_instance_handle_from_bytearray_with_large_number():
106+
ih = fastdds.InstanceHandle_t()
107+
with pytest.raises(ValueError) as exception:
108+
ih.value = bytearray([1, 2, 3, 4, 5, 6, 7, 8, 9, 1000, 11, 12, 13, 14, 15, 16])
109+
assert str(exception.value) == "byte must be in range(0, 256)"
110+
111+
112+
def test_create_instance_handle_from_tuple_with_negative_number():
113+
ih = fastdds.InstanceHandle_t()
114+
with pytest.raises(SystemError) as exception:
115+
ih.value = (1, 2, 3, 4, 5, 6, 7, 8, 9, -10, 11, 12, 13, 14, -15, 16)
116+
repr = exception.getrepr()
117+
assert str(repr).split("\n")[0] == "ValueError: Each value must be in 0..255"
118+
119+
120+
def test_create_instance_handle_from_tuple_with_large_number():
121+
ih = fastdds.InstanceHandle_t()
122+
with pytest.raises(SystemError) as exception:
123+
ih.value = (1, 2, 3, 4, 5, 6, 7, 8, 9, 1000, 11, 12, 13, 14, 15, 16)
124+
repr = exception.getrepr()
125+
assert str(repr).split("\n")[0] == "ValueError: Each value must be in 0..255"
126+
127+
128+
def test_create_instance_handle_from_list_with_negative_number():
129+
ih = fastdds.InstanceHandle_t()
130+
with pytest.raises(SystemError) as exception:
131+
ih.value = [1, 2, 3, 4, 5, 6, 7, 8, 9, -10, 11, 12, 13, 14, 15, 16]
132+
repr = exception.getrepr()
133+
assert str(repr).split("\n")[0] == "ValueError: Each value must be in 0..255"
134+
135+
136+
def test_create_instance_handle_from_list_with_large_number():
137+
ih = fastdds.InstanceHandle_t()
138+
with pytest.raises(SystemError) as exception:
139+
ih.value = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1000, 11, 12, 13, 14, 15, 16]
140+
repr = exception.getrepr()
141+
assert str(repr).split("\n")[0] == "ValueError: Each value must be in 0..255"

0 commit comments

Comments
 (0)