Statistics
| Branch: | Tag: | Revision:

root / lib / outils.py @ 11e90588

History | View | Annotate | Download (4.3 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 must be implemented by the child classes.
96

97
    """
98
    raise NotImplementedError
99

    
100

    
101
def ContainerToDicts(container):
102
  """Convert the elements of a container to standard Python types.
103

104
  This method converts a container with elements to standard Python types. If
105
  the input container is of the type C{dict}, only its values are touched.
106
  Those values, as well as all elements of input sequences, must support a
107
  C{ToDict} method returning a serialized version.
108

109
  @type container: dict or sequence (see L{_SEQUENCE_TYPES})
110

111
  """
112
  if isinstance(container, dict):
113
    ret = dict([(k, v.ToDict()) for k, v in container.items()])
114
  elif isinstance(container, _SEQUENCE_TYPES):
115
    ret = [elem.ToDict() for elem in container]
116
  else:
117
    raise TypeError("Unknown container type '%s'" % type(container))
118

    
119
  return ret
120

    
121

    
122
def ContainerFromDicts(source, c_type, e_type):
123
  """Convert a container from standard python types.
124

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

128
  @type source: None, dict or sequence (see L{_SEQUENCE_TYPES})
129
  @param source: Input data
130
  @type c_type: type class
131
  @param c_type: Desired type for returned container
132
  @type e_type: element type class
133
  @param e_type: Item type for elements in returned container (must have a
134
    C{FromDict} class method)
135

136
  """
137
  if not isinstance(c_type, type):
138
    raise TypeError("Container type '%s' is not a type" % type(c_type))
139

    
140
  if source is None:
141
    source = c_type()
142

    
143
  if c_type is dict:
144
    ret = dict([(k, e_type.FromDict(v)) for k, v in source.items()])
145
  elif c_type in _SEQUENCE_TYPES:
146
    ret = c_type(map(e_type.FromDict, source))
147
  else:
148
    raise TypeError("Unknown container type '%s'" % c_type)
149

    
150
  return ret