#!/usr/bin/python # # Copyright (C) 2007 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Contains extensions to Atom objects used with Google Spreadsheets. """ __author__ = 'api.laurabeth@gmail.com (Laura Beth Lincoln)' try: from xml.etree import cElementTree as ElementTree except ImportError: try: import cElementTree as ElementTree except ImportError: try: from xml.etree import ElementTree except ImportError: from elementtree import ElementTree import atom import gdata import re import string # XML namespaces which are often used in Google Spreadsheets entities. GSPREADSHEETS_NAMESPACE = 'http://schemas.google.com/spreadsheets/2006' GSPREADSHEETS_TEMPLATE = '{http://schemas.google.com/spreadsheets/2006}%s' GSPREADSHEETS_EXTENDED_NAMESPACE = ('http://schemas.google.com/spreadsheets' '/2006/extended') GSPREADSHEETS_EXTENDED_TEMPLATE = ('{http://schemas.google.com/spreadsheets' '/2006/extended}%s') class ColCount(atom.AtomBase): """The Google Spreadsheets colCount element """ _tag = 'colCount' _namespace = GSPREADSHEETS_NAMESPACE _children = atom.AtomBase._children.copy() _attributes = atom.AtomBase._attributes.copy() def __init__(self, text=None, extension_elements=None, extension_attributes=None): self.text = text self.extension_elements = extension_elements or [] self.extension_attributes = extension_attributes or {} def ColCountFromString(xml_string): return atom.CreateClassFromXMLString(ColCount, xml_string) class RowCount(atom.AtomBase): """The Google Spreadsheets rowCount element """ _tag = 'rowCount' _namespace = GSPREADSHEETS_NAMESPACE _children = atom.AtomBase._children.copy() _attributes = atom.AtomBase._attributes.copy() def __init__(self, text=None, extension_elements=None, extension_attributes=None): self.text = text self.extension_elements = extension_elements or [] self.extension_attributes = extension_attributes or {} def RowCountFromString(xml_string): return atom.CreateClassFromXMLString(RowCount, xml_string) class Cell(atom.AtomBase): """The Google Spreadsheets cell element """ _tag = 'cell' _namespace = GSPREADSHEETS_NAMESPACE _children = atom.AtomBase._children.copy() _attributes = atom.AtomBase._attributes.copy() _attributes['row'] = 'row' _attributes['col'] = 'col' _attributes['inputValue'] = 'inputValue' _attributes['numericValue'] = 'numericValue' def __init__(self, text=None, row=None, col=None, inputValue=None, numericValue=None, extension_elements=None, extension_attributes=None): self.text = text self.row = row self.col = col self.inputValue = inputValue self.numericValue = numericValue self.extension_elements = extension_elements or [] self.extension_attributes = extension_attributes or {} def CellFromString(xml_string): return atom.CreateClassFromXMLString(Cell, xml_string) class Custom(atom.AtomBase): """The Google Spreadsheets custom element""" _namespace = GSPREADSHEETS_EXTENDED_NAMESPACE _children = atom.AtomBase._children.copy() _attributes = atom.AtomBase._attributes.copy() def __init__(self, column=None, text=None, extension_elements=None, extension_attributes=None): self.column = column # The name of the column self.text = text self.extension_elements = extension_elements or [] self.extension_attributes = extension_attributes or {} def _BecomeChildElement(self, tree): new_child = ElementTree.Element('') tree.append(new_child) new_child.tag = '{%s}%s' % (self.__class__._namespace, self.column) self._AddMembersToElementTree(new_child) def _ToElementTree(self): new_tree = ElementTree.Element('{%s}%s' % (self.__class__._namespace, self.column)) self._AddMembersToElementTree(new_tree) return new_tree def _HarvestElementTree(self, tree): namespace_uri, local_tag = string.split(tree.tag[1:], "}", 1) self.column = local_tag # Fill in the instance members from the contents of the XML tree. for child in tree: self._ConvertElementTreeToMember(child) for attribute, value in tree.attrib.iteritems(): self._ConvertElementAttributeToMember(attribute, value) self.text = tree.text def CustomFromString(xml_string): element_tree = ElementTree.fromstring(xml_string) return _CustomFromElementTree(element_tree) def _CustomFromElementTree(element_tree): namespace_uri, local_tag = string.split(element_tree.tag[1:], "}", 1) if namespace_uri == GSPREADSHEETS_EXTENDED_NAMESPACE: new_custom = Custom() new_custom._HarvestElementTree(element_tree) new_custom.column = local_tag return new_custom return None class SpreadsheetsSpreadsheet(gdata.GDataEntry): """A Google Spreadsheets flavor of a Spreadsheet Atom Entry """ _tag = 'entry' _namespace = atom.ATOM_NAMESPACE _children = gdata.GDataEntry._children.copy() _attributes = gdata.GDataEntry._attributes.copy() def __init__(self, author=None, category=None, content=None, contributor=None, atom_id=None, link=None, published=None, rights=None, source=None, summary=None, title=None, control=None, updated=None, text=None, extension_elements=None, extension_attributes=None): self.author = author or [] self.category = category or [] self.content = content self.contributor = contributor or [] self.id = atom_id self.link = link or [] self.published = published self.rights = rights self.source = source self.summary = summary self.control = control self.title = title self.updated = updated self.text = text self.extension_elements = extension_elements or [] self.extension_attributes = extension_attributes or {} def SpreadsheetsSpreadsheetFromString(xml_string): return atom.CreateClassFromXMLString(SpreadsheetsSpreadsheet, xml_string) class SpreadsheetsWorksheet(gdata.GDataEntry): """A Google Spreadsheets flavor of a Worksheet Atom Entry """ _tag = 'entry' _namespace = atom.ATOM_NAMESPACE _children = gdata.GDataEntry._children.copy() _attributes = gdata.GDataEntry._attributes.copy() _children['{%s}rowCount' % GSPREADSHEETS_NAMESPACE] = ('row_count', RowCount) _children['{%s}colCount' % GSPREADSHEETS_NAMESPACE] = ('col_count', ColCount) def __init__(self, author=None, category=None, content=None, contributor=None, atom_id=None, link=None, published=None, rights=None, source=None, summary=None, title=None, control=None, updated=None, row_count=None, col_count=None, text=None, extension_elements=None, extension_attributes=None): self.author = author or [] self.category = category or [] self.content = content self.contributor = contributor or [] self.id = atom_id self.link = link or [] self.published = published self.rights = rights self.source = source self.summary = summary self.control = control self.title = title self.updated = updated self.row_count = row_count self.col_count = col_count self.text = text self.extension_elements = extension_elements or [] self.extension_attributes = extension_attributes or {} def SpreadsheetsWorksheetFromString(xml_string): return atom.CreateClassFromXMLString(SpreadsheetsWorksheet, xml_string) class SpreadsheetsCell(gdata.BatchEntry): """A Google Spreadsheets flavor of a Cell Atom Entry """ _tag = 'entry' _namespace = atom.ATOM_NAMESPACE _children = gdata.BatchEntry._children.copy() _attributes = gdata.BatchEntry._attributes.copy() _children['{%s}cell' % GSPREADSHEETS_NAMESPACE] = ('cell', Cell) def __init__(self, author=None, category=None, content=None, contributor=None, atom_id=None, link=None, published=None, rights=None, source=None, summary=None, title=None, control=None, updated=None, cell=None, batch_operation=None, batch_id=None, batch_status=None, text=None, extension_elements=None, extension_attributes=None): self.author = author or [] self.category = category or [] self.content = content self.contributor = contributor or [] self.id = atom_id self.link = link or [] self.published = published self.rights = rights self.source = source self.summary = summary self.control = control self.title = title self.batch_operation = batch_operation self.batch_id = batch_id self.batch_status = batch_status self.updated = updated self.cell = cell self.text = text self.extension_elements = extension_elements or [] self.extension_attributes = extension_attributes or {} def SpreadsheetsCellFromString(xml_string): return atom.CreateClassFromXMLString(SpreadsheetsCell, xml_string) class SpreadsheetsList(gdata.GDataEntry): """A Google Spreadsheets flavor of a List Atom Entry """ _tag = 'entry' _namespace = atom.ATOM_NAMESPACE _children = gdata.GDataEntry._children.copy() _attributes = gdata.GDataEntry._attributes.copy() def __init__(self, author=None, category=None, content=None, contributor=None, atom_id=None, link=None, published=None, rights=None, source=None, summary=None, title=None, control=None, updated=None, custom=None, text=None, extension_elements=None, extension_attributes=None): self.author = author or [] self.category = category or [] self.content = content self.contributor = contributor or [] self.id = atom_id self.link = link or [] self.published = published self.rights = rights self.source = source self.summary = summary self.control = control self.title = title self.updated = updated self.custom = custom or {} self.text = text self.extension_elements = extension_elements or [] self.extension_attributes = extension_attributes or {} # We need to overwrite _ConvertElementTreeToMember to add special logic to # convert custom attributes to members def _ConvertElementTreeToMember(self, child_tree): # Find the element's tag in this class's list of child members if self.__class__._children.has_key(child_tree.tag): member_name = self.__class__._children[child_tree.tag][0] member_class = self.__class__._children[child_tree.tag][1] # If the class member is supposed to contain a list, make sure the # matching member is set to a list, then append the new member # instance to the list. if isinstance(member_class, list): if getattr(self, member_name) is None: setattr(self, member_name, []) getattr(self, member_name).append(atom._CreateClassFromElementTree( member_class[0], child_tree)) else: setattr(self, member_name, atom._CreateClassFromElementTree(member_class, child_tree)) elif child_tree.tag.find('{%s}' % GSPREADSHEETS_EXTENDED_NAMESPACE) == 0: # If this is in the custom namespace, make add it to the custom dict. name = child_tree.tag[child_tree.tag.index('}')+1:] custom = _CustomFromElementTree(child_tree) if custom: self.custom[name] = custom else: atom.ExtensionContainer._ConvertElementTreeToMember(self, child_tree) # We need to overwtite _AddMembersToElementTree to add special logic to # convert custom members to XML nodes. def _AddMembersToElementTree(self, tree): # Convert the members of this class which are XML child nodes. # This uses the class's _children dictionary to find the members which # should become XML child nodes. member_node_names = [values[0] for tag, values in self.__class__._children.iteritems()] for member_name in member_node_names: member = getattr(self, member_name) if member is None: pass elif isinstance(member, list): for instance in member: instance._BecomeChildElement(tree) else: member._BecomeChildElement(tree) # Convert the members of this class which are XML attributes. for xml_attribute, member_name in self.__class__._attributes.iteritems(): member = getattr(self, member_name) if member is not None: tree.attrib[xml_attribute] = member # Convert all special custom item attributes to nodes for name, custom in self.custom.iteritems(): custom._BecomeChildElement(tree) # Lastly, call the ExtensionContainers's _AddMembersToElementTree to # convert any extension attributes. atom.ExtensionContainer._AddMembersToElementTree(self, tree) def SpreadsheetsListFromString(xml_string): return atom.CreateClassFromXMLString(SpreadsheetsList, xml_string) element_tree = ElementTree.fromstring(xml_string) return _SpreadsheetsListFromElementTree(element_tree) class SpreadsheetsSpreadsheetsFeed(gdata.GDataFeed): """A feed containing Google Spreadsheets Spreadsheets""" _tag = 'feed' _namespace = atom.ATOM_NAMESPACE _children = gdata.GDataFeed._children.copy() _attributes = gdata.GDataFeed._attributes.copy() _children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', [SpreadsheetsSpreadsheet]) def SpreadsheetsSpreadsheetsFeedFromString(xml_string): return atom.CreateClassFromXMLString(SpreadsheetsSpreadsheetsFeed, xml_string) class SpreadsheetsWorksheetsFeed(gdata.GDataFeed): """A feed containing Google Spreadsheets Spreadsheets""" _tag = 'feed' _namespace = atom.ATOM_NAMESPACE _children = gdata.GDataFeed._children.copy() _attributes = gdata.GDataFeed._attributes.copy() _children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', [SpreadsheetsWorksheet]) def SpreadsheetsWorksheetsFeedFromString(xml_string): return atom.CreateClassFromXMLString(SpreadsheetsWorksheetsFeed, xml_string) class SpreadsheetsCellsFeed(gdata.BatchFeed): """A feed containing Google Spreadsheets Cells""" _tag = 'feed' _namespace = atom.ATOM_NAMESPACE _children = gdata.BatchFeed._children.copy() _attributes = gdata.BatchFeed._attributes.copy() _children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', [SpreadsheetsCell]) _children['{%s}rowCount' % GSPREADSHEETS_NAMESPACE] = ('row_count', RowCount) _children['{%s}colCount' % GSPREADSHEETS_NAMESPACE] = ('col_count', ColCount) def __init__(self, author=None, category=None, contributor=None, generator=None, icon=None, atom_id=None, link=None, logo=None, rights=None, subtitle=None, title=None, updated=None, entry=None, total_results=None, start_index=None, items_per_page=None, extension_elements=None, extension_attributes=None, text=None, row_count=None, col_count=None, interrupted=None): gdata.BatchFeed.__init__(self, author=author, category=category, contributor=contributor, generator=generator, icon=icon, atom_id=atom_id, link=link, logo=logo, rights=rights, subtitle=subtitle, title=title, updated=updated, entry=entry, total_results=total_results, start_index=start_index, items_per_page=items_per_page, extension_elements=extension_elements, extension_attributes=extension_attributes, text=text, interrupted=interrupted) self.row_count = row_count self.col_count = col_count def GetBatchLink(self): for link in self.link: if link.rel == 'http://schemas.google.com/g/2005#batch': return link return None def SpreadsheetsCellsFeedFromString(xml_string): return atom.CreateClassFromXMLString(SpreadsheetsCellsFeed, xml_string) class SpreadsheetsListFeed(gdata.GDataFeed): """A feed containing Google Spreadsheets Spreadsheets""" _tag = 'feed' _namespace = atom.ATOM_NAMESPACE _children = gdata.GDataFeed._children.copy() _attributes = gdata.GDataFeed._attributes.copy() _children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', [SpreadsheetsList]) def SpreadsheetsListFeedFromString(xml_string): return atom.CreateClassFromXMLString(SpreadsheetsListFeed, xml_string)