from __future__ import print_function
from __future__ import absolute_import
+import ctypes
import sys
+import multiprocessing as mp
import os
import logging
-import collections
-import struct
import functools
import json
import threading
import fnmatch
import weakref
import atexit
-from . vpp_serializer import VPPType, VPPEnumType, VPPUnionType, BaseTypes
+from . vpp_serializer import VPPType, VPPEnumType, VPPUnionType
from . vpp_serializer import VPPMessage, vpp_get_type, VPPTypeAlias
-from . macaddress import MACAddress, mac_pton, mac_ntop
logger = logging.getLogger(__name__)
else:
import queue as queue
+__all__ = ('FuncWrapper', 'VPP', 'VppApiDynamicMethodHolder',
+ 'VppEnum', 'VppEnumType',
+ 'VPPIOError', 'VPPRuntimeError', 'VPPValueError',
+ 'VPPApiClient', )
+
def metaclass(metaclass):
@functools.wraps(metaclass)
def __call__(self, **kwargs):
return self._func(**kwargs)
+ def __repr__(self):
+ return '<FuncWrapper(func=<%s(%s)>)>' % (self.__name__, self.__doc__)
+
class VPPApiError(Exception):
pass
loglevel, if supplied, is the log level this logger is set
to report at (from the loglevels in the logging module).
"""
- if apifiles is None and self.__class__.apidir is None:
- raise ValueError("Either apifiles or apidir must be specified.")
-
if logger is None:
logger = logging.getLogger(__name__)
if loglevel is not None:
self.message_queue = queue.Queue()
self.read_timeout = read_timeout
self.async_thread = async_thread
+ self.event_thread = None
+ self.testmode = testmode
+ self.use_socket = use_socket
+ self.server_address = server_address
+ self._apifiles = apifiles
if use_socket:
from . vpp_transport_socket import VppTransport
atexit.register(vpp_atexit, weakref.ref(self))
class ContextId(object):
- """Thread-safe provider of unique context IDs."""
+ """Multiprocessing-safe provider of unique context IDs."""
def __init__(self):
- self.context = 0
- self.lock = threading.Lock()
+ self.context = mp.Value(ctypes.c_uint, 0)
+ self.lock = mp.Lock()
def __call__(self):
"""Get a new unique (or, at least, not recently used) context."""
with self.lock:
- self.context += 1
- return self.context
+ self.context.value += 1
+ return self.context.value
get_context = ContextId()
def get_type(self, name):
:returns: A single directory name, or None if no such directory
could be found.
"""
- dirs = [cls.apidir]
+ dirs = [cls.apidir] if cls.apidir else []
# perhaps we're in the 'src/scripts' or 'src/vpp-api/python' dir;
# in which case, plot a course to likely places in the src tree
target=self.thread_msg_handler)
self.event_thread.daemon = True
self.event_thread.start()
+ else:
+ self.event_thread = None
return rv
def connect(self, name, chroot_prefix=None, do_async=False, rx_qlen=32):
def disconnect(self):
"""Detach from VPP."""
rv = self.transport.disconnect()
- self.message_queue.put("terminate event thread")
+ if self.event_thread is not None:
+ self.message_queue.put("terminate event thread")
return rv
def msg_handler_sync(self, msg):
if self.event_callback:
self.event_callback(msgname, r)
+ def __repr__(self):
+ return "<VPPApiClient apifiles=%s, testmode=%s, async_thread=%s, " \
+ "logger=%s, read_timeout=%s, use_socket=%s, " \
+ "server_address='%s'>" % (
+ self._apifiles, self.testmode, self.async_thread,
+ self.logger, self.read_timeout, self.use_socket,
+ self.server_address)
+
+
# Provide the old name for backward compatibility.
VPP = VPPApiClient