PageRenderTime 26ms CodeModel.GetById 11ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/gdata/spreadsheets/data.py

http://radioappz.googlecode.com/
Python | 317 lines | 218 code | 42 blank | 57 comment | 0 complexity | a5aa5c40b800bfa223b3587e6261fc35 MD5 | raw file
  1#!/usr/bin/env python
  2#
  3# Copyright (C) 2009 Google Inc.
  4#
  5# Licensed under the Apache License, Version 2.0 (the "License");
  6# you may not use this file except in compliance with the License.
  7# You may obtain a copy of the License at
  8#
  9#      http://www.apache.org/licenses/LICENSE-2.0
 10#
 11# Unless required by applicable law or agreed to in writing, software
 12# distributed under the License is distributed on an "AS IS" BASIS,
 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14# See the License for the specific language governing permissions and
 15# limitations under the License.
 16
 17
 18# This module is used for version 2 of the Google Data APIs.
 19
 20
 21"""Provides classes and constants for the XML in the Google Spreadsheets API.
 22
 23Documentation for the raw XML which these classes represent can be found here:
 24http://code.google.com/apis/spreadsheets/docs/3.0/reference.html#Elements
 25"""
 26
 27
 28__author__ = 'j.s@google.com (Jeff Scudder)'
 29
 30
 31import atom.core
 32import gdata.data
 33
 34
 35GS_TEMPLATE = '{http://schemas.google.com/spreadsheets/2006}%s'
 36GSX_NAMESPACE = 'http://schemas.google.com/spreadsheets/2006/extended'
 37
 38
 39INSERT_MODE = 'insert'
 40OVERWRITE_MODE = 'overwrite'
 41
 42
 43WORKSHEETS_REL = 'http://schemas.google.com/spreadsheets/2006#worksheetsfeed'
 44
 45
 46class Error(Exception):
 47  pass
 48
 49
 50class FieldMissing(Exception):
 51  pass
 52
 53
 54class HeaderNotSet(Error):
 55  """The desired column header had no value for the row in the list feed."""
 56
 57
 58class Cell(atom.core.XmlElement):
 59  """The gs:cell element.
 60
 61  A cell in the worksheet. The <gs:cell> element can appear only as a child
 62  of <atom:entry>.
 63  """
 64  _qname = GS_TEMPLATE % 'cell'
 65  col = 'col'
 66  input_value = 'inputValue'
 67  numeric_value = 'numericValue'
 68  row = 'row'
 69
 70
 71class ColCount(atom.core.XmlElement):
 72  """The gs:colCount element.
 73
 74  Indicates the number of columns in the worksheet, including columns that
 75  contain only empty cells. The <gs:colCount> element can appear as a child
 76  of <atom:entry> or <atom:feed>
 77  """
 78  _qname = GS_TEMPLATE % 'colCount'
 79
 80
 81class Field(atom.core.XmlElement):
 82  """The gs:field element.
 83
 84  A field single cell within a record. Contained in an <atom:entry>.
 85  """
 86  _qname = GS_TEMPLATE % 'field'
 87  index = 'index'
 88  name = 'name'
 89
 90
 91class Column(Field):
 92  """The gs:column element."""
 93  _qname = GS_TEMPLATE % 'column'
 94
 95
 96class Data(atom.core.XmlElement):
 97  """The gs:data element.
 98
 99  A data region of a table. Contained in an <atom:entry> element.
100  """
101  _qname = GS_TEMPLATE % 'data'
102  column = [Column]
103  insertion_mode = 'insertionMode'
104  num_rows = 'numRows'
105  start_row = 'startRow'
106
107
108class Header(atom.core.XmlElement):
109  """The gs:header element.
110
111  Indicates which row is the header row. Contained in an <atom:entry>.
112  """
113  _qname = GS_TEMPLATE % 'header'
114  row = 'row'
115
116
117class RowCount(atom.core.XmlElement):
118  """The gs:rowCount element.
119
120  Indicates the number of total rows in the worksheet, including rows that
121  contain only empty cells. The <gs:rowCount> element can appear as a
122  child of <atom:entry> or <atom:feed>.
123  """
124  _qname = GS_TEMPLATE % 'rowCount'
125
126
127class Worksheet(atom.core.XmlElement):
128  """The gs:worksheet element.
129
130  The worksheet where the table lives.Contained in an <atom:entry>.
131  """
132  _qname = GS_TEMPLATE % 'worksheet'
133  name = 'name'
134
135
136class Spreadsheet(gdata.data.GDEntry):
137  """An Atom entry which represents a Google Spreadsheet."""
138
139  def find_worksheets_feed(self):
140    return self.find_url(WORKSHEETS_REL)
141
142  FindWorksheetsFeed = find_worksheets_feed
143
144
145class SpreadsheetsFeed(gdata.data.GDFeed):
146  """An Atom feed listing a user's Google Spreadsheets."""
147  entry = [Spreadsheet]
148
149
150class WorksheetEntry(gdata.data.GDEntry):
151  """An Atom entry representing a single worksheet in a spreadsheet."""
152  row_count = RowCount
153  col_count = ColCount
154
155
156class WorksheetsFeed(gdata.data.GDFeed):
157  """A feed containing the worksheets in a single spreadsheet."""
158  entry = [WorksheetEntry]
159
160
161class Table(gdata.data.GDEntry):
162  """An Atom entry that represents a subsection of a worksheet.
163
164  A table allows you to treat part or all of a worksheet somewhat like a
165  table in a database that is, as a set of structured data items. Tables
166  don't exist until you explicitly create them before you can use a table
167  feed, you have to explicitly define where the table data comes from.
168  """
169  data = Data
170  header = Header
171  worksheet = Worksheet
172
173  def get_table_id(self):
174    if self.id.text:
175      return self.id.text.split('/')[-1]
176    return None
177
178  GetTableId = get_table_id
179
180
181class TablesFeed(gdata.data.GDFeed):
182  """An Atom feed containing the tables defined within a worksheet."""
183  entry = [Table]
184
185
186class Record(gdata.data.GDEntry):
187  """An Atom entry representing a single record in a table.
188
189  Note that the order of items in each record is the same as the order of
190  columns in the table definition, which may not match the order of
191  columns in the GUI.
192  """
193  field = [Field]
194
195  def value_for_index(self, column_index):
196    for field in self.field:
197      if field.index == column_index:
198        return field.text
199    raise FieldMissing('There is no field for %s' % column_index)
200
201  ValueForIndex = value_for_index
202
203  def value_for_name(self, name):
204    for field in self.field:
205      if field.name == name:
206        return field.text
207    raise FieldMissing('There is no field for %s' % name)
208
209  ValueForName = value_for_name
210
211  def get_record_id(self):
212    if self.id.text:
213      return self.id.text.split('/')[-1]
214    return None
215
216
217class RecordsFeed(gdata.data.GDFeed):
218  """An Atom feed containing the individuals records in a table."""
219  entry = [Record]
220
221
222class ListRow(atom.core.XmlElement):
223  """A gsx column value within a row.
224
225  The local tag in the _qname is blank and must be set to the column
226  name. For example, when adding to a ListEntry, do:
227  col_value = ListRow(text='something')
228  col_value._qname = col_value._qname % 'mycolumnname'
229  """
230  _qname = '{http://schemas.google.com/spreadsheets/2006/extended}%s'
231
232
233class ListEntry(gdata.data.GDEntry):
234  """An Atom entry representing a worksheet row in the list feed.
235
236  The values for a particular column can be get and set using
237  x.get_value('columnheader') and x.set_value('columnheader', 'value').
238  See also the explanation of column names in the ListFeed class.
239  """
240
241  def get_value(self, column_name):
242    """Returns the displayed text for the desired column in this row.
243
244    The formula or input which generated the displayed value is not accessible
245    through the list feed, to see the user's input, use the cells feed.
246
247    If a column is not present in this spreadsheet, or there is no value
248    for a column in this row, this method will return None.
249    """
250    values = self.get_elements(column_name, GSX_NAMESPACE)
251    if len(values) == 0:
252      return None
253    return values[0].text
254
255  def set_value(self, column_name, value):
256    """Changes the value of cell in this row under the desired column name.
257
258    Warning: if the cell contained a formula, it will be wiped out by setting
259    the value using the list feed since the list feed only works with
260    displayed values.
261
262    No client side checking is performed on the column_name, you need to
263    ensure that the column_name is the local tag name in the gsx tag for the
264    column. For example, the column_name will not contain special characters,
265    spaces, uppercase letters, etc.
266    """
267    # Try to find the column in this row to change an existing value.
268    values = self.get_elements(column_name, GSX_NAMESPACE)
269    if len(values) > 0:
270      values[0].text = value
271    else:
272      # There is no value in this row for the desired column, so add a new
273      # gsx:column_name element.
274      new_value = ListRow(text=value)
275      new_value._qname = new_value._qname % (column_name,)
276      self._other_elements.append(new_value)
277
278
279class ListsFeed(gdata.data.GDFeed):
280  """An Atom feed in which each entry represents a row in a worksheet.
281
282  The first row in the worksheet is used as the column names for the values
283  in each row. If a header cell is empty, then a unique column ID is used
284  for the gsx element name.
285
286  Spaces in a column name are removed from the name of the corresponding
287  gsx element.
288
289  Caution: The columnNames are case-insensitive. For example, if you see
290  a <gsx:e-mail> element in a feed, you can't know whether the column
291  heading in the original worksheet was "e-mail" or "E-Mail".
292
293  Note: If two or more columns have the same name, then subsequent columns
294  of the same name have _n appended to the columnName. For example, if the
295  first column name is "e-mail", followed by columns named "E-Mail" and
296  "E-mail", then the columnNames will be gsx:e-mail, gsx:e-mail_2, and
297  gsx:e-mail_3 respectively.
298  """
299  entry = [ListEntry]
300
301
302class CellEntry(gdata.data.BatchEntry):
303  """An Atom entry representing a single cell in a worksheet."""
304  cell = Cell
305
306
307class CellsFeed(gdata.data.BatchFeed):
308  """An Atom feed contains one entry per cell in a worksheet.
309
310  The cell feed supports batch operations, you can send multiple cell
311  operations in one HTTP request.
312  """
313  entry = [CellEntry]
314
315  def batch_set_cell(row, col, input):
316    pass
317