from six import moves
from framework import VppTestCase
+from enum import Enum
class SerializableClassCopy(object):
def __getattr__(self, attr):
if attr[0] == '_':
- raise AttributeError
+ if not (attr.startswith('__') and attr.endswith('__')):
+ raise AttributeError
self._path.append(attr)
return self
def __setattr__(self, attr, val):
if attr[0] == '_':
- super(RemoteClassAttr, self).__setattr__(attr, val)
- return
+ if not (attr.startswith('__') and attr.endswith('__')):
+ super(RemoteClassAttr, self).__setattr__(attr, val)
+ return
self._path.append(attr)
self._remote._remote_exec(RemoteClass.SETATTR, self.path_to_str(),
True, value=val)
def __getattr__(self, attr):
if attr[0] == '_' or not self.is_alive():
- if hasattr(super(RemoteClass, self), '__getattr__'):
- return super(RemoteClass, self).__getattr__(attr)
- raise AttributeError
+ if not (attr.startswith('__') and attr.endswith('__')):
+ if hasattr(super(RemoteClass, self), '__getattr__'):
+ return super(RemoteClass, self).__getattr__(attr)
+ raise AttributeError
return RemoteClassAttr(self, attr)
def __setattr__(self, attr, val):
if attr[0] == '_' or not self.is_alive():
- super(RemoteClass, self).__setattr__(attr, val)
- return
+ if not (attr.startswith('__') and attr.endswith('__')):
+ super(RemoteClass, self).__setattr__(attr, val)
+ return
setattr(RemoteClassAttr(self, None), attr, val)
def _remote_exec(self, op, path=None, ret=True, *args, **kwargs):
"""
if self._serializable(obj):
return obj # already serializable
+
copy = SerializableClassCopy()
+
+ """
+ Dictionaries can hold complex values, so we split keys and values into
+ separate lists and serialize them individually.
+ """
+ if (type(obj) is dict):
+ copy.type = type(obj)
+ copy.k_list = list()
+ copy.v_list = list()
+ for k, v in obj.items():
+ copy.k_list.append(self._make_serializable(k))
+ copy.v_list.append(self._make_serializable(v))
+ return copy
+
# copy at least serializable attributes and properties
for name, member in inspect.getmembers(obj):
if name[0] == '_': # skip private members
- continue
+ if not (name.startswith('__') and name.endswith('__')):
+ continue
if callable(member) and not isinstance(member, property):
continue
if not self._serializable(member):
if type(obj) is tuple:
rv = tuple(rv)
return rv
+ elif (isinstance(obj, Enum)):
+ return obj.value
else:
return self._make_obj_serializable(obj)
def _deserialize_obj(self, obj):
+ if (hasattr(obj, 'type')):
+ if obj.type is dict:
+ _obj = dict()
+ for k, v in zip(obj.k_list, obj.v_list):
+ _obj[self._deserialize(k)] = self._deserialize(v)
+ return _obj
return obj
def _deserialize(self, obj):
def __init__(self):
super(RemoteVppTestCase, self).__init__("emptyTest")
+ # Note: __del__ is a 'Finalizer" not a 'Destructor'.
+ # https://docs.python.org/3/reference/datamodel.html#object.__del__
def __del__(self):
if hasattr(self, "vpp"):
- cls.vpp.poll()
- if cls.vpp.returncode is None:
- cls.vpp.terminate()
- cls.vpp.communicate()
+ self.vpp.poll()
+ if self.vpp.returncode is None:
+ self.vpp.terminate()
+ self.vpp.communicate()
@classmethod
def setUpClass(cls, tempdir):