Statistics
| Branch: | Tag: | Revision:

root / lib / outils.py @ 185192f2

History | View | Annotate | Download (4.5 kB)

1
#
2
#
3

    
4
# Copyright (C) 2012 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21
"""Module for object related utils."""
22

    
23

    
24
#: Supported container types for serialization/de-serialization (must be a
25
#: tuple as it's used as a parameter for C{isinstance})
26
_SEQUENCE_TYPES = (list, tuple, set, frozenset)
27

    
28

    
29
class AutoSlots(type):
30
  """Meta base class for __slots__ definitions.
31

32
  """
33
  def __new__(mcs, name, bases, attrs):
34
    """Called when a class should be created.
35

36
    @param mcs: The meta class
37
    @param name: Name of created class
38
    @param bases: Base classes
39
    @type attrs: dict
40
    @param attrs: Class attributes
41

42
    """
43
    assert "__slots__" not in attrs, \
44
      "Class '%s' defines __slots__ when it should not" % name
45

    
46
    attrs["__slots__"] = mcs._GetSlots(attrs)
47

    
48
    return type.__new__(mcs, name, bases, attrs)
49

    
50
  @classmethod
51
  def _GetSlots(mcs, attrs):
52
    """Used to get the list of defined slots.
53

54
    @param attrs: The attributes of the class
55

56
    """
57
    raise NotImplementedError
58

    
59

    
60
class ValidatedSlots(object):
61
  """Sets and validates slots.
62

63
  """
64
  __slots__ = []
65

    
66
  def __init__(self, **kwargs):
67
    """Constructor for BaseOpCode.
68

69
    The constructor takes only keyword arguments and will set
70
    attributes on this object based on the passed arguments. As such,
71
    it means that you should not pass arguments which are not in the
72
    __slots__ attribute for this class.
73

74
    """
75
    slots = self.GetAllSlots()
76
    for (key, value) in kwargs.items():
77
      if key not in slots:
78
        raise TypeError("Object %s doesn't support the parameter '%s'" %
79
                        (self.__class__.__name__, key))
80
      setattr(self, key, value)
81

    
82
  @classmethod
83
  def GetAllSlots(cls):
84
    """Compute the list of all declared slots for a class.
85

86
    """
87
    slots = []
88
    for parent in cls.__mro__:
89
      slots.extend(getattr(parent, "__slots__", []))
90
    return slots
91

    
92
  def Validate(self):
93
    """Validates the slots.
94

95
    This method returns L{None} if the validation succeeds, or raises
96
    an exception otherwise.
97

98
    @rtype: NoneType
99
    @return: L{None}, if the validation succeeds
100

101
    @raise Exception: validation fails
102

103
    This method must be implemented by the child classes.
104

105
    """
106
    raise NotImplementedError
107

    
108

    
109
def ContainerToDicts(container):
110
  """Convert the elements of a container to standard Python types.
111

112
  This method converts a container with elements to standard Python types. If
113
  the input container is of the type C{dict}, only its values are touched.
114
  Those values, as well as all elements of input sequences, must support a
115
  C{ToDict} method returning a serialized version.
116

117
  @type container: dict or sequence (see L{_SEQUENCE_TYPES})
118

119
  """
120
  if isinstance(container, dict):
121
    ret = dict([(k, v.ToDict()) for k, v in container.items()])
122
  elif isinstance(container, _SEQUENCE_TYPES):
123
    ret = [elem.ToDict() for elem in container]
124
  else:
125
    raise TypeError("Unknown container type '%s'" % type(container))
126

    
127
  return ret
128

    
129

    
130
def ContainerFromDicts(source, c_type, e_type):
131
  """Convert a container from standard python types.
132

133
  This method converts a container with standard Python types to objects. If
134
  the container is a dict, we don't touch the keys, only the values.
135

136
  @type source: None, dict or sequence (see L{_SEQUENCE_TYPES})
137
  @param source: Input data
138
  @type c_type: type class
139
  @param c_type: Desired type for returned container
140
  @type e_type: element type class
141
  @param e_type: Item type for elements in returned container (must have a
142
    C{FromDict} class method)
143

144
  """
145
  if not isinstance(c_type, type):
146
    raise TypeError("Container type '%s' is not a type" % type(c_type))
147

    
148
  if source is None:
149
    source = c_type()
150

    
151
  if c_type is dict:
152
    ret = dict([(k, e_type.FromDict(v)) for k, v in source.items()])
153
  elif c_type in _SEQUENCE_TYPES:
154
    ret = c_type(map(e_type.FromDict, source))
155
  else:
156
    raise TypeError("Unknown container type '%s'" % c_type)
157

    
158
  return ret