"""This module provides the base types used by :mod:`virtualbox.library`."""
import re
import inspect
import platform
import time
# Py2 and Py3 compatibility
try:
import __builtin__ as builtin
except:
import builtins as builtin
def pythonic_name(name):
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
if hasattr(builtin, name) is True or name in ['global']:
name += "_p"
return name
[docs]class EnumType(type):
"""EnumType is a metaclass for Enum. It is responsible for configuring
the Enum class object's values defined in Enum.lookup_label"""
def __init__(cls, name, bases, dct):
cls._value = None
cls._lookup_label = dict((v, l) for l, v, _ in cls._enums)
cls._lookup_doc = dict((v, d) for _, v, d in cls._enums)
for l, v, _ in cls._enums:
setattr(cls, pythonic_name(l), cls(v))
def __getitem__(cls, k):
if not hasattr(cls, k):
raise KeyError("%s has no key %s" % cls.__name__, k)
return getattr(cls, k)
# Code from six - support for py2 and py3 compatibility
[docs]@add_metaclass(EnumType)
class Enum(object):
"""Enum objects provide a container for VirtualBox enumerations"""
_enums = {}
def __init__(self, value):
if value not in self._lookup_label:
raise ValueError("Can not find enumeration where value=%s" % value)
self._value = value
self.__doc__ = self._lookup_doc[self._value]
def __str__(self):
if self._value is None:
return "None"
return self._lookup_label[self._value]
def __int__(self):
return self._value
def __repr__(self):
return "%s(%s)" % (self.__class__.__name__, self._value)
def __eq__(self, k):
return self.__cmp__(k) == 0
def __cmp__(self, k):
return (int(self) > int(k)) - (int(self) < int(k))
def __getitem__(self, k):
return self.__class__[k]
vbox_error = {}
class VBoxErrorMeta(type):
def __init__(cls, name, bases, dct):
global vbox_error
if cls.value != -1:
vbox_error[cls.value] = cls
[docs]@add_metaclass(VBoxErrorMeta)
class VBoxError(Exception):
"""Generic VBoxError"""
name = "undef"
value = -1
msg = ""
def __str__(self):
return "0x%x (%s)" % (self.value, self.msg)
[docs]class Interface(object):
"""Interface objects provide a wrapper for the VirtualBox COM objects"""
def __init__(self, interface=None):
if isinstance(interface, Interface):
import virtualbox
manager = virtualbox.Manager()
self._i = manager.cast_object(interface, self.__class__)._i
else:
self._i = interface
def __nonzero__(self):
return bool(self._i)
def _cast_to_valuetype(self, value):
def cast_to_valuetype(value):
if isinstance(value, Interface):
return value._i
elif isinstance(value, Enum):
return int(value)
else:
return value
if isinstance(value, list):
return [cast_to_valuetype(a) for a in value]
else:
return cast_to_valuetype(value)
def _search_attr(self, name, prefix=None):
attr_names = [name]
if prefix is not None:
attr_names.append(prefix + name[0].upper() + name[1:])
# Sometimes xpcom interface fails to return the attribute. Check a few
# times before giving up.
for i in range(3):
for attr_name in attr_names:
attr = getattr(self._i, attr_name, self)
if attr is not self:
break
else:
# Failed to get attribute, do a quick sleep and try again.
time.sleep(0.1)
continue
break
else:
raise AttributeError("Failed to find attribute %s in %s" % (name, self))
return attr
def _get_attr(self, name):
attr = self._search_attr(name, prefix='get')
if inspect.isfunction(attr) or inspect.ismethod(attr):
return self._call_method(attr)
else:
return attr
def _set_attr(self, name, value):
attr = self._search_attr(name, prefix='set')
if inspect.isfunction(attr) or inspect.ismethod(attr):
return self._call_method(attr, value)
else:
if isinstance(value, Enum):
value = int(value)
return setattr(self._i, name, value)
def _call(self, name, in_p=None):
if in_p is None:
in_p = []
global vbox_error
method = self._search_attr(name)
if inspect.isfunction(method) or inspect.ismethod(method):
return self._call_method(method, in_p=in_p)
else:
return method
def _call_method(self, method, in_p=None):
if in_p is None:
in_p = []
in_params = [self._cast_to_valuetype(p) for p in in_p]
try:
ret = method(*in_params)
except Exception as exc:
errno = getattr(exc, 'errno', getattr(exc, 'hresult', -1))
errno &= 0xFFFFFFFF
errclass = vbox_error.get(errno, VBoxError)
errobj = errclass()
errobj.exc = exc
errobj.value = errno
# TODO: Is this the only way to get a message from exc...
# does this also vary between nix vs windows.
errobj.msg = None
if platform.system() == 'Windows':
if hasattr(exc, 'args'):
errobj.msg = exc.args[2][2]
# TODO: get the Linux/Darwin specific args struct
if errobj.msg is None:
errobj.msg = getattr(exc, 'msg', getattr(exc, 'message'))
raise errobj
return ret