eclipse-ecal / ecal

📦 eCAL - enhanced Communication Abstraction Layer. A high performance publish-subscribe, client-server cross-plattform middleware.
https://ecal.io
Apache License 2.0
842 stars 174 forks source link

[Python] message with default values only is None #1103

Closed ENAC-Robotique closed 1 year ago

ENAC-Robotique commented 1 year ago

Problem Description

Using the python bindings, I get this error when receiving a message with only default values (e.g. only 0):

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/ecal/core/subscriber.py", line 131, in _on_receive
    proto_message.ParseFromString(msg)
TypeError: a bytes-like object is required, not 'NoneType'

I temporarily "solved" the issue by inserting these 2 lines at line 131 (https://github.com/eclipse-ecal/ecal/blob/master/lang/python/core/ecal/core/subscriber.py#L131):

if msg is None:
    msg = b''

How to reproduce

  1. Define the following protobuf message:
    message Position {
    float x = 1;
    float y = 2;
    float theta = 3;
    }
  2. In a python program, make a ProtoSubscriber over this message, and set a callback.
  3. Send a Position message from an other python program with all fields at the value 0.

How did you get eCAL?

Ubuntu PPA (apt-get)

Environment

eCAL System Information

------------------------- SYSTEM ---------------------------------
Version                  : v5.11.4 (2023-04-06 09:25:10 +0200)
Platform                 : linux

------------------------- CONFIGURATION --------------------------
Default INI              : /etc/ecal/ecal.ini

------------------------- NETWORK --------------------------------
Host name                : cooking-mama
Network mode             : cloud
Network ttl              : 2
Network sndbuf           : 5 MByte
Network rcvbuf           : 5 MByte
Multicast group          : 239.0.0.1
Multicast mask           : 0.0.0.15
Multicast ports          : 14000 - 14010
Multicast join all IFs   : on
Bandwidth limit (udp)    : not limited

------------------------- TIME -----------------------------------
Synchronization realtime : "ecaltime-localtime"
Synchronization replay   : 
State                    :  synchronized 
Master / Slave           :  Master 
Status (Code)            : "everything is fine." (0)

------------------------- PUBLISHER LAYER DEFAULTS ---------------
Layer Mode INPROC        : off
Layer Mode SHM           : auto
Layer Mode TCP           : off
Layer Mode UDP MC        : auto

------------------------- SUBSCRIPTION LAYER DEFAULTS ------------
Layer Mode INPROC        : on
Layer Mode SHM           : on
Layer Mode TCP           : on
Layer Mode UDP MC        : on
Npcap UDP Reciever       : off
KerstinKeller commented 1 year ago

Thanks for reporting, I can reproduce. It seems to be an issue only with the callbacks, not when calling receive!

KerstinKeller commented 1 year ago

See https://docs.python.org/3/c-api/arg.html#building-values

y# (bytes) [const char *, Py_ssize_t] This converts a C string and its lengths to a Python object. If the C string pointer is NULL, None is returned.

The pointer passed to build the value in the callback might be null, in case that the size is 0. https://github.com/eclipse-ecal/ecal/blob/6fc81d074bc3d5918df8378e56c6bb3134a26e95/lang/python/core/src/ecal_wrap.cxx#L592

I guess your quick fix might be the actual solution, since I haven't found anything that can create a 0 length byte array (and I don't think it makes sense to let the pointer point to arbitrary memory...)