diff --git a/PyMediaRSS2Gen.py b/PyMediaRSS2Gen.py index 0cf7771..6caa0db 100644 --- a/PyMediaRSS2Gen.py +++ b/PyMediaRSS2Gen.py @@ -74,9 +74,14 @@ def __init__( duration=None, height=None, width=None, - lang=None + lang=None, + + + media_thumbnails=None, ): """Create a media:content element, args will be attributes.""" + self.media_thumbnails = media_thumbnails + self.element_attrs = OrderedDict() self._add_attribute('url', url) @@ -113,7 +118,16 @@ def _add_attribute(self, name, value, allowed_values=None): def publish(self, handler): """Publish the MediaContent as XML.""" - PyRSS2Gen._element(handler, "media:content", None, self.element_attrs) + handler.startElement("media:content", self.element_attrs) + + if hasattr(self, 'media_thumbnails'): + if not isinstance(self.media_thumbnails, list): + self.media_thumbnails = [self.media_thumbnails] + + for t in self.media_thumbnails: + PyRSS2Gen._opt_element(handler, "media:thumbnail", t) + + handler.endElement("media:content") def __repr__(self): """Return a nice string representation for prettier debugging.""" @@ -243,3 +257,53 @@ def publish_extensions(self, handler): if hasattr(self, 'media_text'): PyRSS2Gen._opt_element(handler, "media:text", self.media_text) + +class MediaThumbnail(object): + + """Publish a Media Thumbnail Item.""" + + def __init__( + self, + url, + height=None, + width=None, + time=None # string in the NTP format - see http://www.rssboard.org/media-rss + ): + """Create a thumbnail element that contains args as attributes.""" + + self.element_attrs = OrderedDict() + self._add_attribute('url', url) + self._add_attribute('width', width) + self._add_attribute('height', height) + self._add_attribute('time', time) + + self.check_complicance() + + def _add_attribute(self, name, value): + """Add an attribute to the MediaContent element.""" + if value: + if isinstance(value, (int, bool)): + value = str(value) + + self.element_attrs[name] = value + + def check_complicance(self): + """Check compliance with Media RSS Specification, Version 1.5.1. + + see http://www.rssboard.org/media-rss + Raises AttributeError on error. + """ + + if not self.element_attrs.get('url'): + raise AttributeError('thumbnail url must be specified') + + if self.element_attrs.get('time'): + try: + parts = self.element_attrs['time'].split(':') + assert len(parts) == 3 + except AssertionError: + raise AttributeError('time, if present, must be in the NTP format') + + def publish(self, handler): + """Publish the MediaThumbnail as XML.""" + PyRSS2Gen._element(handler, "media:thumbnail", None, self.element_attrs) \ No newline at end of file diff --git a/tests/fixtures.py b/tests/fixtures.py new file mode 100644 index 0000000..b061eb0 --- /dev/null +++ b/tests/fixtures.py @@ -0,0 +1,17 @@ +# coding=utf-8 + +""" fixtures """ + +import pytest +import PyMediaRSS2Gen as mrss + +FEED_URL = 'http://nowhere.org/rss.xml' + +@pytest.fixture +def feed(): + """ fixture creating an empty feed """ + return mrss.MediaRSS2( + title = 'Test Feed', + link = 'http://nowhere.org/nopost', + description = 'A testing feed' + ) \ No newline at end of file diff --git a/tests/test_content.py b/tests/test_content.py new file mode 100644 index 0000000..6288ccc --- /dev/null +++ b/tests/test_content.py @@ -0,0 +1,31 @@ +# coding=utf-8 + +""" +tests of MediaContent +""" + +import pytest +import PyMediaRSS2Gen as mrss + +from fixtures import * + +class TestMediaContent(object): + + def test_output(self, feed): + """ output of a basic content should look like this """ + + image = mrss.MediaContent( + type='image', + url='http://nowhere.org/img/hippo.jpg', + ) + item = mrss.MediaRSSItem( + title="Item with thumbnail", + media_content=image + ) + feed.items = [item] + output = feed.to_xml() + + assert output.endswith( + ''+ + '' + ) \ No newline at end of file diff --git a/tests/test_mediarss2.py b/tests/test_mediarss2.py new file mode 100644 index 0000000..34461fd --- /dev/null +++ b/tests/test_mediarss2.py @@ -0,0 +1,43 @@ +# coding=utf-8 + +""" +tests of the main class - +MediaRSS2 +""" + +import pytest +import PyMediaRSS2Gen as mrss + +from fixtures import * + +class Test_EmptyFeed(object): + + def test_toXML(self, feed): + """ it is possible to render an empty feed """ + output = feed.to_xml() + assert output.startswith('' in output + assert '' not in output + + @pytest.mark.xfail(reason='PyRSS2Gen ignores the attribute') + def test_hasNamespace(self, feed): + """ the feed defines the media module namespace """ + output = feed.to_xml() + assert 'xmlns:media="http://search.yahoo.com/mrss/"' in output + +class Test_Items(object): + + def test_noMedia(self, feed): + """ + it is possible to have an item without media content + in a media-enabled feed + + The test simply shouldn't throw an error + """ + feed.items = [ + mrss.MediaRSSItem( + title="Item without media content", + description="It has no media content", + ) + ] + output = feed.to_xml() diff --git a/tests/test_thumbnail.py b/tests/test_thumbnail.py new file mode 100644 index 0000000..432d148 --- /dev/null +++ b/tests/test_thumbnail.py @@ -0,0 +1,67 @@ +# coding=utf-8 + +""" +tests of MediaThumbnail +""" + +import pytest +import PyMediaRSS2Gen as mrss + +from fixtures import * + +@pytest.fixture +def itemWithThumbnail(): + """ fixture creating an item with thumbnail """ + thumb = mrss.MediaThumbnail( + url='http://nowhere.org/img/hippo_tn.jpg', + time='00:15:46', + width=150, + height=652 + ) + image = mrss.MediaContent( + type='image', + url='http://nowhere.org/img/hippo.jpg', + media_thumbnails=thumb + ) + return mrss.MediaRSSItem( + title="Item with thumbnail", + media_content=image + ) + +class TestMediaThumbnail(object): + + def test_withoutUrl(self): + """ url is required """ + with pytest.raises(AttributeError): + mrss.MediaThumbnail(url=None) + + def test_withoutTime(self): + """ is ok """ + mrss.MediaThumbnail(url=FEED_URL) + + def test_withInvalidTime(self): + """ time must be in the NTP format """ + with pytest.raises(AttributeError): + mrss.MediaThumbnail(url=FEED_URL, time='notime') + + def test_withValidTime(self): + """ is ok """ + mrss.MediaThumbnail(url=FEED_URL, time='00:05:10') + mrss.MediaThumbnail(url=FEED_URL, time='00:05:10.5') + + def test_XMLOutputContainsThumbnail(self, feed, itemWithThumbnail): + """ first output test: the thumbnail element must be in the output """ + feed.items = [itemWithThumbnail] + output = feed.to_xml() + assert '' + + '' + + '' + ) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..59a9cd1 --- /dev/null +++ b/tox.ini @@ -0,0 +1,9 @@ +[tox] +envlist=py26,py27,py34 + +[testenv] +deps= + pytest + PyRSS2Gen + +commands=py.test \ No newline at end of file