Add support for html summaries for Atom feeds
- Add a test - Update existing test - Make flake8 happy
This commit is contained in:
parent
edd988f8a6
commit
e771488854
2 changed files with 65 additions and 38 deletions
|
@ -19,6 +19,45 @@ from feedgen.compat import string_types
|
||||||
from feedgen.util import ensure_format, formatRFC2822
|
from feedgen.util import ensure_format, formatRFC2822
|
||||||
|
|
||||||
|
|
||||||
|
def _add_text_elm(entry, data, name):
|
||||||
|
"""Add a text subelement to an entry"""
|
||||||
|
if not data:
|
||||||
|
return
|
||||||
|
|
||||||
|
elm = etree.SubElement(entry, name)
|
||||||
|
type_ = data.get('type')
|
||||||
|
if data.get('src'):
|
||||||
|
if name != 'content':
|
||||||
|
raise ValueError("Only the 'content' element of an entry can "
|
||||||
|
"contain a 'src' attribute")
|
||||||
|
elm.attrib['src'] = data['src']
|
||||||
|
elif data.get(name):
|
||||||
|
# Surround xhtml with a div tag, parse it and embed it
|
||||||
|
if type_ == 'xhtml':
|
||||||
|
elm.append(etree.fromstring(
|
||||||
|
'<div xmlns="http://www.w3.org/1999/xhtml">' +
|
||||||
|
data.get(name) + '</div>'))
|
||||||
|
elif type_ == 'CDATA':
|
||||||
|
elm.text = etree.CDATA(
|
||||||
|
data.get(name))
|
||||||
|
# Emed the text in escaped form
|
||||||
|
elif not type_ or type_.startswith('text') or type_ == 'html':
|
||||||
|
elm.text = data.get(name)
|
||||||
|
# Parse XML and embed it
|
||||||
|
elif type_.endswith('/xml') or type_.endswith('+xml'):
|
||||||
|
elm.append(etree.fromstring(
|
||||||
|
data[name]))
|
||||||
|
# Everything else should be included base64 encoded
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
'base64 encoded {} is not supported at the moment. '
|
||||||
|
'Pull requests adding support are welcome.'.format(name)
|
||||||
|
)
|
||||||
|
# Add type description of the content
|
||||||
|
if type_:
|
||||||
|
elm.attrib['type'] = type_
|
||||||
|
|
||||||
|
|
||||||
class FeedEntry(object):
|
class FeedEntry(object):
|
||||||
'''FeedEntry call representing an ATOM feeds entry node or an RSS feeds item
|
'''FeedEntry call representing an ATOM feeds entry node or an RSS feeds item
|
||||||
node.
|
node.
|
||||||
|
@ -96,35 +135,7 @@ class FeedEntry(object):
|
||||||
uri = etree.SubElement(author, 'uri')
|
uri = etree.SubElement(author, 'uri')
|
||||||
uri.text = a.get('uri')
|
uri.text = a.get('uri')
|
||||||
|
|
||||||
if self.__atom_content:
|
_add_text_elm(entry, self.__atom_content, 'content')
|
||||||
content = etree.SubElement(entry, 'content')
|
|
||||||
type = self.__atom_content.get('type')
|
|
||||||
if self.__atom_content.get('src'):
|
|
||||||
content.attrib['src'] = self.__atom_content['src']
|
|
||||||
elif self.__atom_content.get('content'):
|
|
||||||
# Surround xhtml with a div tag, parse it and embed it
|
|
||||||
if type == 'xhtml':
|
|
||||||
content.append(etree.fromstring(
|
|
||||||
'<div xmlns="http://www.w3.org/1999/xhtml">' +
|
|
||||||
self.__atom_content.get('content') + '</div>'))
|
|
||||||
elif type == 'CDATA':
|
|
||||||
content.text = etree.CDATA(
|
|
||||||
self.__atom_content.get('content'))
|
|
||||||
# Emed the text in escaped form
|
|
||||||
elif not type or type.startswith('text') or type == 'html':
|
|
||||||
content.text = self.__atom_content.get('content')
|
|
||||||
# Parse XML and embed it
|
|
||||||
elif type.endswith('/xml') or type.endswith('+xml'):
|
|
||||||
content.append(etree.fromstring(
|
|
||||||
self.__atom_content['content']))
|
|
||||||
# Everything else should be included base64 encoded
|
|
||||||
else:
|
|
||||||
raise ValueError('base64 encoded content is not ' +
|
|
||||||
'supported at the moment. Pull requests' +
|
|
||||||
' adding support are welcome.')
|
|
||||||
# Add type description of the content
|
|
||||||
if type:
|
|
||||||
content.attrib['type'] = type
|
|
||||||
|
|
||||||
for l in self.__atom_link or []:
|
for l in self.__atom_link or []:
|
||||||
link = etree.SubElement(entry, 'link', href=l['href'])
|
link = etree.SubElement(entry, 'link', href=l['href'])
|
||||||
|
@ -139,9 +150,7 @@ class FeedEntry(object):
|
||||||
if l.get('length'):
|
if l.get('length'):
|
||||||
link.attrib['length'] = l['length']
|
link.attrib['length'] = l['length']
|
||||||
|
|
||||||
if self.__atom_summary:
|
_add_text_elm(entry, self.__atom_summary, 'summary')
|
||||||
summary = etree.SubElement(entry, 'summary')
|
|
||||||
summary.text = self.__atom_summary
|
|
||||||
|
|
||||||
for c in self.__atom_category or []:
|
for c in self.__atom_category or []:
|
||||||
cat = etree.SubElement(entry, 'category', term=c['term'])
|
cat = etree.SubElement(entry, 'category', term=c['term'])
|
||||||
|
@ -453,7 +462,7 @@ class FeedEntry(object):
|
||||||
# return the set with more information (atom)
|
# return the set with more information (atom)
|
||||||
return self.__atom_link
|
return self.__atom_link
|
||||||
|
|
||||||
def summary(self, summary=None):
|
def summary(self, summary=None, type=None):
|
||||||
'''Get or set the summary element of an entry which conveys a short
|
'''Get or set the summary element of an entry which conveys a short
|
||||||
summary, abstract, or excerpt of the entry. Summary is an ATOM only
|
summary, abstract, or excerpt of the entry. Summary is an ATOM only
|
||||||
element and should be provided if there either is no content provided
|
element and should be provided if there either is no content provided
|
||||||
|
@ -467,11 +476,16 @@ class FeedEntry(object):
|
||||||
'''
|
'''
|
||||||
if summary is not None:
|
if summary is not None:
|
||||||
# Replace the RSS description with the summary if it was the
|
# Replace the RSS description with the summary if it was the
|
||||||
# summary before. Not if is the description.
|
# summary before. Not if it is the description.
|
||||||
if not self.__rss_description or \
|
if not self.__rss_description or (
|
||||||
self.__rss_description == self.__atom_summary:
|
self.__atom_summary and
|
||||||
|
self.__rss_description == self.__atom_summary.get("summary")
|
||||||
|
):
|
||||||
self.__rss_description = summary
|
self.__rss_description = summary
|
||||||
self.__atom_summary = summary
|
|
||||||
|
self.__atom_summary = {'summary': summary}
|
||||||
|
if type is not None:
|
||||||
|
self.__atom_summary['type'] = type
|
||||||
return self.__atom_summary
|
return self.__atom_summary
|
||||||
|
|
||||||
def description(self, description=None, isSummary=False):
|
def description(self, description=None, isSummary=False):
|
||||||
|
|
|
@ -84,7 +84,7 @@ class TestSequenceFunctions(unittest.TestCase):
|
||||||
fe.updated('2017-02-05 13:26:58+01:00')
|
fe.updated('2017-02-05 13:26:58+01:00')
|
||||||
assert fe.updated().year == 2017
|
assert fe.updated().year == 2017
|
||||||
fe.summary('asdf')
|
fe.summary('asdf')
|
||||||
assert fe.summary() == 'asdf'
|
assert fe.summary() == {'summary': 'asdf'}
|
||||||
fe.description('asdfx')
|
fe.description('asdfx')
|
||||||
assert fe.description() == 'asdfx'
|
assert fe.description() == 'asdfx'
|
||||||
fe.pubDate('2017-02-05 13:26:58+01:00')
|
fe.pubDate('2017-02-05 13:26:58+01:00')
|
||||||
|
@ -164,3 +164,16 @@ class TestSequenceFunctions(unittest.TestCase):
|
||||||
fe.content('content', type='CDATA')
|
fe.content('content', type='CDATA')
|
||||||
result = fg.atom_str()
|
result = fg.atom_str()
|
||||||
assert b'<content type="CDATA"><![CDATA[content]]></content>' in result
|
assert b'<content type="CDATA"><![CDATA[content]]></content>' in result
|
||||||
|
|
||||||
|
def test_summary_html_type(self):
|
||||||
|
fg = FeedGenerator()
|
||||||
|
fg.title('some title')
|
||||||
|
fg.id('http://lernfunk.de/media/654322/1')
|
||||||
|
fe = fg.add_entry()
|
||||||
|
fe.id('http://lernfunk.de/media/654322/1')
|
||||||
|
fe.title('some title')
|
||||||
|
fe.link(href='http://lernfunk.de/media/654322/1')
|
||||||
|
fe.summary('<p>summary</p>', type='html')
|
||||||
|
result = fg.atom_str()
|
||||||
|
expected = b'<summary type="html"><p>summary</p></summary>'
|
||||||
|
assert expected in result
|
||||||
|
|
Loading…
Reference in a new issue