/atom/__init__.py
http://radioappz.googlecode.com/ · Python · 1484 lines · 1191 code · 72 blank · 221 comment · 97 complexity · ef8e16177c6dfb17146d802edfceafe2 MD5 · raw file
- #!/usr/bin/python
- #
- # Copyright (C) 2006 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 classes representing Atom elements.
- Module objective: provide data classes for Atom constructs. These classes hide
- the XML-ness of Atom and provide a set of native Python classes to interact
- with.
- Conversions to and from XML should only be necessary when the Atom classes
- "touch the wire" and are sent over HTTP. For this reason this module
- provides methods and functions to convert Atom classes to and from strings.
- For more information on the Atom data model, see RFC 4287
- (http://www.ietf.org/rfc/rfc4287.txt)
- AtomBase: A foundation class on which Atom classes are built. It
- handles the parsing of attributes and children which are common to all
- Atom classes. By default, the AtomBase class translates all XML child
- nodes into ExtensionElements.
- ExtensionElement: Atom allows Atom objects to contain XML which is not part
- of the Atom specification, these are called extension elements. If a
- classes parser encounters an unexpected XML construct, it is translated
- into an ExtensionElement instance. ExtensionElement is designed to fully
- capture the information in the XML. Child nodes in an XML extension are
- turned into ExtensionElements as well.
- """
- __author__ = 'api.jscudder (Jeffrey Scudder)'
- 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 warnings
- # XML namespaces which are often used in Atom entities.
- ATOM_NAMESPACE = 'http://www.w3.org/2005/Atom'
- ELEMENT_TEMPLATE = '{http://www.w3.org/2005/Atom}%s'
- APP_NAMESPACE = 'http://purl.org/atom/app#'
- APP_TEMPLATE = '{http://purl.org/atom/app#}%s'
- # This encoding is used for converting strings before translating the XML
- # into an object.
- XML_STRING_ENCODING = 'utf-8'
- # The desired string encoding for object members. set or monkey-patch to
- # unicode if you want object members to be Python unicode strings, instead of
- # encoded strings
- MEMBER_STRING_ENCODING = 'utf-8'
- #MEMBER_STRING_ENCODING = unicode
- # If True, all methods which are exclusive to v1 will raise a
- # DeprecationWarning
- ENABLE_V1_WARNINGS = False
- def v1_deprecated(warning=None):
- """Shows a warning if ENABLE_V1_WARNINGS is True.
- Function decorator used to mark methods used in v1 classes which
- may be removed in future versions of the library.
- """
- warning = warning or ''
- # This closure is what is returned from the deprecated function.
- def mark_deprecated(f):
- # The deprecated_function wraps the actual call to f.
- def optional_warn_function(*args, **kwargs):
- if ENABLE_V1_WARNINGS:
- warnings.warn(warning, DeprecationWarning, stacklevel=2)
- return f(*args, **kwargs)
- # Preserve the original name to avoid masking all decorated functions as
- # 'deprecated_function'
- try:
- optional_warn_function.func_name = f.func_name
- except TypeError:
- pass # In Python2.3 we can't set the func_name
- return optional_warn_function
- return mark_deprecated
- def CreateClassFromXMLString(target_class, xml_string, string_encoding=None):
- """Creates an instance of the target class from the string contents.
- Args:
- target_class: class The class which will be instantiated and populated
- with the contents of the XML. This class must have a _tag and a
- _namespace class variable.
- xml_string: str A string which contains valid XML. The root element
- of the XML string should match the tag and namespace of the desired
- class.
- string_encoding: str The character encoding which the xml_string should
- be converted to before it is interpreted and translated into
- objects. The default is None in which case the string encoding
- is not changed.
- Returns:
- An instance of the target class with members assigned according to the
- contents of the XML - or None if the root XML tag and namespace did not
- match those of the target class.
- """
- encoding = string_encoding or XML_STRING_ENCODING
- if encoding and isinstance(xml_string, unicode):
- xml_string = xml_string.encode(encoding)
- tree = ElementTree.fromstring(xml_string)
- return _CreateClassFromElementTree(target_class, tree)
- CreateClassFromXMLString = v1_deprecated(
- 'Please use atom.core.parse with atom.data classes instead.')(
- CreateClassFromXMLString)
- def _CreateClassFromElementTree(target_class, tree, namespace=None, tag=None):
- """Instantiates the class and populates members according to the tree.
- Note: Only use this function with classes that have _namespace and _tag
- class members.
- Args:
- target_class: class The class which will be instantiated and populated
- with the contents of the XML.
- tree: ElementTree An element tree whose contents will be converted into
- members of the new target_class instance.
- namespace: str (optional) The namespace which the XML tree's root node must
- match. If omitted, the namespace defaults to the _namespace of the
- target class.
- tag: str (optional) The tag which the XML tree's root node must match. If
- omitted, the tag defaults to the _tag class member of the target
- class.
- Returns:
- An instance of the target class - or None if the tag and namespace of
- the XML tree's root node did not match the desired namespace and tag.
- """
- if namespace is None:
- namespace = target_class._namespace
- if tag is None:
- tag = target_class._tag
- if tree.tag == '{%s}%s' % (namespace, tag):
- target = target_class()
- target._HarvestElementTree(tree)
- return target
- else:
- return None
- class ExtensionContainer(object):
- def __init__(self, extension_elements=None, extension_attributes=None,
- text=None):
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- self.text = text
- __init__ = v1_deprecated(
- 'Please use data model classes in atom.data instead.')(
- __init__)
- # Three methods to create an object from an ElementTree
- def _HarvestElementTree(self, tree):
- # 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)
- # Encode the text string according to the desired encoding type. (UTF-8)
- if tree.text:
- if MEMBER_STRING_ENCODING is unicode:
- self.text = tree.text
- else:
- self.text = tree.text.encode(MEMBER_STRING_ENCODING)
- def _ConvertElementTreeToMember(self, child_tree, current_class=None):
- self.extension_elements.append(_ExtensionElementFromElementTree(
- child_tree))
- def _ConvertElementAttributeToMember(self, attribute, value):
- # Encode the attribute value's string with the desired type Default UTF-8
- if value:
- if MEMBER_STRING_ENCODING is unicode:
- self.extension_attributes[attribute] = value
- else:
- self.extension_attributes[attribute] = value.encode(
- MEMBER_STRING_ENCODING)
- # One method to create an ElementTree from an object
- def _AddMembersToElementTree(self, tree):
- for child in self.extension_elements:
- child._BecomeChildElement(tree)
- for attribute, value in self.extension_attributes.iteritems():
- if value:
- if isinstance(value, unicode) or MEMBER_STRING_ENCODING is unicode:
- tree.attrib[attribute] = value
- else:
- # Decode the value from the desired encoding (default UTF-8).
- tree.attrib[attribute] = value.decode(MEMBER_STRING_ENCODING)
- if self.text:
- if isinstance(self.text, unicode) or MEMBER_STRING_ENCODING is unicode:
- tree.text = self.text
- else:
- tree.text = self.text.decode(MEMBER_STRING_ENCODING)
- def FindExtensions(self, tag=None, namespace=None):
- """Searches extension elements for child nodes with the desired name.
- Returns a list of extension elements within this object whose tag
- and/or namespace match those passed in. To find all extensions in
- a particular namespace, specify the namespace but not the tag name.
- If you specify only the tag, the result list may contain extension
- elements in multiple namespaces.
- Args:
- tag: str (optional) The desired tag
- namespace: str (optional) The desired namespace
- Returns:
- A list of elements whose tag and/or namespace match the parameters
- values
- """
- results = []
- if tag and namespace:
- for element in self.extension_elements:
- if element.tag == tag and element.namespace == namespace:
- results.append(element)
- elif tag and not namespace:
- for element in self.extension_elements:
- if element.tag == tag:
- results.append(element)
- elif namespace and not tag:
- for element in self.extension_elements:
- if element.namespace == namespace:
- results.append(element)
- else:
- for element in self.extension_elements:
- results.append(element)
- return results
- class AtomBase(ExtensionContainer):
- _children = {}
- _attributes = {}
- def __init__(self, extension_elements=None, extension_attributes=None,
- text=None):
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- self.text = text
- __init__ = v1_deprecated(
- 'Please use data model classes in atom.data instead.')(
- __init__)
- 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(_CreateClassFromElementTree(
- member_class[0], child_tree))
- else:
- setattr(self, member_name,
- _CreateClassFromElementTree(member_class, child_tree))
- else:
- ExtensionContainer._ConvertElementTreeToMember(self, child_tree)
- def _ConvertElementAttributeToMember(self, attribute, value):
- # Find the attribute in this class's list of attributes.
- if self.__class__._attributes.has_key(attribute):
- # Find the member of this class which corresponds to the XML attribute
- # (lookup in current_class._attributes) and set this member to the
- # desired value (using self.__dict__).
- if value:
- # Encode the string to capture non-ascii characters (default UTF-8)
- if MEMBER_STRING_ENCODING is unicode:
- setattr(self, self.__class__._attributes[attribute], value)
- else:
- setattr(self, self.__class__._attributes[attribute],
- value.encode(MEMBER_STRING_ENCODING))
- else:
- ExtensionContainer._ConvertElementAttributeToMember(
- self, attribute, value)
- # Three methods to create an ElementTree from an object
- 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:
- if isinstance(member, unicode) or MEMBER_STRING_ENCODING is unicode:
- tree.attrib[xml_attribute] = member
- else:
- tree.attrib[xml_attribute] = member.decode(MEMBER_STRING_ENCODING)
- # Lastly, call the ExtensionContainers's _AddMembersToElementTree to
- # convert any extension attributes.
- ExtensionContainer._AddMembersToElementTree(self, tree)
- def _BecomeChildElement(self, tree):
- """
- Note: Only for use with classes that have a _tag and _namespace class
- member. It is in AtomBase so that it can be inherited but it should
- not be called on instances of AtomBase.
- """
- new_child = ElementTree.Element('')
- tree.append(new_child)
- new_child.tag = '{%s}%s' % (self.__class__._namespace,
- self.__class__._tag)
- self._AddMembersToElementTree(new_child)
- def _ToElementTree(self):
- """
- Note, this method is designed to be used only with classes that have a
- _tag and _namespace. It is placed in AtomBase for inheritance but should
- not be called on this class.
- """
- new_tree = ElementTree.Element('{%s}%s' % (self.__class__._namespace,
- self.__class__._tag))
- self._AddMembersToElementTree(new_tree)
- return new_tree
- def ToString(self, string_encoding='UTF-8'):
- """Converts the Atom object to a string containing XML."""
- return ElementTree.tostring(self._ToElementTree(), encoding=string_encoding)
- def __str__(self):
- return self.ToString()
- class Name(AtomBase):
- """The atom:name element"""
- _tag = 'name'
- _namespace = ATOM_NAMESPACE
- _children = AtomBase._children.copy()
- _attributes = AtomBase._attributes.copy()
- def __init__(self, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for Name
- Args:
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def NameFromString(xml_string):
- return CreateClassFromXMLString(Name, xml_string)
- class Email(AtomBase):
- """The atom:email element"""
- _tag = 'email'
- _namespace = ATOM_NAMESPACE
- _children = AtomBase._children.copy()
- _attributes = AtomBase._attributes.copy()
- def __init__(self, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for Email
- Args:
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- text: str The text data in the this element
- """
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def EmailFromString(xml_string):
- return CreateClassFromXMLString(Email, xml_string)
- class Uri(AtomBase):
- """The atom:uri element"""
- _tag = 'uri'
- _namespace = ATOM_NAMESPACE
- _children = AtomBase._children.copy()
- _attributes = AtomBase._attributes.copy()
- def __init__(self, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for Uri
- Args:
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- text: str The text data in the this element
- """
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def UriFromString(xml_string):
- return CreateClassFromXMLString(Uri, xml_string)
- class Person(AtomBase):
- """A foundation class from which atom:author and atom:contributor extend.
- A person contains information like name, email address, and web page URI for
- an author or contributor to an Atom feed.
- """
- _children = AtomBase._children.copy()
- _attributes = AtomBase._attributes.copy()
- _children['{%s}name' % (ATOM_NAMESPACE)] = ('name', Name)
- _children['{%s}email' % (ATOM_NAMESPACE)] = ('email', Email)
- _children['{%s}uri' % (ATOM_NAMESPACE)] = ('uri', Uri)
- def __init__(self, name=None, email=None, uri=None,
- extension_elements=None, extension_attributes=None, text=None):
- """Foundation from which author and contributor are derived.
- The constructor is provided for illustrative purposes, you should not
- need to instantiate a Person.
- Args:
- name: Name The person's name
- email: Email The person's email address
- uri: Uri The URI of the person's webpage
- extension_elements: list A list of ExtensionElement instances which are
- children of this element.
- extension_attributes: dict A dictionary of strings which are the values
- for additional XML attributes of this element.
- text: String The text contents of the element. This is the contents
- of the Entry's XML text node. (Example: <foo>This is the text</foo>)
- """
- self.name = name
- self.email = email
- self.uri = uri
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- self.text = text
- class Author(Person):
- """The atom:author element
- An author is a required element in Feed.
- """
- _tag = 'author'
- _namespace = ATOM_NAMESPACE
- _children = Person._children.copy()
- _attributes = Person._attributes.copy()
- #_children = {}
- #_attributes = {}
- def __init__(self, name=None, email=None, uri=None,
- extension_elements=None, extension_attributes=None, text=None):
- """Constructor for Author
- Args:
- name: Name
- email: Email
- uri: Uri
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- text: str The text data in the this element
- """
- self.name = name
- self.email = email
- self.uri = uri
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- self.text = text
- def AuthorFromString(xml_string):
- return CreateClassFromXMLString(Author, xml_string)
- class Contributor(Person):
- """The atom:contributor element"""
- _tag = 'contributor'
- _namespace = ATOM_NAMESPACE
- _children = Person._children.copy()
- _attributes = Person._attributes.copy()
- def __init__(self, name=None, email=None, uri=None,
- extension_elements=None, extension_attributes=None, text=None):
- """Constructor for Contributor
- Args:
- name: Name
- email: Email
- uri: Uri
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- text: str The text data in the this element
- """
- self.name = name
- self.email = email
- self.uri = uri
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- self.text = text
- def ContributorFromString(xml_string):
- return CreateClassFromXMLString(Contributor, xml_string)
- class Link(AtomBase):
- """The atom:link element"""
- _tag = 'link'
- _namespace = ATOM_NAMESPACE
- _children = AtomBase._children.copy()
- _attributes = AtomBase._attributes.copy()
- _attributes['rel'] = 'rel'
- _attributes['href'] = 'href'
- _attributes['type'] = 'type'
- _attributes['title'] = 'title'
- _attributes['length'] = 'length'
- _attributes['hreflang'] = 'hreflang'
- def __init__(self, href=None, rel=None, link_type=None, hreflang=None,
- title=None, length=None, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for Link
- Args:
- href: string The href attribute of the link
- rel: string
- type: string
- hreflang: string The language for the href
- title: string
- length: string The length of the href's destination
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- text: str The text data in the this element
- """
- self.href = href
- self.rel = rel
- self.type = link_type
- self.hreflang = hreflang
- self.title = title
- self.length = length
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def LinkFromString(xml_string):
- return CreateClassFromXMLString(Link, xml_string)
- class Generator(AtomBase):
- """The atom:generator element"""
- _tag = 'generator'
- _namespace = ATOM_NAMESPACE
- _children = AtomBase._children.copy()
- _attributes = AtomBase._attributes.copy()
- _attributes['uri'] = 'uri'
- _attributes['version'] = 'version'
- def __init__(self, uri=None, version=None, text=None,
- extension_elements=None, extension_attributes=None):
- """Constructor for Generator
- Args:
- uri: string
- version: string
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.uri = uri
- self.version = version
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def GeneratorFromString(xml_string):
- return CreateClassFromXMLString(Generator, xml_string)
- class Text(AtomBase):
- """A foundation class from which atom:title, summary, etc. extend.
- This class should never be instantiated.
- """
- _children = AtomBase._children.copy()
- _attributes = AtomBase._attributes.copy()
- _attributes['type'] = 'type'
- def __init__(self, text_type=None, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for Text
- Args:
- text_type: string
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.type = text_type
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- class Title(Text):
- """The atom:title element"""
- _tag = 'title'
- _namespace = ATOM_NAMESPACE
- _children = Text._children.copy()
- _attributes = Text._attributes.copy()
- def __init__(self, title_type=None, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for Title
- Args:
- title_type: string
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.type = title_type
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def TitleFromString(xml_string):
- return CreateClassFromXMLString(Title, xml_string)
- class Subtitle(Text):
- """The atom:subtitle element"""
- _tag = 'subtitle'
- _namespace = ATOM_NAMESPACE
- _children = Text._children.copy()
- _attributes = Text._attributes.copy()
- def __init__(self, subtitle_type=None, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for Subtitle
- Args:
- subtitle_type: string
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.type = subtitle_type
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def SubtitleFromString(xml_string):
- return CreateClassFromXMLString(Subtitle, xml_string)
- class Rights(Text):
- """The atom:rights element"""
- _tag = 'rights'
- _namespace = ATOM_NAMESPACE
- _children = Text._children.copy()
- _attributes = Text._attributes.copy()
- def __init__(self, rights_type=None, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for Rights
- Args:
- rights_type: string
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.type = rights_type
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def RightsFromString(xml_string):
- return CreateClassFromXMLString(Rights, xml_string)
- class Summary(Text):
- """The atom:summary element"""
- _tag = 'summary'
- _namespace = ATOM_NAMESPACE
- _children = Text._children.copy()
- _attributes = Text._attributes.copy()
- def __init__(self, summary_type=None, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for Summary
- Args:
- summary_type: string
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.type = summary_type
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def SummaryFromString(xml_string):
- return CreateClassFromXMLString(Summary, xml_string)
- class Content(Text):
- """The atom:content element"""
- _tag = 'content'
- _namespace = ATOM_NAMESPACE
- _children = Text._children.copy()
- _attributes = Text._attributes.copy()
- _attributes['src'] = 'src'
- def __init__(self, content_type=None, src=None, text=None,
- extension_elements=None, extension_attributes=None):
- """Constructor for Content
- Args:
- content_type: string
- src: string
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.type = content_type
- self.src = src
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def ContentFromString(xml_string):
- return CreateClassFromXMLString(Content, xml_string)
- class Category(AtomBase):
- """The atom:category element"""
- _tag = 'category'
- _namespace = ATOM_NAMESPACE
- _children = AtomBase._children.copy()
- _attributes = AtomBase._attributes.copy()
- _attributes['term'] = 'term'
- _attributes['scheme'] = 'scheme'
- _attributes['label'] = 'label'
- def __init__(self, term=None, scheme=None, label=None, text=None,
- extension_elements=None, extension_attributes=None):
- """Constructor for Category
- Args:
- term: str
- scheme: str
- label: str
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.term = term
- self.scheme = scheme
- self.label = label
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def CategoryFromString(xml_string):
- return CreateClassFromXMLString(Category, xml_string)
- class Id(AtomBase):
- """The atom:id element."""
- _tag = 'id'
- _namespace = ATOM_NAMESPACE
- _children = AtomBase._children.copy()
- _attributes = AtomBase._attributes.copy()
- def __init__(self, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for Id
- Args:
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def IdFromString(xml_string):
- return CreateClassFromXMLString(Id, xml_string)
- class Icon(AtomBase):
- """The atom:icon element."""
- _tag = 'icon'
- _namespace = ATOM_NAMESPACE
- _children = AtomBase._children.copy()
- _attributes = AtomBase._attributes.copy()
- def __init__(self, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for Icon
- Args:
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def IconFromString(xml_string):
- return CreateClassFromXMLString(Icon, xml_string)
- class Logo(AtomBase):
- """The atom:logo element."""
- _tag = 'logo'
- _namespace = ATOM_NAMESPACE
- _children = AtomBase._children.copy()
- _attributes = AtomBase._attributes.copy()
- def __init__(self, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for Logo
- Args:
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def LogoFromString(xml_string):
- return CreateClassFromXMLString(Logo, xml_string)
- class Draft(AtomBase):
- """The app:draft element which indicates if this entry should be public."""
- _tag = 'draft'
- _namespace = APP_NAMESPACE
- _children = AtomBase._children.copy()
- _attributes = AtomBase._attributes.copy()
- def __init__(self, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for app:draft
- Args:
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def DraftFromString(xml_string):
- return CreateClassFromXMLString(Draft, xml_string)
- class Control(AtomBase):
- """The app:control element indicating restrictions on publication.
- The APP control element may contain a draft element indicating whether or
- not this entry should be publicly available.
- """
- _tag = 'control'
- _namespace = APP_NAMESPACE
- _children = AtomBase._children.copy()
- _attributes = AtomBase._attributes.copy()
- _children['{%s}draft' % APP_NAMESPACE] = ('draft', Draft)
- def __init__(self, draft=None, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for app:control"""
- self.draft = draft
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def ControlFromString(xml_string):
- return CreateClassFromXMLString(Control, xml_string)
- class Date(AtomBase):
- """A parent class for atom:updated, published, etc."""
- #TODO Add text to and from time conversion methods to allow users to set
- # the contents of a Date to a python DateTime object.
- _children = AtomBase._children.copy()
- _attributes = 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 {}
- class Updated(Date):
- """The atom:updated element."""
- _tag = 'updated'
- _namespace = ATOM_NAMESPACE
- _children = Date._children.copy()
- _attributes = Date._attributes.copy()
- def __init__(self, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for Updated
- Args:
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def UpdatedFromString(xml_string):
- return CreateClassFromXMLString(Updated, xml_string)
- class Published(Date):
- """The atom:published element."""
- _tag = 'published'
- _namespace = ATOM_NAMESPACE
- _children = Date._children.copy()
- _attributes = Date._attributes.copy()
- def __init__(self, text=None, extension_elements=None,
- extension_attributes=None):
- """Constructor for Published
- Args:
- text: str The text data in the this element
- extension_elements: list A list of ExtensionElement instances
- extension_attributes: dict A dictionary of attribute value string pairs
- """
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def PublishedFromString(xml_string):
- return CreateClassFromXMLString(Published, xml_string)
- class LinkFinder(object):
- """An "interface" providing methods to find link elements
- Entry elements often contain multiple links which differ in the rel
- attribute or content type. Often, developers are interested in a specific
- type of link so this class provides methods to find specific classes of
- links.
- This class is used as a mixin in Atom entries and feeds.
- """
- def GetSelfLink(self):
- """Find the first link with rel set to 'self'
- Returns:
- An atom.Link or none if none of the links had rel equal to 'self'
- """
- for a_link in self.link:
- if a_link.rel == 'self':
- return a_link
- return None
- def GetEditLink(self):
- for a_link in self.link:
- if a_link.rel == 'edit':
- return a_link
- return None
- def GetEditMediaLink(self):
- for a_link in self.link:
- if a_link.rel == 'edit-media':
- return a_link
- return None
- def GetNextLink(self):
- for a_link in self.link:
- if a_link.rel == 'next':
- return a_link
- return None
- def GetLicenseLink(self):
- for a_link in self.link:
- if a_link.rel == 'license':
- return a_link
- return None
- def GetAlternateLink(self):
- for a_link in self.link:
- if a_link.rel == 'alternate':
- return a_link
- return None
- class FeedEntryParent(AtomBase, LinkFinder):
- """A super class for atom:feed and entry, contains shared attributes"""
- _children = AtomBase._children.copy()
- _attributes = AtomBase._attributes.copy()
- _children['{%s}author' % ATOM_NAMESPACE] = ('author', [Author])
- _children['{%s}category' % ATOM_NAMESPACE] = ('category', [Category])
- _children['{%s}contributor' % ATOM_NAMESPACE] = ('contributor', [Contributor])
- _children['{%s}id' % ATOM_NAMESPACE] = ('id', Id)
- _children['{%s}link' % ATOM_NAMESPACE] = ('link', [Link])
- _children['{%s}rights' % ATOM_NAMESPACE] = ('rights', Rights)
- _children['{%s}title' % ATOM_NAMESPACE] = ('title', Title)
- _children['{%s}updated' % ATOM_NAMESPACE] = ('updated', Updated)
- def __init__(self, author=None, category=None, contributor=None,
- atom_id=None, link=None, rights=None, title=None, updated=None,
- text=None, extension_elements=None, extension_attributes=None):
- self.author = author or []
- self.category = category or []
- self.contributor = contributor or []
- self.id = atom_id
- self.link = link or []
- self.rights = rights
- self.title = title
- self.updated = updated
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- class Source(FeedEntryParent):
- """The atom:source element"""
- _tag = 'source'
- _namespace = ATOM_NAMESPACE
- _children = FeedEntryParent._children.copy()
- _attributes = FeedEntryParent._attributes.copy()
- _children['{%s}generator' % ATOM_NAMESPACE] = ('generator', Generator)
- _children['{%s}icon' % ATOM_NAMESPACE] = ('icon', Icon)
- _children['{%s}logo' % ATOM_NAMESPACE] = ('logo', Logo)
- _children['{%s}subtitle' % ATOM_NAMESPACE] = ('subtitle', Subtitle)
- 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, text=None,
- extension_elements=None, extension_attributes=None):
- """Constructor for Source
- Args:
- author: list (optional) A list of Author instances which belong to this
- class.
- category: list (optional) A list of Category instances
- contributor: list (optional) A list on Contributor instances
- generator: Generator (optional)
- icon: Icon (optional)
- id: Id (optional) The entry's Id element
- link: list (optional) A list of Link instances
- logo: Logo (optional)
- rights: Rights (optional) The entry's Rights element
- subtitle: Subtitle (optional) The entry's subtitle element
- title: Title (optional) the entry's title element
- updated: Updated (optional) the entry's updated element
- text: String (optional) The text contents of the element. This is the
- contents of the Entry's XML text node.
- (Example: <foo>This is the text</foo>)
- extension_elements: list (optional) A list of ExtensionElement instances
- which are children of this element.
- extension_attributes: dict (optional) A dictionary of strings which are
- the values for additional XML attributes of this element.
- """
- self.author = author or []
- self.category = category or []
- self.contributor = contributor or []
- self.generator = generator
- self.icon = icon
- self.id = atom_id
- self.link = link or []
- self.logo = logo
- self.rights = rights
- self.subtitle = subtitle
- self.title = title
- self.updated = updated
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- def SourceFromString(xml_string):
- return CreateClassFromXMLString(Source, xml_string)
- class Entry(FeedEntryParent):
- """The atom:entry element"""
- _tag = 'entry'
- _namespace = ATOM_NAMESPACE
- _children = FeedEntryParent._children.copy()
- _attributes = FeedEntryParent._attributes.copy()
- _children['{%s}content' % ATOM_NAMESPACE] = ('content', Content)
- _children['{%s}published' % ATOM_NAMESPACE] = ('published', Published)
- _children['{%s}source' % ATOM_NAMESPACE] = ('source', Source)
- _children['{%s}summary' % ATOM_NAMESPACE] = ('summary', Summary)
- _children['{%s}control' % APP_NAMESPACE] = ('control', Control)
- def __init__(self, author=None, category=None, content=None,
- contributor=None, atom_id=None, link=None, published=None, rights=None,
- source=None, summary=None, control=None, title=None, updated=None,
- extension_elements=None, extension_attributes=None, text=None):
- """Constructor for atom:entry
- Args:
- author: list A list of Author instances which belong to this class.
- category: list A list of Category instances
- content: Content The entry's Content
- contributor: list A list on Contributor instances
- id: Id The entry's Id element
- link: list A list of Link instances
- published: Published The entry's Published element
- rights: Rights The entry's Rights element
- source: Source the entry's source element
- summary: Summary the entry's summary element
- title: Title the entry's title element
- updated: Updated the entry's updated element
- control: The entry's app:control element which can be used to mark an
- entry as a draft which should not be publicly viewable.
- text: String The text contents of the element. This is the contents
- of the Entry's XML text node. (Example: <foo>This is the text</foo>)
- extension_elements: list A list of ExtensionElement instances which are
- children of this element.
- extension_attributes: dict A dictionary of strings which are the values
- for additional XML attributes of this element.
- """
- 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.title = title
- self.updated = updated
- self.control = control
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- __init__ = v1_deprecated('Please use atom.data.Entry instead.')(__init__)
- def EntryFromString(xml_string):
- return CreateClassFromXMLString(Entry, xml_string)
- class Feed(Source):
- """The atom:feed element"""
- _tag = 'feed'
- _namespace = ATOM_NAMESPACE
- _children = Source._children.copy()
- _attributes = Source._attributes.copy()
- _children['{%s}entry' % ATOM_NAMESPACE] = ('entry', [Entry])
- 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,
- text=None, extension_elements=None, extension_attributes=None):
- """Constructor for Source
- Args:
- author: list (optional) A list of Author instances which belong to this
- class.
- category: list (optional) A list of Category instances
- contributor: list (optional) A list on Contributor instances
- generator: Generator (optional)
- icon: Icon (optional)
- id: Id (optional) The entry's Id element
- link: list (optional) A list of Link instances
- logo: Logo (optional)
- rights: Rights (optional) The entry's Rights element
- subtitle: Subtitle (optional) The entry's subtitle element
- title: Title (optional) the entry's title element
- updated: Updated (optional) the entry's updated element
- entry: list (optional) A list of the Entry instances contained in the
- feed.
- text: String (optional) The text contents of the element. This is the
- contents of the Entry's XML text node.
- (Example: <foo>This is the text</foo>)
- extension_elements: list (optional) A list of ExtensionElement instances
- which are children of this element.
- extension_attributes: dict (optional) A dictionary of strings which are
- the values for additional XML attributes of this element.
- """
- self.author = author or []
- self.category = category or []
- self.contributor = contributor or []
- self.generator = generator
- self.icon = icon
- self.id = atom_id
- self.link = link or []
- self.logo = logo
- self.rights = rights
- self.subtitle = subtitle
- self.title = title
- self.updated = updated
- self.entry = entry or []
- self.text = text
- self.extension_elements = extension_elements or []
- self.extension_attributes = extension_attributes or {}
- __init__ = v1_deprecated('Please use atom.data.Feed instead.')(__init__)
- def FeedFromString(xml_string):
- return CreateClassFromXMLString(Feed, xml_string)
- class ExtensionElement(object):
- """Represents extra XML elements contained in Atom classes."""
- def __init__(self, tag, namespace=None, attributes=None,
- children=None, text=None):
- """Constructor for EtensionElement
- Args:
- namespace: string (optional) The XML namespace for this element.
- tag: string (optional) The tag (without the namespace qualifier) for
- this element. To reconstruct the full qualified name of the element,
- combine this tag with the namespace.
- attributes: dict (optinal) The attribute value string pairs for the XML
- attributes of this element.
- children: list (optional) A list of ExtensionElements which represent
- the XML child nodes of this element.
- """
- self.namespace = namespace
- self.tag = tag
- self.attributes = attributes or {}
- self.children = children or []
- self.text = text
- def ToString(self):
- element_tree = self._TransferToElementTree(ElementTree.Element(''))
- return ElementTree.tostring(element_tree, encoding="UTF-8")
- def _TransferToElementTree(self, element_tree):
- if self.tag is None:
- return None
- if self.namespace is not None:
- element_tree.tag = '{%s}%s' % (self.namespace, self.tag)
- else:
- element_tree.tag = self.tag
- for key, value in self.attributes.iteritems():
- element_tree.attrib[key] = value
- for child in self.children:
- child._BecomeChildElement(element_tree)
- element_tree.text = self.text
- return element_tree
- def _BecomeChildElement(self, element_tree):
- """Converts this object into an etree element and adds it as a child node.
- Adds self to the ElementTree. This method is required to avoid verbose XML
- which constantly redefines the namespace.
- Args:
- element_tree: ElementTree._Element The element to which this object's XML
- will be added.
- """
- new_element = ElementTree.Element('')
- element_tree.append(new_element)
- self._TransferToElementTree(new_element)
- def FindChildren(self, tag=None, namespace=None):
- """Searches child nodes for objects with the desired tag/namespace.
- Returns a list of extension elements within this object whose tag
- and/or namespace match those passed in. To find all children in
- a particular namespace, specify the namespace but not the tag name.
- If you specify only the tag, the result list may contain extension
- elements in multiple namespaces.
- Args:
- tag: str (optional) The desired tag
- namespace: str (optional) The desired namespace
- Returns:
- A list of elements whose tag and/or namespace match the parameters
- values
- """
- results = []
- if tag and namespace:
- for element in self.children:
- if element.tag == tag and element.namespace == namespace:
- results.append(element)
- elif tag and not namespace:
- for element in self.children:
- if element.tag == tag:
- results.append(element)
- elif namespace and not tag:
- for element in self.children:
- if element.namespace == namespace:
- results.append(element)
- else:
- for element in self.children:
- results.append(element)
- return results
- def ExtensionElementFromString(xml_string):
- element_tree = ElementTree.fromstring(xml_string)
- return _ExtensionElementFromElementTree(element_tree)
- def _ExtensionElementFromElementTree(element_tree):
- element_tag = element_tree.tag
- if '}' in element_tag:
- namespace = element_tag[1:element_tag.index('}')]
- tag = element_tag[element_tag.index('}')+1:]
- else:
- namespace = None
- tag = element_tag
- extension = ExtensionElement(namespace=namespace, tag=tag)
- for key, value in element_tree.attrib.iteritems():
- extension.attributes[key] = value
- for child in element_tree:
- extension.children.append(_ExtensionElementFromElementTree(child))
- extension.text = element_tree.text
- return extension
- def deprecated(warning=None):
- """Decorator to raise warning each time the function is called.
- Args:
- warning: The warning message to be displayed as a string (optinoal).
- """
- warning = warning or ''
- # This closure is what is returned from the deprecated function.
- def mark_deprecated(f):
- # The deprecated_function wraps the actual call to f.
- def deprecated_function(*args, **kwargs):
- warnings.warn(warning, DeprecationWarning, stacklevel=2)
- return f(*args, **kwargs)
- # Preserve the original name to avoid masking all decorated functions as
- # 'deprecated_function'
- try:
- deprecated_function.func_name = f.func_name
- except TypeError:
- # Setting the func_name is not allowed in Python2.3.
- pass
- return deprecated_function
- return mark_deprecated