source: people/peter.buschman/backup_monitoring/dal/dbapi/dtuple.py

Last change on this file was 976, checked in by peter, on Dec 6, 2011 at 10:19:33 AM

Raw checkin of current NetBackup / TSM parsing code.

File size: 8.2 KB
Line 
1#
2# dtuple.py: Database Tuple handling
3#
4# Written by Greg Stein. Public Domain.
5# No Copyright, no Rights Reserved, and no Warranties.
6#
7# This module is maintained by Greg and is available at:
8# http://www.lyra.org/greg/python/dtuple.py
9#
10# Some discussion/usage of this module can be found at:
11# http://www.python.org/pipermail/db-sig/1996-January/000000.html
12# http://www.python.org/pipermail/db-sig/1997-January/000152.html
13# (and various other posts around these time frames)
14#
15# Since this isn't in any Python distribution yet, we'll use the CVS ID for
16# tracking:
17# $Id: dtuple.py,v 1.1 2004/09/27 16:43:51 pbuschman Exp $
18#
19
20class TupleDescriptor:
21 """Describes a return tuple from a DB-API fetch*() method.
22
23 Instances of this class are used to describe database tuples (which are
24 typically instances of DatabaseTuple or one of its derivative classes).
25 These instances specify the column names, formats, lengths, and other
26 relevant information about the items in a particular tuple. An instance
27 is typically shared between many database tuples (such as those returned
28 by a single query).
29
30 Note: the term database tuple is rather specific; in actuality the tuple
31 may have come from non-database sources and/or generated by a process
32 wholly unrelated to databases.
33
34 Note again: I'm open for new names for this and the DatabaseTuple class
35 and concept :-)
36 """
37
38 def __init__(self, desc):
39 """TupleDescriptor constructor.
40
41 An instance is created by passing a "descriptor" to fully specify the
42 information about the related database tuple. This descriptor takes the
43 form of a tuple or list where each element is a tuple. The first element
44 of this tuple is the name of the column. The following elements of the
45 tuple are used to describe the column (such as length, format,
46 significant
47 digits, etc).
48 """
49 self.desc = tuple(desc)
50 ### validate the names?
51 self.names = map(lambda x: x[0], desc)
52 self.namemap = { }
53 for i in range(len(self.names)):
54 self.namemap[self.names[i]] = i
55
56 def __len__(self):
57 """Returns the number of elements in the data object.
58
59 A tuple descriptor responds to __len__ to simplify some processing by
60 allowing the use of the len() builtin function.
61 """
62 return len(self.names)
63
64 def __repr__(self):
65 return '%s(%s)' % (self.__class__.__name__, repr(self.desc))
66 def __str__(self):
67 return str(self.desc)
68
69
70
71class DatabaseTuple:
72 """Wraps the return data from a DB-API fetch*() method.
73
74 Instances of this class are used to represent tuples of information,
75 typically returned by a database query. A TupleDescriptor is used as
76 a means of describing the information for a variety of access methods.
77 The tuple's information can be accessed via simple indexing, slices,
78 as a mapping where the keys are the column names (as defined by the
79 descriptor), or via attribute-based access (where the attribute names
80 are equivalent to the column names).
81
82 This object acts as a tuple, a list, a mapping, and an instance. To
83 retrieve "pure" tuples, lists, or mappings, the asTuple(), asList(),
84 and asMapping() methods may be used, each returning a value equal to
85 what this object pretends to be.
86
87 There exists a potential ambiguity between attempting to act as a list
88 or mapping and the attribute-based access to the data. In particular,
89 if the column names are 'index', 'count', 'keys', 'items', 'values', or
90 'has_key', then the attribute-based access will have precedence over
91 their related methods for lists and mappings. To actually use these
92 methods, simply apply them to the result of the asList() or asMapping()
93 methods.
94
95 Note that column names with leading underscores may interfere with
96 the implementation of this class, and as a result may not be accessible
97 via the attribute-access scheme. Also, column names of asTuple, asList,
98 and asMapping will be inaccessible via the attribute-access scheme
99 since those will always represent the methods. To access these columns,
100 the mapping interface can be used with the column name as the mapping
101 key.
102
103 Note that a database tuple acts as a tuple with respect to sub-scripted
104 assignment. TypeError exceptions will be raised for several situations,
105 and AttributeError may be raised for some methods that are intended
106 to mutate the data (list's 'sort' method) as these methods have not
107 been implemented.
108 """
109
110 def __init__(self, desc, data):
111 """DatabaseTuple constructor.
112
113 A DatabaseTuple is initialized with a TupleDescriptor and a tuple or
114 list specifying the data elements.
115 """
116 if len(desc) != len(data):
117 raise ValueError # descriptor does not seem to describe tuple
118 if type(desc) == type(()) or type(desc) == type([]):
119 desc = TupleDescriptor(desc)
120 self.__dict__['_desc_'] = desc
121 self.__dict__['_data_'] = tuple(data)
122
123 def __str__(self):
124 return str(self._data_)
125 def __repr__(self):
126 return '%s(%s,%s)' % (self.__class__.__name__,
127 repr(self._desc_),
128 repr(self._data_))
129
130 def __cmp__(self, other):
131 if type(self._data_) == type(other):
132 return cmp(self._data_, other)
133 if type(self._data_) == type( {} ):
134 return cmp(self.asMapping(), other)
135 if type(self._data_) == type( () ):
136 return cmp(self.asTuple(), other)
137 if type(self) == type(other): ### fix this: need to verify equal classes
138 return cmp(self._data_, other._data_)
139 return cmp(self._data_, other)
140
141 def __getattr__(self, name):
142 'Simulate attribute-access via column names'
143 return self._getvalue_(name)
144
145 def __setattr__(self, name, value):
146 'Simulate attribute-access via column names'
147 ### need to redirect into a db update
148 raise TypeError, "can't assign to this subscripted object"
149
150 def __getitem__(self, key):
151 'Simulate indexed (tuple/list) and mapping-style access'
152 if type(key) == type(1):
153 return self._data_[key]
154 return self._getvalue_(key)
155
156 def __setitem__(self, key, value):
157 'Simulate indexed (tuple/list) and mapping-style access'
158 if type(key) == type(1):
159 ### need to redirect into a db update of elem #key
160 raise TypeError, "can't assign to this subscripted object"
161 ### need to redirect into a db update of elem named key
162 raise TypeError, "can't assign to this subscripted object"
163
164 def __len__(self):
165 return len(self._data_)
166
167 def __getslice__(self, i, j):
168 'Simulate list/tuple slicing access'
169 return self._data_[i:j]
170
171 def __setslice__(self, i, j, list):
172 'Simulate list/tuple slicing access'
173 ### need to redirect into a db update of elems
174 raise TypeError, "can't assign to this subscripted object"
175
176 def _keys_(self):
177 "Simulate mapping's methods"
178 return self._desc_.names
179
180 def _has_key_(self, key):
181 "Simulate mapping's methods"
182 return key in self._desc_.names
183
184 def _items_(self):
185 "Simulate mapping's methods"
186 return self.asMapping().items()
187
188 def _count_(self, item):
189 "Simulate list's methods"
190 return self.asList().count(item)
191
192 def _index_(self, item):
193 "Simulate list's methods"
194 return self.asList().index(item)
195
196 def _getvalue_(self,name):
197 'Internal method for named-based value retrieval'
198 if name not in self._desc_.names:
199 if name == 'keys':
200 return self._keys_
201 if name == 'items':
202 return self._items_
203 if name == 'values':
204 return self.asList
205 if name == 'has_key':
206 return self._has_key_
207 if name == 'count':
208 return self._count_
209 if name == 'index':
210 return self._index_
211 raise AttributeError
212 return self._data_[self._desc_.namemap[name]]
213
214 def asMapping(self):
215 'Return the "tuple" as a real mapping'
216 value = { }
217 for name, idx in self._desc_.namemap.items():
218 value[name] = self._data_[idx]
219 return value
220
221 def asTuple(self):
222 'Return the "tuple" as a real tuple'
223 return self._data_
224
225 def asList(self):
226 'Return the "list" as a real mapping'
227 return map(None, self._data_)
Note: See TracBrowser for help on using the repository browser.