X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=python%2Fovs%2Fdb%2Fdata.py;h=e21a1ccfaaa5a545150b01f33cec01e9378c3be7;hb=ec9f40dce11c7e81bc41d42e3bbfaaf8287165ce;hp=15a715135f2fc3bbbbd3edc42d2c3059125b3d6b;hpb=49c541dc1193528ff1a5f68ed7a69d3ddd4a00be;p=sliver-openvswitch.git diff --git a/python/ovs/db/data.py b/python/ovs/db/data.py index 15a715135..e21a1ccfa 100644 --- a/python/ovs/db/data.py +++ b/python/ovs/db/data.py @@ -1,4 +1,4 @@ -# Copyright (c) 2009, 2010, 2011 Nicira Networks +# Copyright (c) 2009, 2010, 2011 Nicira, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -25,10 +25,12 @@ import ovs.db.parser from ovs.db import error import ovs.db.types + class ConstraintViolation(error.Error): def __init__(self, msg, json=None): error.Error.__init__(self, msg, json, tag="constraint violation") + def escapeCString(src): dst = [] for c in src: @@ -55,9 +57,11 @@ def escapeCString(src): dst.append(c) return ''.join(dst) + def returnUnchanged(x): return x + class Atom(object): def __init__(self, type_, value=None): self.type = type_ @@ -81,6 +85,18 @@ class Atom(object): @staticmethod def default(type_): + """Returns the default value for the given type_, which must be an + instance of ovs.db.types.AtomicType. + + The default value for each atomic type is; + + - 0, for integer or real atoms. + + - False, for a boolean atom. + + - "", for a string atom. + + - The all-zeros UUID, for a UUID atom.""" return Atom(type_) def is_default(self): @@ -91,9 +107,11 @@ class Atom(object): type_ = base.type json = ovs.db.parser.float_to_int(json) if ((type_ == ovs.db.types.IntegerType and type(json) in [int, long]) - or (type_ == ovs.db.types.RealType and type(json) in [int, long, float]) + or (type_ == ovs.db.types.RealType + and type(json) in [int, long, float]) or (type_ == ovs.db.types.BooleanType and type(json) == bool) - or (type_ == ovs.db.types.StringType and type(json) in [str, unicode])): + or (type_ == ovs.db.types.StringType + and type(json) in [str, unicode])): atom = Atom(type_, json) elif type_ == ovs.db.types.UuidType: atom = Atom(type_, ovs.ovsuuid.from_json(json, symtab)) @@ -102,12 +120,21 @@ class Atom(object): atom.check_constraints(base) return atom + @staticmethod + def from_python(base, value): + value = ovs.db.parser.float_to_int(value) + if type(value) in base.type.python_types: + atom = Atom(base.type, value) + else: + raise error.Error("expected %s, got %s" % (base.type, type(value))) + atom.check_constraints(base) + return atom + def check_constraints(self, base): """Checks whether 'atom' meets the constraints (if any) defined in 'base' and raises an ovs.db.error.Error if any constraint is violated. 'base' and 'atom' must have the same type. - Checking UUID constraints is deferred to transaction commit time, so this function does nothing for UUID constraints.""" assert base.type == self.type @@ -144,7 +171,7 @@ class Atom(object): raise ConstraintViolation( '"%s" length %d is greater than maximum allowed ' 'length %d' % (s, length, base.max_length)) - + def to_json(self): if self.type == ovs.db.types.UuidType: return ovs.ovsuuid.to_json(self.value) @@ -183,6 +210,7 @@ class Atom(object): return self.value.value __need_quotes_re = re.compile("$|true|false|[^_a-zA-Z]|.*[^-._a-zA-Z]") + @staticmethod def __string_needs_quotes(s): return Atom.__need_quotes_re.match(s) @@ -221,6 +249,7 @@ class Atom(object): raise TypeError return Atom(t, x) + class Datum(object): def __init__(self, type_, values={}): self.type = type_ @@ -241,7 +270,7 @@ class Datum(object): def __contains__(self, item): return item in self.values - def clone(self): + def copy(self): return Datum(self.type, dict(self.values)) @staticmethod @@ -274,9 +303,9 @@ class Datum(object): """Parses 'json' as a datum of the type described by 'type'. If successful, returns a new datum. On failure, raises an ovs.db.error.Error. - + Violations of constraints expressed by 'type' are treated as errors. - + If 'symtab' is nonnull, then named UUIDs in 'symtab' are accepted. Refer to ovsdb/SPECS for information about this, and for the syntax that this function accepts.""" @@ -288,7 +317,8 @@ class Datum(object): else: class_ = "set" - inner = ovs.db.parser.unwrap_json(json, class_, list) + inner = ovs.db.parser.unwrap_json(json, class_, [list, tuple], + "array") n = len(inner) if n < type_.n_min or n > type_.n_max: raise error.Error("%s must have %d to %d members but %d are " @@ -361,7 +391,10 @@ class Datum(object): return [[k.value, v.value] for k, v in self.values.iteritems()] else: return [k.value for k in self.values.iterkeys()] - + + def as_dict(self): + return dict(self.values) + def as_scalar(self): if len(self.values) == 1: if self.type.is_map(): @@ -372,6 +405,97 @@ class Datum(object): else: return None + def to_python(self, uuid_to_row): + """Returns this datum's value converted into a natural Python + representation of this datum's type, according to the following + rules: + + - If the type has exactly one value and it is not a map (that is, + self.type.is_scalar() returns True), then the value is: + + * An int or long, for an integer column. + + * An int or long or float, for a real column. + + * A bool, for a boolean column. + + * A str or unicode object, for a string column. + + * A uuid.UUID object, for a UUID column without a ref_table. + + * An object represented the referenced row, for a UUID column with + a ref_table. (For the Idl, this object will be an ovs.db.idl.Row + object.) + + If some error occurs (e.g. the database server's idea of the column + is different from the IDL's idea), then the default value for the + scalar type is used (see Atom.default()). + + - Otherwise, if the type is not a map, then the value is a Python list + whose elements have the types described above. + + - Otherwise, the type is a map, and the value is a Python dict that + maps from key to value, with key and value types determined as + described above. + + 'uuid_to_row' must be a function that takes a value and an + ovs.db.types.BaseType and translates UUIDs into row objects.""" + if self.type.is_scalar(): + value = uuid_to_row(self.as_scalar(), self.type.key) + if value is None: + return self.type.key.default() + else: + return value + elif self.type.is_map(): + value = {} + for k, v in self.values.iteritems(): + dk = uuid_to_row(k.value, self.type.key) + dv = uuid_to_row(v.value, self.type.value) + if dk is not None and dv is not None: + value[dk] = dv + return value + else: + s = set() + for k in self.values: + dk = uuid_to_row(k.value, self.type.key) + if dk is not None: + s.add(dk) + return sorted(s) + + @staticmethod + def from_python(type_, value, row_to_uuid): + """Returns a new Datum with the given ovs.db.types.Type 'type_'. The + new datum's value is taken from 'value', which must take the form + described as a valid return value from Datum.to_python() for 'type'. + + Each scalar value within 'value' is initially passed through + 'row_to_uuid', which should convert objects that represent rows (if + any) into uuid.UUID objects and return other data unchanged. + + Raises ovs.db.error.Error if 'value' is not in an appropriate form for + 'type_'.""" + d = {} + if type(value) == dict: + for k, v in value.iteritems(): + ka = Atom.from_python(type_.key, row_to_uuid(k)) + va = Atom.from_python(type_.value, row_to_uuid(v)) + d[ka] = va + elif type(value) in (list, tuple): + for k in value: + ka = Atom.from_python(type_.key, row_to_uuid(k)) + d[ka] = None + else: + ka = Atom.from_python(type_.key, row_to_uuid(value)) + d[ka] = None + + datum = Datum(type_, d) + datum.check_constraints() + if not datum.conforms_to_type(): + raise error.Error("%d values when type requires between %d and %d" + % (len(d), type_.n_min, type_.n_max)) + + return datum + def __getitem__(self, key): if not isinstance(key, Atom): key = Atom.new(key) @@ -389,7 +513,7 @@ class Datum(object): return self.values[key].value else: return default - + def __str__(self): return self.to_string() @@ -407,7 +531,7 @@ class Datum(object): for i, key in enumerate(sorted(self.values)): s += key.cInitAtom("%s->keys[%d]" % (var, i)) - + if self.type.value: s += ["%s->values = xmalloc(%d * sizeof *%s->values);" % (var, len(self.values), var)]