PAPI: Unpack embedded types with variable length arrays.
[vpp.git] / src / vpp-api / python / vpp_papi / vpp_papi.py
index 5ff8064..4f765ec 100644 (file)
@@ -15,6 +15,7 @@
 #
 
 from __future__ import print_function
+from __future__ import absolute_import
 import sys
 import os
 import logging
@@ -27,7 +28,8 @@ import weakref
 import atexit
 from cffi import FFI
 import cffi
-from vpp_serializer import VPPType, VPPEnumType, VPPUnionType, BaseTypes
+from . vpp_serializer import VPPType, VPPEnumType, VPPUnionType, BaseTypes
+from . vpp_serializer import VPPMessage
 
 if sys.version[0] == '2':
     import Queue as queue
@@ -61,7 +63,7 @@ vpp_api = ffi.dlopen('libvppapiclient.so')
 def vpp_atexit(vpp_weakref):
     """Clean up VPP connection on shutdown."""
     vpp_instance = vpp_weakref()
-    if vpp_instance.connected:
+    if vpp_instance and vpp_instance.connected:
         vpp_instance.logger.debug('Cleaning up VPP on exit')
         vpp_instance.disconnect()
 
@@ -91,7 +93,7 @@ def vac_error_handler(arg, msg, msg_len):
     vpp_object.logger.warning("VPP API client:: %s", ffi.string(msg, msg_len))
 
 
-class Empty(object):
+class VppApiDynamicMethodHolder(object):
     pass
 
 
@@ -104,9 +106,6 @@ class FuncWrapper(object):
         return self._func(**kwargs)
 
 
-class VPPMessage(VPPType):
-    pass
-
 class VPP():
     """VPP interface.
 
@@ -389,8 +388,8 @@ class VPP():
             raise Exception("Not connected, api definitions not available")
         return self._api
 
-    def make_function(self, msg, i, multipart, async):
-        if (async):
+    def make_function(self, msg, i, multipart, do_async):
+        if (do_async):
             def f(**kwargs):
                 return self._call_vpp_async(i, msg, **kwargs)
         else:
@@ -399,13 +398,14 @@ class VPP():
 
         f.__name__ = str(msg.name)
         f.__doc__ = ", ".join(["%s %s" %
-                               (msg.fieldtypes[j], k) for j, k in enumerate(msg.fields)])
+                               (msg.fieldtypes[j], k)
+                               for j, k in enumerate(msg.fields)])
         return f
 
-    def _register_functions(self, async=False):
+    def _register_functions(self, do_async=False):
         self.id_names = [None] * (self.vpp_dictionary_maxid + 1)
         self.id_msgdef = [None] * (self.vpp_dictionary_maxid + 1)
-        self._api = Empty()
+        self._api = VppApiDynamicMethodHolder()
         for name, msg in vpp_iterator(self.messages):
             n = name + '_' + msg.crc[2:]
             i = vpp_api.vac_get_msg_index(n.encode())
@@ -414,7 +414,7 @@ class VPP():
                 self.id_names[i] = name
                 # TODO: Fix multipart (use services)
                 multipart = True if name.find('_dump') > 0 else False
-                f = self.make_function(msg, i, multipart, async)
+                f = self.make_function(msg, i, multipart, do_async)
                 setattr(self._api, name, FuncWrapper(f))
             else:
                 self.logger.debug(
@@ -445,14 +445,14 @@ class VPP():
         return msg
 
     def connect_internal(self, name, msg_handler, chroot_prefix, rx_qlen,
-                         async):
+                         do_async):
         pfx = chroot_prefix.encode() if chroot_prefix else ffi.NULL
         rv = vpp_api.vac_connect(name.encode(), pfx, msg_handler, rx_qlen)
         if rv != 0:
             raise IOError(2, 'Connect failed')
         self.connected = True
         self.vpp_dictionary_maxid = vpp_api.vac_msg_table_max_index()
-        self._register_functions(async=async)
+        self._register_functions(do_async=do_async)
 
         # Initialise control ping
         crc = self.messages['control_ping'].crc
@@ -466,18 +466,18 @@ class VPP():
             self.event_thread.start()
         return rv
 
-    def connect(self, name, chroot_prefix=None, async=False, rx_qlen=32):
+    def connect(self, name, chroot_prefix=None, do_async=False, rx_qlen=32):
         """Attach to VPP.
 
         name - the name of the client.
         chroot_prefix - if VPP is chroot'ed, the prefix of the jail
-        async - if true, messages are sent without waiting for a reply
+        do_async - if true, messages are sent without waiting for a reply
         rx_qlen - the length of the VPP message receive queue between
         client and server.
         """
-        msg_handler = vac_callback_sync if not async else vac_callback_async
+        msg_handler = vac_callback_sync if not do_async else vac_callback_async
         return self.connect_internal(name, msg_handler, chroot_prefix, rx_qlen,
-                                     async)
+                                     do_async)
 
     def connect_sync(self, name, chroot_prefix=None, rx_qlen=32):
         """Attach to VPP in synchronous mode. Application must poll for events.
@@ -489,7 +489,7 @@ class VPP():
         """
 
         return self.connect_internal(name, ffi.NULL, chroot_prefix, rx_qlen,
-                                     async=False)
+                                     do_async=False)
 
     def disconnect(self):
         """Detach from VPP."""
@@ -523,8 +523,7 @@ class VPP():
         if not msg:
             self.logger.warning('vpp_api.read failed')
             return
-
-        i, ci = self.header.unpack(msg, 0)
+        (i, ci), size = self.header.unpack(msg, 0)
         if self.id_names[i] == 'rx_thread_exit':
             return
 
@@ -535,8 +534,7 @@ class VPP():
         if not msgobj:
             raise IOError(2, 'Reply message undefined')
 
-        r = msgobj.unpack(msg)
-
+        r, size = msgobj.unpack(msg)
         return r
 
     def msg_handler_async(self, msg):
@@ -562,7 +560,8 @@ class VPP():
     def validate_args(self, msg, kwargs):
         d = set(kwargs.keys()) - set(msg.field_by_name.keys())
         if d:
-            raise ValueError('Invalid argument {} to {}'.format(list(d), msg.name))
+            raise ValueError('Invalid argument {} to {}'
+                             .format(list(d), msg.name))
 
     def _call_vpp(self, i, msg, multipart, **kwargs):
         """Given a message, send the message and await a reply.