Skip to content

Commit

Permalink
changed API to only accept a list of stylesheets
Browse files Browse the repository at this point in the history
  • Loading branch information
bmispelon committed May 17, 2024
1 parent 972ac8a commit a32185d
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 41 deletions.
6 changes: 1 addition & 5 deletions django/utils/feedgenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,8 @@ def to_stylesheet(s):

categories = categories and [str(c) for c in categories]

if stylesheets is None:
pass
elif isinstance(stylesheets, (list, tuple)):
if stylesheets is not None:
stylesheets = [to_stylesheet(s) for s in stylesheets]
else:
stylesheets = [to_stylesheet(stylesheets)]

self.feed = {
"title": to_str(title),
Expand Down
25 changes: 17 additions & 8 deletions docs/ref/contrib/syndication.txt
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ This example illustrates all possible attributes and methods for a
instances).
"""

# Hardcoded stylesheets (can be a single stylesheet or a list)
# Hardcoded stylesheets
stylesheets = ["/stylesheet1.xsl", "stylesheet2.xls"]

# ITEMS -- One of the following three is required. The framework looks
Expand Down Expand Up @@ -1140,7 +1140,9 @@ This can be a hardcoded URL::

class FeedWithHardcodedStylesheet(Feed):
... # author, etc.
stylesheets = "https://example.com/rss_stylesheet.xslt"
stylesheets = [
"https://example.com/rss_stylesheet.xslt",
]

You can also use Django's static files system::

Expand All @@ -1150,7 +1152,9 @@ You can also use Django's static files system::

class FeedWithStaticFileStylesheet(Feed):
... # author, etc.
stylesheets = static("rss_styles.xslt")
stylesheets = [
static("rss_styles.xslt"),
]

Another option is to have a view in your project that renders the XSLT document.
You can then link it like so::
Expand All @@ -1161,7 +1165,9 @@ You can then link it like so::

class FeedWithStylesheetView(Feed):
... # author, etc.
stylesheets = reverse_lazy("your-custom-view-name")
stylesheets = [
reverse_lazy("your-custom-view-name"),
]

Django will normally try to guess the MIME type of the given URL based on its
extension, but if that fails you can specify it using the
Expand All @@ -1173,7 +1179,9 @@ extension, but if that fails you can specify it using the

class FeedWithHardcodedStylesheet(Feed):
... # author, etc.
stylesheets = Stylesheet("https://example.com/rss_stylesheet", mimetype="text/xsl")
stylesheets = [
Stylesheet("https://example.com/rss_stylesheet", mimetype="text/xsl"),
]

Similarly, if you'd like to use a different ``media`` attribute than ``screen``
(Django's default), you can use the
Expand All @@ -1185,10 +1193,11 @@ Similarly, if you'd like to use a different ``media`` attribute than ``screen``

class FeedWithHardcodedStylesheet(Feed):
... # author, etc.
stylesheets = Stylesheet("https://example.com/rss_stylesheet.xslt", media="print")
stylesheets = [
Stylesheet("https://example.com/rss_stylesheet.xslt", media="print"),
]

Finally, if you need support for multiple stylesheets you can pass a list of
stylesheets (either as strings or as ``Stylesheet`` objects as shown above)::
Any of these options can be combined when using multiple stylesheets::

from django.contrib.syndication.views import Feed
from django.utils.feedgenerator import Stylesheet
Expand Down
5 changes: 2 additions & 3 deletions docs/ref/utils.txt
Original file line number Diff line number Diff line change
Expand Up @@ -376,9 +376,8 @@ https://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004
All parameters should be strings, except for two:

* ``categories`` should be a sequence of strings.
* ``stylesheets`` can be a single string, an instance of
:class:`Stylesheet`, or a list of either strings or ``Stylesheet``
instances.
* ``stylesheets`` should be a sequence of either strings or
:class:`Stylesheet` instances.

.. versionchanged:: 5.1

Expand Down
3 changes: 2 additions & 1 deletion docs/releases/5.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ Minor features

* All :class:`~django.utils.feedgenerator.SyndicationFeed` classes now support
a ``stylesheets`` attribute. If specified, an ``<? xml-stylesheet ?>``
processing instruction will be added to the top of the document.
processing instruction will be added to the top of the document for each
stylesheet in the given list.

Asynchronous views
~~~~~~~~~~~~~~~~~~
Expand Down
6 changes: 1 addition & 5 deletions tests/syndication_tests/feeds.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,7 @@ def item_title(self, item):
return "Title: %s" % item.title


class TestFeedWithStylesheet(TestRss2Feed):
stylesheets = "/stylesheet.xsl"


class TestFeedWithMultipleStylesheets(TestRss2Feed):
class TestFeedWithStylesheets(TestRss2Feed):
stylesheets = [
"/stylesheet1.xsl",
feedgenerator.Stylesheet("/stylesheet2.xsl"),
Expand Down
19 changes: 2 additions & 17 deletions tests/syndication_tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,36 +623,21 @@ def test_stylesheet(self):
'href="/test.xsl" type="text/xml" media="screen"',
),
]
# any accepted single argument should also be accepted when in a list/tuple
testdata = (
testdata
+ [([s], expected) for s, expected in testdata]
+ [((s,), expected) for s, expected in testdata]
)
for stylesheets, expected in testdata:
feed = Rss201rev2Feed(
title="test",
link="https://example.com",
description="test",
stylesheets=stylesheets,
stylesheets=[stylesheets],
)
doc = feed.writeString("utf-8")
with self.subTest(expected=expected):
self.assertIn(f"<?xml-stylesheet {expected}?>", doc)

def test_stylesheet_instruction_is_at_the_top(self):
def test_stylesheets_instructions_are_at_the_top(self):
response = self.client.get("/syndication/stylesheet/")
doc = minidom.parseString(response.content)
self.assertEqual(doc.childNodes[0].nodeName, "xml-stylesheet")
self.assertEqual(
doc.childNodes[0].data,
'href="/stylesheet.xsl" type="text/xsl" media="screen"',
)

def test_multiple_stylesheets(self):
response = self.client.get("/syndication/stylesheet/multi/")
doc = minidom.parseString(response.content)
self.assertEqual(doc.childNodes[0].nodeName, "xml-stylesheet")
self.assertEqual(
doc.childNodes[0].data,
'href="/stylesheet1.xsl" type="text/xsl" media="screen"',
Expand Down
3 changes: 1 addition & 2 deletions tests/syndication_tests/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@
path("syndication/articles/", feeds.ArticlesFeed()),
path("syndication/template/", feeds.TemplateFeed()),
path("syndication/template_context/", feeds.TemplateContextFeed()),
path("syndication/stylesheet/", feeds.TestFeedWithStylesheet()),
path("syndication/stylesheet/multi/", feeds.TestFeedWithMultipleStylesheets()),
path("syndication/stylesheet/", feeds.TestFeedWithStylesheets()),
path("syndication/rss2/single-enclosure/", feeds.TestSingleEnclosureRSSFeed()),
path("syndication/rss2/multiple-enclosure/", feeds.TestMultipleEnclosureRSSFeed()),
path("syndication/atom/single-enclosure/", feeds.TestSingleEnclosureAtomFeed()),
Expand Down

0 comments on commit a32185d

Please sign in to comment.