From e7714888540fe82ddcc41d9754259d4de59e1759 Mon Sep 17 00:00:00 2001 From: Carey Metcalfe Date: Sun, 24 Nov 2019 12:44:00 -0500 Subject: [PATCH] Add support for html summaries for Atom feeds - Add a test - Update existing test - Make flake8 happy --- feedgen/entry.py | 88 ++++++++++++++++++++++++++------------------- tests/test_entry.py | 15 +++++++- 2 files changed, 65 insertions(+), 38 deletions(-) diff --git a/feedgen/entry.py b/feedgen/entry.py index ab3e84b..ea86581 100644 --- a/feedgen/entry.py +++ b/feedgen/entry.py @@ -19,6 +19,45 @@ from feedgen.compat import string_types 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( + '
' + + data.get(name) + '
')) + 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): '''FeedEntry call representing an ATOM feeds entry node or an RSS feeds item node. @@ -96,35 +135,7 @@ class FeedEntry(object): uri = etree.SubElement(author, 'uri') uri.text = a.get('uri') - if self.__atom_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( - '
' + - self.__atom_content.get('content') + '
')) - 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 + _add_text_elm(entry, self.__atom_content, 'content') for l in self.__atom_link or []: link = etree.SubElement(entry, 'link', href=l['href']) @@ -139,9 +150,7 @@ class FeedEntry(object): if l.get('length'): link.attrib['length'] = l['length'] - if self.__atom_summary: - summary = etree.SubElement(entry, 'summary') - summary.text = self.__atom_summary + _add_text_elm(entry, self.__atom_summary, 'summary') for c in self.__atom_category or []: cat = etree.SubElement(entry, 'category', term=c['term']) @@ -453,7 +462,7 @@ class FeedEntry(object): # return the set with more information (atom) 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 summary, abstract, or excerpt of the entry. Summary is an ATOM only element and should be provided if there either is no content provided @@ -467,11 +476,16 @@ class FeedEntry(object): ''' if summary is not None: # Replace the RSS description with the summary if it was the - # summary before. Not if is the description. - if not self.__rss_description or \ - self.__rss_description == self.__atom_summary: + # summary before. Not if it is the description. + if not self.__rss_description or ( + self.__atom_summary and + self.__rss_description == self.__atom_summary.get("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 def description(self, description=None, isSummary=False): diff --git a/tests/test_entry.py b/tests/test_entry.py index 6c9835a..5eaeffa 100644 --- a/tests/test_entry.py +++ b/tests/test_entry.py @@ -84,7 +84,7 @@ class TestSequenceFunctions(unittest.TestCase): fe.updated('2017-02-05 13:26:58+01:00') assert fe.updated().year == 2017 fe.summary('asdf') - assert fe.summary() == 'asdf' + assert fe.summary() == {'summary': 'asdf'} fe.description('asdfx') assert fe.description() == 'asdfx' fe.pubDate('2017-02-05 13:26:58+01:00') @@ -164,3 +164,16 @@ class TestSequenceFunctions(unittest.TestCase): fe.content('content', type='CDATA') result = fg.atom_str() assert b'' 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('

summary

', type='html') + result = fg.atom_str() + expected = b'<p>summary</p>' + assert expected in result