X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvpp-api%2Fpython%2Fvpp_papi%2Fvpp_papi.py;h=c37334cd4e546d1f5969f5d1319b850ca92bf871;hb=dfb984d4e82d3950bb7270a4e8c6b2dda26c10da;hp=2310cd1e4553f0e552b54ccbc229cae8ea2cf4b7;hpb=31555a3475a37195938378217a635b3451e449de;p=vpp.git diff --git a/src/vpp-api/python/vpp_papi/vpp_papi.py b/src/vpp-api/python/vpp_papi/vpp_papi.py index 2310cd1e455..c37334cd4e5 100644 --- a/src/vpp-api/python/vpp_papi/vpp_papi.py +++ b/src/vpp-api/python/vpp_papi/vpp_papi.py @@ -27,7 +27,7 @@ import fnmatch import weakref import atexit from . vpp_serializer import VPPType, VPPEnumType, VPPUnionType, BaseTypes -from . vpp_serializer import VPPMessage, vpp_get_type +from . vpp_serializer import VPPMessage, vpp_get_type, VPPTypeAlias from . vpp_format import VPPFormat if sys.version[0] == '2': @@ -45,7 +45,7 @@ class VppEnumType(type): # Python3 # class VppEnum(metaclass=VppEnumType): # pass -class VppEnum: +class VppEnum(object): __metaclass__ = VppEnumType @@ -77,7 +77,27 @@ class FuncWrapper(object): return self._func(**kwargs) -class VPP(): +class VPPApiError(Exception): + pass + + +class VPPNotImplementedError(NotImplementedError): + pass + + +class VPPIOError(IOError): + pass + + +class VPPRuntimeError(RuntimeError): + pass + + +class VPPValueError(ValueError): + pass + + +class VPP(object): """VPP interface. This class provides the APIs to VPP. The APIs are loaded @@ -89,6 +109,11 @@ class VPP(): provides a means to register a callback function to receive these messages in a background thread. """ + VPPApiError = VPPApiError + VPPRuntimeError = VPPRuntimeError + VPPValueError = VPPValueError + VPPNotImplementedError = VPPNotImplementedError + VPPIOError = VPPIOError def process_json_file(self, apidef_file): api = json.load(apidef_file) @@ -102,13 +127,16 @@ class VPP(): for t in api['types']: t[0] = 'vl_api_' + t[0] + '_t' types[t[0]] = {'type': 'type', 'data': t} + for t, v in api['aliases'].items(): + types['vl_api_' + t + '_t'] = {'type': 'alias', 'data': v} + self.services.update(api['services']) i = 0 while True: unresolved = {} for k, v in types.items(): t = v['data'] - if not vpp_get_type(t[0]): + if not vpp_get_type(k): if v['type'] == 'enum': try: VPPEnumType(t[0], t[1:]) @@ -124,22 +152,27 @@ class VPP(): VPPType(t[0], t[1:]) except ValueError: unresolved[k] = v + elif v['type'] == 'alias': + try: + VPPTypeAlias(k, t) + except ValueError: + unresolved[k] = v if len(unresolved) == 0: break if i > 3: - raise ValueError('Unresolved type definitions {}' - .format(unresolved)) + raise VPPValueError('Unresolved type definitions {}' + .format(unresolved)) types = unresolved i += 1 for m in api['messages']: try: self.messages[m[0]] = VPPMessage(m[0], m[1:]) - except NotImplementedError: + except VPPNotImplementedError: self.logger.error('Not implemented error for {}'.format(m[0])) def __init__(self, apifiles=None, testmode=False, async_thread=True, - logger=logging.getLogger('vpp_papi'), loglevel='debug', + logger=None, loglevel=None, read_timeout=5, use_socket=False, server_address='/run/vpp-api.sock'): """Create a VPP API object. @@ -161,6 +194,7 @@ class VPP(): self.logger = logger self.messages = {} + self.services = {} self.id_names = [] self.id_msgdef = [] self.header = VPPType('header', [['u16', 'msgid'], @@ -185,7 +219,7 @@ class VPP(): if testmode: apifiles = [] else: - raise + raise VPPRuntimeError for file in apifiles: with open(file) as apidef_file: @@ -195,7 +229,7 @@ class VPP(): # Basic sanity check if len(self.messages) == 0 and not testmode: - raise ValueError(1, 'Missing JSON message definitions') + raise VPPValueError(1, 'Missing JSON message definitions') self.transport = VppTransport(self, read_timeout=read_timeout, server_address=server_address) @@ -326,7 +360,7 @@ class VPP(): if api_dir is None: api_dir = cls.find_api_dir() if api_dir is None: - raise RuntimeError("api_dir cannot be located") + raise VPPApiError("api_dir cannot be located") if isinstance(patterns, list) or isinstance(patterns, tuple): patterns = [p.strip() + '.api.json' for p in patterns] @@ -345,7 +379,7 @@ class VPP(): @property def api(self): if not hasattr(self, "_api"): - raise Exception("Not connected, api definitions not available") + raise VPPApiError("Not connected, api definitions not available") return self._api def make_function(self, msg, i, multipart, do_async): @@ -372,10 +406,15 @@ class VPP(): if i > 0: self.id_msgdef[i] = msg 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, do_async) - setattr(self._api, name, FuncWrapper(f)) + + # Create function for client side messages. + if name in self.services: + if 'stream' in self.services[name] and self.services[name]['stream']: + multipart = True + else: + multipart = False + f = self.make_function(msg, i, multipart, do_async) + setattr(self._api, name, FuncWrapper(f)) else: self.logger.debug( 'No such message type or failed CRC checksum: %s', n) @@ -386,7 +425,7 @@ class VPP(): rv = self.transport.connect(name.encode(), pfx, msg_handler, rx_qlen) if rv != 0: - raise IOError(2, 'Connect failed') + raise VPPIOError(2, 'Connect failed') self.vpp_dictionary_maxid = self.transport.msg_table_max_index() self._register_functions(do_async=do_async) @@ -452,7 +491,7 @@ class VPP(): # No context -> async notification that we feed to the callback self.message_queue.put_nowait(r) else: - raise IOError(2, 'RPC reply message received in event handler') + raise VPPIOError(2, 'RPC reply message received in event handler') def decode_incoming_msg(self, msg): if not msg: @@ -467,7 +506,7 @@ class VPP(): # msgobj = self.id_msgdef[i] if not msgobj: - raise IOError(2, 'Reply message undefined') + raise VPPIOError(2, 'Reply message undefined') r, size = msgobj.unpack(msg) return r @@ -495,7 +534,7 @@ 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 {}' + raise VPPValueError('Invalid argument {} to {}' .format(list(d), msg.name)) def _call_vpp(self, i, msg, multipart, **kwargs): @@ -542,7 +581,7 @@ class VPP(): while (True): msg = self.transport.read() if not msg: - raise IOError(2, 'VPP API client: read failed') + raise VPPIOError(2, 'VPP API client: read failed') r = self.decode_incoming_msg(msg) msgname = type(r).__name__ if context not in r or r.context == 0 or context != r.context: