Commit 79970c08 authored by Giorgos Korfiatis's avatar Giorgos Korfiatis
Browse files

Merge quotaholder into synnefo

parents 746c1c81 1ce99b13
......@@ -25,3 +25,6 @@ _build
*/synnefo/versions/*.py
!*/synnefo/versions/__init__.py
snf-tools/synnefo_tools/version.py
*.iml
*.graffle
# Import general commission framework
from .exception import (CallError, CorruptedError, InvalidDataError,
register_exception, register_exceptions)
from .callpoint import Callpoint, get_callpoint, mkcallargs
from .specificator import (Specificator, SpecifyException,
Canonifier, CanonifyException,
Canonical,
Null, Nothing, Integer, Serial,
Text, Bytes, Tuple, ListOf, Dict, Args)
# Import standard implementations?
from .specificator import CanonifyException
from .exception import CorruptedError, InvalidDataError
from .importing import imp_module
from re import compile as re_compile, sub as re_sub
class Callpoint(object):
api_spec = None
CorruptedError = CorruptedError
InvalidDataError = InvalidDataError
original_calls = {}
def __init__(self, connection=None):
from json import loads, dumps
self.json_loads = loads
self.json_dumps = dumps
self.init_connection(connection)
original_calls = self.original_calls
canonifier = self.api_spec
if canonifier is None:
m = "No api spec given to '%s'" % (type(self).__name__,)
raise NotImplementedError(m)
for call_name, call_doc in canonifier.call_docs():
if hasattr(self, call_name):
# don't crash: wrap the function instead
#m = ( "Method '%s' defined both in natively "
# "in callpoint '%s' and in api spec '%s'" %
# (call_name,
# type(self).__name__,
# type(canonifier).__name__) )
#raise ValueError(m)
call_func = getattr(self, call_name)
if not callable(call_func):
m = ( "api spec '%s', method '%s' is not a "
"callable attribute in callpoint '%s'" %
( type(canonifier).__name__,
call_name,
type(self).__name ) )
raise ValueError(m)
original_calls[call_name] = call_func
def mk_call_func():
local_call_name = call_name
def call_func(**data):
return self.make_call(local_call_name, data)
call_func.__name__ = call_name
call_func.__doc__ = call_doc
return call_func
setattr(self, call_name, mk_call_func())
def init_connection(self, connection):
pass
def commit(self):
pass
def rollback(self):
pass
def do_make_call(self, call_name, data):
raise NotImplementedError
def validate_call(self, call_name):
return hasattr(self, call_name)
def make_call_from_json_description(self, json_description):
try:
description = self.json_loads(json_description)
except ValueError, e:
m = "Cannot load json description"
raise self.InvalidDataError(m)
data = self.make_call_from_description(description)
json_data = self.json_dumps(data) if data is not None else None
return json_data
def make_call_from_description(self, description):
try:
call_name = description['call_name']
call_data = description['call_data']
except (TypeError, KeyError), e:
m = "Invalid description"
raise self.InvalidDataError(m, e)
return self.make_call(call_name, call_data)
def make_call_from_json(self, call_name, json_data):
if json_data:
try:
data = self.json_loads(json_data)
except ValueError, e:
m = "Cannot load json data"
raise self.InvalidDataError(m, e)
else:
data = None
data = self.make_call(call_name, data)
json_data = self.json_dumps(data)
return json_data
def make_call(self, call_name, data):
if call_name.startswith('_'):
m = "Invalid call '%s'" % (call_name,)
raise self.InvalidDataError(m)
canonifier = self.api_spec
try:
data = canonifier.canonify_input(call_name, data)
except CanonifyException, e:
m = "Invalid input to call '%s'" % (call_name,)
raise self.InvalidDataError(m, e)
if not self.validate_call(call_name):
m = "Cannot find specified call '%s'" % (call_name,)
raise self.CorruptedError(m)
call_func = self.original_calls.get(call_name, None)
try:
if call_func is None:
data = self.do_make_call(call_name, data)
else:
data = call_func(**data)
except Exception, e:
self.rollback()
raise
else:
self.commit()
try:
data = canonifier.canonify_output(call_name, data)
except CanonifyException, e:
m = "Invalid output from call '%s'" % (call_name,)
raise self.CorruptedError(m, e)
return data
def mkcallargs(**kw):
return kw
versiontag_pattern = re_compile('[^a-zA-Z0-9_-]')
def mk_versiontag(version):
if not version or version == 'v':
return ''
return '_' + re_sub(versiontag_pattern, '_', version)
def get_callpoint(pointname, version=None, automake=None, **kw):
versiontag = mk_versiontag(version)
components = pointname.split('.')
appname = components[0]
if len(components) < 2:
raise ValueError("invalid pointname '%s'" % (pointname,))
category = components[1]
if not category or category not in ['clients', 'servers']:
raise ValueError("invalid pointname '%s'" % (pointname,))
modname = ('%s.callpoint.API_Callpoint%s'
% (pointname, versiontag))
try:
API_Callpoint = imp_module(modname)
return API_Callpoint
except ImportError:
if not automake:
raise
if category != 'clients':
m = ("Can only auto-make callpoint in 'clients' not '%s'" % (category,))
raise ValueError(m)
components = components[1:]
if not components:
raise ValueError("invalid pointname '%s'" % (pointname))
pointname = '.'.join(components)
if pointname == 'quotaholder':
apiname = 'quotaholder.api.QuotaholderAPI'
else:
apiname = '%s.api.API_Spec%s' % (pointname, versiontag)
API_Spec = imp_module(apiname)
basename = 'commissioning.clients.%s.API_Callpoint' % (automake,)
BaseCallpoint = imp_module(basename)
stupidpython = (appname,
version if version is not None else 'v',
pointname,
automake)
class AutoCallpoint(BaseCallpoint):
appname, version, pointname, automake = stupidpython
api_spec = API_Spec()
return AutoCallpoint
class CallError(Exception):
exceptions = {}
def __new__(cls, *args, **kw):
call_error = kw.get('call_error', None)
if call_error is None:
call_error = cls.__name__
else:
call_error = str(call_error)
cls = CallError.exceptions.get(call_error, cls)
self = Exception.__new__(cls)
return self
def __init__(self, *args, **kw):
self.call_error = kw.get('call_error', self.__class__.__name__)
self.args = args
def __str__(self):
return '\n--------\n'.join(str(x) for x in self.args)
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__,
','.join(str(x) for x in self.args))
@classmethod
def from_exception(cls, exc):
args = None
try:
args = tuple(exc.args)
except (TypeError, AttributeError), e:
pass
if args is None:
args = (str(exc),)
self = cls(*args, call_error=exc.__class__.__name__)
return self
def to_dict(self):
return {'call_error': self.call_error,
'error_args': self.args}
@classmethod
def from_dict(cls, dictobj):
args = None
try:
if 'error_args' in dictobj and 'call_error' in dictobj:
args = dictobj['error_args']
call_error = dictobj['call_error']
except TypeError, e:
pass
if args is None:
args = (str(dictobj),)
call_error = 'UnknownError'
self = cls(*args, call_error=call_error)
return self
def register_exceptions(*exceptions):
for exception in exceptions:
if not issubclass(exception, CallError):
m = "Registering '%s': is not a CallError subclass" % (exception,)
raise ValueError(m)
CallError.exceptions[exception.__name__] = exception
def register_exception(exc):
register_exceptions(exc)
return exc
@register_exception
class CorruptedError(CallError):
pass
@register_exception
class InvalidDataError(CallError):
pass
from imp import find_module, load_module
_modules = {}
def imp_module(fullname):
if fullname in _modules:
return _modules[fullname]
components = fullname.split('.')
if not components:
raise ValueError('invalid module name')
module = None
modulepath = []
for name in components:
if not name:
raise ValueError("Relative paths not allowed")
modulepath.append(name)
modulename = '.'.join(modulepath)
if modulename in _modules:
module = _modules[modulename]
elif hasattr(module, name):
module = getattr(module, name)
elif not hasattr(module, '__path__'):
m = find_module(name)
module = load_module(modulename, *m)
else:
try:
m = find_module(name, module.__path__)
module = load_module(modulename, *m)
except ImportError:
m = "No module '%s' in '%s'" % (name, module.__path__)
raise ImportError(m)
_modules[modulename] = module
return module
def list_modules():
return sorted(_modules.keys())
This diff is collapsed.
try:
from collections import OrderedDict
except ImportError:
from commissioning.utils.ordereddict import OrderedDict
from itertools import chain
from cStringIO import StringIO
class arguments(object):
__slots__ = ('args', 'kw')
def __init__(self, *args, **kwargs):
self.args = list(args)
kw = OrderedDict()
kwitems = kw.pop('kwitems', None)
if kwitems is not None:
kw.update(kwitems)
kw.update(kwargs)
self.kw = kw
def __str__(self):
return str(self.args) + '+' + str(self.kw)
def __repr__(self):
return repr(self.args) + '+' + repr(self.kw)
def __getitem__(self, key):
if (isinstance(key, int)
or isinstance(key, long)
or isinstance(key, slice)):
return self.args[key]
else:
return self.kw[key]
def __setitem__(self, key, value):
if (isinstance(key, int)
or isinstance(key, long)
or isinstance(key, slice)):
self.args[key] = value
else:
self.kw[key] = value
def __delitem__(self, key):
if (isinstance(key, int)
or isinstance(key, long)
or isinstance(key, slice)):
del self.args[key]
else:
del self.kw[key]
def iteritems(self):
for item in self.args:
yield None, item
for k, v in self.kw:
yield k, v
def items(self):
return list(self.iteritems())
def iterkeys(self):
return self.kw.iterkeys()
def keys(self):
return self.kw.keys()
def itervalues(self):
return chain(self.args, self.kw.itervalues())
def values(self):
return list(self.itervalues)
def append(self, value):
self.args.append(value)
def betteron_encode(obj, output):
if obj is None:
output('[=null]')
return
if isinstance(obj, basestring):
if not obj:
output('""')
if isinstance(obj, unicode):
obj = obj.encode('utf-8')
output('"')
start = 0
while 1:
end = obj.find(start) + 1
if end < 0:
break
output(obj[start:end] + '"')
start = end
output(obj[start:])
output('"')
return
if isinstance(obj, int) or isinstance(obj, long):
output(str(obj))
return
if hasattr(obj, 'iteritems'):
output('[')
once = 1
for k, v in obj.iteritems():
if once:
once = 0
else:
output(' ')
if k is not None:
betteron_encode(k)
output('=')
betteron_encode(v)
output(']')
if hasattr(obj, '__iter__'):
output('[')
once = 1
for item in obj:
if once:
once = 0
else:
output(' ')
betteron_encode(item)
output(']')
m = "Unsupported type '%s'" % (type(obj))
def betteron_decode(inputf, s=None):
if isinstance(inputf, str):
inputf = StringIO(inputf).read
if s is None:
s = inputf(1)
while 1:
if not s.isspace():
break
s = inputf(1)
item = ''
if s == '"':
s = inputf(1)
while 1:
if s == '"':
s = inputf(1)
if s != '"':
return item, s
item += s
s = inputf(1)
elif s == '[':
item, s = betteron_decode_args(inputf)
return item, s
else:
while 1:
item += s
s = inputf(1)
if s in ' =]':
return item, s
def betteron_decode_atom(inputf):
s = inputf(4)
if s != 'null':
m = "Invalid atom '%s'" % (s,)
raise ValueError(m)
return None, None
def betteron_decode_args(inputf):
args = []
append = args.append
s = inputf(1)
key = None
while 1:
if s is None:
s = inputf(1)
if s == ']':
if key is not None:
append((None, key))
return args, None
if s == '=':
if key is None:
atom, s = betteron_decode_atom(inputf)
append((None, atom))
else:
value, s = betteron_decode(inputf)
append((key, value))
key = None
elif s == ' ':
if key is not None:
append((None, key))
key = None
s = inputf(1)
elif s == '':
m = "EOF while scanning for ']'"
raise ValueError(m)
else:
if key is not None:
append((None, key))
key, s = betteron_decode(inputf, s=s)
#!/usr/bin/env python
import re
keywords = set(['true', 'false', 'null'])
unquoted = set('{}[]"\'0123456789')
name_matcher = re.compile('^[\w @_.+-]+$', re.UNICODE)
def is_name(token):
if name_matcher.match(token):
return 1
return 0
def quote(token, is_dict):
if not token:
return '""'
if not is_name(token[0]):