X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=python%2Fovs%2Fdb%2Ftypes.py;h=fc9fc0a231d8a463a48f5c2d3b3d18d038e6d05d;hb=746cb7604e734c6e220c7a68218d8df50e692a56;hp=ded9f5f71eb88d813e2ff28acba7513f2788eba4;hpb=f2d8ad13e1819a6553b30ba33a28abf7603f5b9b;p=sliver-openvswitch.git diff --git a/python/ovs/db/types.py b/python/ovs/db/types.py index ded9f5f71..fc9fc0a23 100644 --- a/python/ovs/db/types.py +++ b/python/ovs/db/types.py @@ -1,4 +1,4 @@ -# Copyright (c) 2009, 2010, 2011 Nicira Networks +# Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,16 +13,19 @@ # limitations under the License. import sys +import uuid from ovs.db import error import ovs.db.parser import ovs.db.data import ovs.ovsuuid + class AtomicType(object): - def __init__(self, name, default): + def __init__(self, name, default, python_types): self.name = name self.default = default + self.python_types = python_types @staticmethod def from_string(s): @@ -30,16 +33,14 @@ class AtomicType(object): for atomic_type in ATOMIC_TYPES: if s == atomic_type.name: return atomic_type - raise error.Error('"%s" is not an atomic type' % s) + raise error.Error('"%s" is not an atomic-type' % s, s) @staticmethod def from_json(json): if type(json) not in [str, unicode]: raise error.Error("atomic-type expected", json) - try: + else: return AtomicType.from_string(json) - except error.Error: - raise error.Error('"%s" is not an atomic-type' % json, json) def __str__(self): return self.name @@ -53,16 +54,17 @@ class AtomicType(object): def default_atom(self): return ovs.db.data.Atom(self, self.default) -VoidType = AtomicType("void", None) -IntegerType = AtomicType("integer", 0) -RealType = AtomicType("real", 0.0) -BooleanType = AtomicType("boolean", False) -StringType = AtomicType("string", "") -UuidType = AtomicType("uuid", ovs.ovsuuid.UUID.zero()) +VoidType = AtomicType("void", None, ()) +IntegerType = AtomicType("integer", 0, (int, long)) +RealType = AtomicType("real", 0.0, (int, long, float)) +BooleanType = AtomicType("boolean", False, (bool,)) +StringType = AtomicType("string", "", (str, unicode)) +UuidType = AtomicType("uuid", ovs.ovsuuid.zero(), (uuid.UUID,)) ATOMIC_TYPES = [VoidType, IntegerType, RealType, BooleanType, StringType, UuidType] + def escapeCString(src): dst = "" for c in src: @@ -89,10 +91,13 @@ def escapeCString(src): dst += c return dst + def commafy(x): """Returns integer x formatted in decimal with thousands set off by commas.""" return _commafy("%d" % x) + + def _commafy(s): if s.startswith('-'): return '-' + _commafy(s[1:]) @@ -101,12 +106,14 @@ def _commafy(s): else: return _commafy(s[:-3]) + ',' + _commafy(s[-3:]) + def returnUnchanged(x): return x + class BaseType(object): def __init__(self, type_, enum=None, min=None, max=None, - min_length = 0, max_length=sys.maxint, ref_table=None): + min_length=0, max_length=sys.maxint, ref_table_name=None): assert isinstance(type_, AtomicType) self.type = type_ self.enum = enum @@ -114,7 +121,12 @@ class BaseType(object): self.max = max self.min_length = min_length self.max_length = max_length - self.ref_table = ref_table + self.ref_table_name = ref_table_name + if ref_table_name: + self.ref_type = 'strong' + else: + self.ref_type = None + self.ref_table = None def default(self): return ovs.db.data.Atom.default(self.type) @@ -126,7 +138,7 @@ class BaseType(object): self.min == other.min and self.max == other.max and self.min_length == other.min_length and self.max_length == other.max_length and - self.ref_table == other.ref_table) + self.ref_table_name == other.ref_table_name) def __ne__(self, other): if not isinstance(other, BaseType): @@ -140,15 +152,15 @@ class BaseType(object): if value is None: value = default else: - max_value = 2**32 - 1 - if value < 0 or value > max_value: + max_value = 2 ** 32 - 1 + if not (0 <= value <= max_value): raise error.Error("%s out of valid range 0 to %d" % (name, max_value), value) return value @staticmethod def from_json(json): - if type(json) == unicode: + if type(json) in [str, unicode]: return BaseType(AtomicType.from_json(json)) parser = ovs.db.parser.Parser(json, "ovsdb type") @@ -158,16 +170,19 @@ class BaseType(object): enum = parser.get_optional("enum", []) if enum is not None: - base.enum = ovs.db.data.Datum.from_json(BaseType.get_enum_type(base.type), enum) + base.enum = ovs.db.data.Datum.from_json( + BaseType.get_enum_type(base.type), enum) elif base.type == IntegerType: base.min = parser.get_optional("minInteger", [int, long]) base.max = parser.get_optional("maxInteger", [int, long]) - if base.min is not None and base.max is not None and base.min > base.max: + if (base.min is not None and base.max is not None + and base.min > base.max): raise error.Error("minInteger exceeds maxInteger", json) elif base.type == RealType: base.min = parser.get_optional("minReal", [int, long, float]) base.max = parser.get_optional("maxReal", [int, long, float]) - if base.min is not None and base.max is not None and base.min > base.max: + if (base.min is not None and base.max is not None + and base.min > base.max): raise error.Error("minReal exceeds maxReal", json) elif base.type == StringType: base.min_length = BaseType.__parse_uint(parser, "minLength", 0) @@ -176,8 +191,8 @@ class BaseType(object): if base.min_length > base.max_length: raise error.Error("minLength exceeds maxLength", json) elif base.type == UuidType: - base.ref_table = parser.get_optional("refTable", ['id']) - if base.ref_table: + base.ref_table_name = parser.get_optional("refTable", ['id']) + if base.ref_table_name: base.ref_type = parser.get_optional("refType", [str, unicode], "strong") if base.ref_type not in ['strong', 'weak']: @@ -212,15 +227,17 @@ class BaseType(object): if self.max_length != sys.maxint: json['maxLength'] = self.max_length elif self.type == UuidType: - if self.ref_table: - json['refTable'] = self.ref_table + if self.ref_table_name: + json['refTable'] = self.ref_table_name if self.ref_type != 'strong': json['refType'] = self.ref_type return json - def clone(self): - return BaseType(self.type, self.enum.clone(), self.min, self.max, - self.min_length, self.max_length, self.ref_table) + def copy(self): + base = BaseType(self.type, self.enum.copy(), self.min, self.max, + self.min_length, self.max_length, self.ref_table_name) + base.ref_table = self.ref_table + return base def is_valid(self): if self.type in (VoidType, BooleanType, UuidType): @@ -233,9 +250,10 @@ class BaseType(object): return False def has_constraints(self): - return (self.enum is not None or self.min is not None or self.max is not None or + return (self.enum is not None or self.min is not None or + self.max is not None or self.min_length != 0 or self.max_length != sys.maxint or - self.ref_table is not None) + self.ref_table_name is not None) def without_constraints(self): return BaseType(self.type) @@ -245,9 +263,9 @@ class BaseType(object): """Returns the type of the 'enum' member for a BaseType whose 'type' is 'atomic_type'.""" return Type(BaseType(atomic_type), None, 1, sys.maxint) - + def is_ref(self): - return self.type == UuidType and self.ref_table is not None + return self.type == UuidType and self.ref_table_name is not None def is_strong_ref(self): return self.is_ref() and self.ref_type == 'strong' @@ -256,55 +274,64 @@ class BaseType(object): return self.is_ref() and self.ref_type == 'weak' def toEnglish(self, escapeLiteral=returnUnchanged): - if self.type == UuidType and self.ref_table: - s = escapeLiteral(self.ref_table) + if self.type == UuidType and self.ref_table_name: + s = escapeLiteral(self.ref_table_name) if self.ref_type == 'weak': s = "weak reference to " + s return s else: return self.type.to_string() - def constraintsToEnglish(self, escapeLiteral=returnUnchanged): + def constraintsToEnglish(self, escapeLiteral=returnUnchanged, + escapeNumber=returnUnchanged): if self.enum: literals = [value.toEnglish(escapeLiteral) for value in self.enum.values] if len(literals) == 2: - return 'either %s or %s' % (literals[0], literals[1]) + english = 'either %s or %s' % (literals[0], literals[1]) else: - return 'one of %s, %s, or %s' % (literals[0], - ', '.join(literals[1:-1]), - literals[-1]) + english = 'one of %s, %s, or %s' % (literals[0], + ', '.join(literals[1:-1]), + literals[-1]) elif self.min is not None and self.max is not None: if self.type == IntegerType: - return 'in range %s to %s' % (commafy(self.min), - commafy(self.max)) + english = 'in range %s to %s' % ( + escapeNumber(commafy(self.min)), + escapeNumber(commafy(self.max))) else: - return 'in range %g to %g' % (self.min, self.max) + english = 'in range %s to %s' % ( + escapeNumber("%g" % self.min), + escapeNumber("%g" % self.max)) elif self.min is not None: if self.type == IntegerType: - return 'at least %s' % commafy(self.min) + english = 'at least %s' % escapeNumber(commafy(self.min)) else: - return 'at least %g' % self.min + english = 'at least %s' % escapeNumber("%g" % self.min) elif self.max is not None: if self.type == IntegerType: - return 'at most %s' % commafy(self.max) + english = 'at most %s' % escapeNumber(commafy(self.max)) else: - return 'at most %g' % self.max + english = 'at most %s' % escapeNumber("%g" % self.max) elif self.min_length != 0 and self.max_length != sys.maxint: if self.min_length == self.max_length: - return 'exactly %d characters long' % (self.min_length) + english = ('exactly %s characters long' + % commafy(self.min_length)) else: - return 'between %d and %d characters long' % (self.min_length, self.max_length) + english = ('between %s and %s characters long' + % (commafy(self.min_length), + commafy(self.max_length))) elif self.min_length != 0: - return 'at least %d characters long' % self.min_length + return 'at least %s characters long' % commafy(self.min_length) elif self.max_length != sys.maxint: - return 'at most %d characters long' % self.max_length + english = 'at most %s characters long' % commafy(self.max_length) else: - return '' + english = '' + + return english def toCType(self, prefix): - if self.ref_table: - return "struct %s%s *" % (prefix, self.ref_table.lower()) + if self.ref_table_name: + return "struct %s%s *" % (prefix, self.ref_table_name.lower()) else: return {IntegerType: 'int64_t ', RealType: 'double ', @@ -317,7 +344,7 @@ class BaseType(object): def copyCValue(self, dst, src): args = {'dst': dst, 'src': src} - if self.ref_table: + if self.ref_table_name: return ("%(dst)s = %(src)s->header_.uuid;") % args elif self.type == StringType: return "%(dst)s = xstrdup(%(src)s);" % args @@ -325,7 +352,7 @@ class BaseType(object): return "%(dst)s = %(src)s;" % args def initCDefault(self, var, is_optional): - if self.ref_table: + if self.ref_table_name: return "%s = NULL;" % var elif self.type == StringType and not is_optional: return '%s = "";' % var @@ -336,20 +363,22 @@ class BaseType(object): BooleanType: '%s = false;', StringType: '%s = NULL;'}[self.type] return pattern % var - + def cInitBaseType(self, indent, var): stmts = [] - stmts.append('ovsdb_base_type_init(&%s, OVSDB_TYPE_%s);' % ( - var, self.type.to_string().upper()),) + stmts.append('ovsdb_base_type_init(&%s, %s);' % ( + var, self.toAtomicType())) if self.enum: stmts.append("%s.enum_ = xmalloc(sizeof *%s.enum_);" % (var, var)) stmts += self.enum.cInitDatum("%s.enum_" % var) if self.type == IntegerType: if self.min is not None: - stmts.append('%s.u.integer.min = INT64_C(%d);' % (var, self.min)) + stmts.append('%s.u.integer.min = INT64_C(%d);' + % (var, self.min)) if self.max is not None: - stmts.append('%s.u.integer.max = INT64_C(%d);' % (var, self.max)) + stmts.append('%s.u.integer.max = INT64_C(%d);' + % (var, self.max)) elif self.type == RealType: if self.min is not None: stmts.append('%s.u.real.min = %d;' % (var, self.min)) @@ -357,28 +386,36 @@ class BaseType(object): stmts.append('%s.u.real.max = %d;' % (var, self.max)) elif self.type == StringType: if self.min_length is not None: - stmts.append('%s.u.string.minLen = %d;' % (var, self.min_length)) + stmts.append('%s.u.string.minLen = %d;' + % (var, self.min_length)) if self.max_length != sys.maxint: - stmts.append('%s.u.string.maxLen = %d;' % (var, self.max_length)) + stmts.append('%s.u.string.maxLen = %d;' + % (var, self.max_length)) elif self.type == UuidType: - if self.ref_table is not None: - stmts.append('%s.u.uuid.refTableName = "%s";' % (var, escapeCString(self.ref_table))) - stmts.append('%s.u.uuid.refType = OVSDB_REF_%s;' % (var, self.ref_type.upper())) + if self.ref_table_name is not None: + stmts.append('%s.u.uuid.refTableName = "%s";' + % (var, escapeCString(self.ref_table_name))) + stmts.append('%s.u.uuid.refType = OVSDB_REF_%s;' + % (var, self.ref_type.upper())) return '\n'.join([indent + stmt for stmt in stmts]) + class Type(object): - def __init__(self, key, value=None, n_min=1, n_max=1): + DEFAULT_MIN = 1 + DEFAULT_MAX = 1 + + def __init__(self, key, value=None, n_min=DEFAULT_MIN, n_max=DEFAULT_MAX): self.key = key self.value = value self.n_min = n_min self.n_max = n_max - def clone(self): + def copy(self): if self.value is None: value = None else: - value = self.value.clone() - return Type(self.key.clone(), value, self.n_min, self.n_max) + value = self.value.copy() + return Type(self.key.copy(), value, self.n_min, self.n_max) def __eq__(self, other): if not isinstance(other, Type): @@ -396,9 +433,7 @@ class Type(object): return (self.key.type != VoidType and self.key.is_valid() and (self.value is None or (self.value.type != VoidType and self.value.is_valid())) and - self.n_min <= 1 and - self.n_min <= self.n_max and - self.n_max >= 1) + self.n_min <= 1 <= self.n_max) def is_scalar(self): return self.n_min == 1 and self.n_max == 1 and not self.value @@ -417,25 +452,25 @@ class Type(object): def is_optional_pointer(self): return (self.is_optional() and not self.value - and (self.key.type == StringType or self.key.ref_table)) + and (self.key.type == StringType or self.key.ref_table_name)) @staticmethod def __n_from_json(json, default): if json is None: return default - elif type(json) == int and json >= 0 and json <= sys.maxint: + elif type(json) == int and 0 <= json <= sys.maxint: return json else: raise error.Error("bad min or max value", json) - + @staticmethod def from_json(json): if type(json) in [str, unicode]: return Type(BaseType.from_json(json)) parser = ovs.db.parser.Parser(json, "ovsdb type") - key_json = parser.get("key", [dict, unicode]) - value_json = parser.get_optional("value", [dict, unicode]) + key_json = parser.get("key", [dict, str, unicode]) + value_json = parser.get_optional("value", [dict, str, unicode]) min_json = parser.get_optional("min", [int]) max_json = parser.get_optional("max", [int, str, unicode]) parser.finish() @@ -446,12 +481,12 @@ class Type(object): else: value = None - n_min = Type.__n_from_json(min_json, 1) + n_min = Type.__n_from_json(min_json, Type.DEFAULT_MIN) if max_json == 'unlimited': n_max = sys.maxint else: - n_max = Type.__n_from_json(max_json, 1) + n_max = Type.__n_from_json(max_json, Type.DEFAULT_MAX) type_ = Type(key, value, n_min, n_max) if not type_.is_valid(): @@ -465,11 +500,11 @@ class Type(object): json = {"key": self.key.to_json()} if self.value is not None: json["value"] = self.value.to_json() - if self.n_min != 1: + if self.n_min != Type.DEFAULT_MIN: json["min"] = self.n_min if self.n_max == sys.maxint: json["max"] = "unlimited" - elif self.n_max != 1: + elif self.n_max != Type.DEFAULT_MAX: json["max"] = self.n_max return json @@ -488,13 +523,14 @@ class Type(object): else: if self.n_max == sys.maxint: if self.n_min: - quantity = "%d or more " % self.n_min + quantity = "%s or more " % commafy(self.n_min) else: quantity = "" elif self.n_min: - quantity = "%d to %d " % (self.n_min, self.n_max) + quantity = "%s to %s " % (commafy(self.n_min), + commafy(self.n_max)) else: - quantity = "up to %d " % self.n_max + quantity = "up to %s " % commafy(self.n_max) if self.value: return "map of %s%s-%s pairs" % (quantity, keyName, valueName) @@ -505,24 +541,25 @@ class Type(object): plural = keyName + "s" return "set of %s%s" % (quantity, plural) - def constraintsToEnglish(self, escapeLiteral=returnUnchanged): - s = "" - + def constraintsToEnglish(self, escapeLiteral=returnUnchanged, + escapeNumber=returnUnchanged): constraints = [] - keyConstraints = self.key.constraintsToEnglish(escapeLiteral) + keyConstraints = self.key.constraintsToEnglish(escapeLiteral, + escapeNumber) if keyConstraints: if self.value: - constraints += ['key ' + keyConstraints] + constraints.append('key %s' % keyConstraints) else: - constraints += [keyConstraints] + constraints.append(keyConstraints) if self.value: - valueConstraints = self.value.constraintsToEnglish(escapeLiteral) + valueConstraints = self.value.constraintsToEnglish(escapeLiteral, + escapeNumber) if valueConstraints: - constraints += ['value ' + valueConstraints] + constraints.append('value %s' % valueConstraints) return ', '.join(constraints) - + def cDeclComment(self): if self.n_min == 1 and self.n_max == 1 and self.key.type == StringType: return "\t/* Always nonnull. */" @@ -538,9 +575,8 @@ class Type(object): 'OVSDB_TYPE_VOID);' % (indent, var)) initMin = "%s%s.n_min = %s;" % (indent, var, self.n_min) if self.n_max == sys.maxint: - max = "UINT_MAX" + n_max = "UINT_MAX" else: - max = self.n_max - initMax = "%s%s.n_max = %s;" % (indent, var, max) + n_max = self.n_max + initMax = "%s%s.n_max = %s;" % (indent, var, n_max) return "\n".join((initKey, initValue, initMin, initMax)) -