We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Full Atom feeds contain empty summaries
When providing the full content of articles in an Atom feed, the generated file contains an empty `summary` in each entry. It should only contain a `content` and no `summary`.

According to the [Atom RFC](https://tools.ietf.org/html/rfc4287):

> It is advisable that each atom:entry element contain a non-empty atom:title element, a non-empty atom:content element when that element is present, and a non-empty atom:summary element when the entry contains no atom:content element.

The [W3C validator](https://validator.w3.org/feed/) raises a warning when it finds such empty summaries.

Sample configuration:

```python
FEED_DOMAIN = SITEURL
FEED_ALL_ATOM = 'feeds/atom.xml'
FEED_ALL_RSS = 'feeds/rss.xml'
ATOM_FEED_SUMMARY_ONLY = False
RSS_FEED_SUMMARY_ONLY = False
CATEGORY_FEED_ATOM = None
TRANSLATION_FEED_ATOM = None
AUTHOR_FEED_ATOM = None
AUTHOR_FEED_RSS = None
SUMMARY_MAX_LENGTH = 0
```

Excerpt of the generated Atom feed:
```xml
    <entry>
        <title>Foo</title>
        <link href="https://foo.com/bar.html" rel="alternate"></link>
        <published>2018-03-13T18:27:00+01:00</published>
        <updated>2018-03-13T18:27:00+01:00</updated>
        <author>
            <name>Foo</name>
        </author>
        <id>https://foo.com/bar.html</id>
        <summary type="html"></summary>
        <content type="html">This is the content.</content>
    </entry>
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pelican/writers.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 from __future__ import print_function, unicode_literals, with_statement
3 
4 import logging
5 import os
6 
7 from feedgenerator import Atom1Feed, Rss201rev2Feed, get_tag_uri
8 
9 from jinja2 import Markup
10 
11 import six
12 from six.moves.urllib.parse import urljoin
13 
14 from pelican import signals
15 from pelican.paginator import Paginator
16 from pelican.utils import (get_relative_path, is_selected_for_writing,
17                            path_to_url, sanitised_join, set_date_tzinfo)
18 
19 if not six.PY3:
20     from codecs import open
21 
22 logger = logging.getLogger(__name__)
23 
24 
25 class Writer(object):
26 
27     def __init__(self, output_path, settings=None):
28         self.output_path = output_path
29         self.reminder = dict()
30         self.settings = settings or {}
31         self._written_files = set()
32         self._overridden_files = set()
33 
34         # See Content._link_replacer for details
35         if self.settings['RELATIVE_URLS']:
36             self.urljoiner = os.path.join
37         else:
38             self.urljoiner = lambda base, url: urljoin(
39                 base if base.endswith('/') else base + '/', url)
40 
41     def _create_new_feed(self, feed_type, feed_title, context):
42         feed_class = Rss201rev2Feed if feed_type == 'rss' else Atom1Feed
43         if feed_title:
44             feed_title = context['SITENAME'] + ' - ' + feed_title
45         else:
46             feed_title = context['SITENAME']
47         feed = feed_class(
48             title=Markup(feed_title).striptags(),
49             link=(self.site_url + '/'),
50             feed_url=self.feed_url,
51             description=context.get('SITESUBTITLE', ''),
52             subtitle=context.get('SITESUBTITLE', None))
53         return feed
54 
55     def _add_item_to_the_feed(self, feed, item):
56         title = Markup(item.title).striptags()
57         link = self.urljoiner(self.site_url, item.url)
58         is_rss = isinstance(feed, Rss201rev2Feed)
59         if not is_rss or self.settings.get('RSS_FEED_SUMMARY_ONLY'):
60             description = item.summary
61         else:
62             description = item.get_content(self.site_url)
63         feed.add_item(
64             title=title,
65             link=link,
66             unique_id=get_tag_uri(link, item.date),
67             description=description,
68             content=item.get_content(self.site_url),
69             categories=item.tags if hasattr(item, 'tags') else None,
70             author_name=getattr(item, 'author', ''),
71             pubdate=set_date_tzinfo(
72                 item.date, self.settings.get('TIMEZONE', None)),
73             updateddate=set_date_tzinfo(
74                 item.modified, self.settings.get('TIMEZONE', None)
75                 ) if hasattr(item, 'modified') else None)
76 
77     def _open_w(self, filename, encoding, override=False):
78         """Open a file to write some content to it.
79 
80         Exit if we have already written to that file, unless one (and no more
81         than one) of the writes has the override parameter set to True.
82         """
83         if filename in self._overridden_files:
84             if override:
85                 raise RuntimeError('File %s is set to be overridden twice'
86                                    % filename)
87             else:
88                 logger.info('Skipping %s', filename)
89                 filename = os.devnull
90         elif filename in self._written_files:
91             if override:
92                 logger.info('Overwriting %s', filename)
93             else:
94                 raise RuntimeError('File %s is to be overwritten' % filename)
95         if override:
96             self._overridden_files.add(filename)
97         self._written_files.add(filename)
98         return open(filename, 'w', encoding=encoding)
99 
100     def write_feed(self, elements, context, path=None, url=None,
101                    feed_type='atom', override_output=False, feed_title=None):
102         """Generate a feed with the list of articles provided
103 
104         Return the feed. If no path or output_path is specified, just
105         return the feed object.
106 
107         :param elements: the articles to put on the feed.
108         :param context: the context to get the feed metadata.
109         :param path: the path to output.
110         :param url: the publicly visible feed URL; if None, path is used
111             instead
112         :param feed_type: the feed type to use (atom or rss)
113         :param override_output: boolean telling if we can override previous
114             output with the same name (and if next files written with the same
115             name should be skipped to keep that one)
116         :param feed_title: the title of the feed.o
117         """
118         if not is_selected_for_writing(self.settings, path):
119             return
120 
121         self.site_url = context.get(
122             'SITEURL', path_to_url(get_relative_path(path)))
123 
124         self.feed_domain = context.get('FEED_DOMAIN')
125         self.feed_url = self.urljoiner(self.feed_domain, url if url else path)
126 
127         feed = self._create_new_feed(feed_type, feed_title, context)
128 
129         max_items = len(elements)
130         if self.settings['FEED_MAX_ITEMS']:
131             max_items = min(self.settings['FEED_MAX_ITEMS'], max_items)
132         for i in range(max_items):
133             self._add_item_to_the_feed(feed, elements[i])
134 
135         signals.feed_generated.send(context, feed=feed)
136         if path:
137             complete_path = sanitised_join(self.output_path, path)
138 
139             try:
140                 os.makedirs(os.path.dirname(complete_path))
141             except Exception:
142                 pass
143 
144             encoding = 'utf-8' if six.PY3 else None
145             with self._open_w(complete_path, encoding, override_output) as fp:
146                 feed.write(fp, 'utf-8')
147                 logger.info('Writing %s', complete_path)
148 
149             signals.feed_written.send(
150                 complete_path, context=context, feed=feed)
151         return feed
152 
153     def write_file(self, name, template, context, relative_urls=False,
154                    paginated=None, template_name=None, override_output=False,
155                    url=None, **kwargs):
156         """Render the template and write the file.
157 
158         :param name: name of the file to output
159         :param template: template to use to generate the content
160         :param context: dict to pass to the templates.
161         :param relative_urls: use relative urls or absolutes ones
162         :param paginated: dict of article list to paginate - must have the
163             same length (same list in different orders)
164         :param template_name: the template name, for pagination
165         :param override_output: boolean telling if we can override previous
166             output with the same name (and if next files written with the same
167             name should be skipped to keep that one)
168         :param url: url of the file (needed by the paginator)
169         :param **kwargs: additional variables to pass to the templates
170         """
171 
172         if name is False or \
173            name == "" or \
174            not is_selected_for_writing(self.settings,
175                                        os.path.join(self.output_path, name)):
176             return
177         elif not name:
178             # other stuff, just return for now
179             return
180 
181         def _write_file(template, localcontext, output_path, name, override):
182             """Render the template write the file."""
183             # set localsiteurl for context so that Contents can adjust links
184             if localcontext['localsiteurl']:
185                 context['localsiteurl'] = localcontext['localsiteurl']
186             output = template.render(localcontext)
187             path = sanitised_join(output_path, name)
188 
189             try:
190                 os.makedirs(os.path.dirname(path))
191             except Exception:
192                 pass
193 
194             with self._open_w(path, 'utf-8', override=override) as f:
195                 f.write(output)
196             logger.info('Writing %s', path)
197 
198             # Send a signal to say we're writing a file with some specific
199             # local context.
200             signals.content_written.send(path, context=localcontext)
201 
202         def _get_localcontext(context, name, kwargs, relative_urls):
203             localcontext = context.copy()
204             localcontext['localsiteurl'] = localcontext.get(
205                 'localsiteurl', None)
206             if relative_urls:
207                 relative_url = path_to_url(get_relative_path(name))
208                 localcontext['SITEURL'] = relative_url
209                 localcontext['localsiteurl'] = relative_url
210             localcontext['output_file'] = name
211             localcontext.update(kwargs)
212             return localcontext
213 
214         if paginated is None:
215             paginated = {key: val for key, val in kwargs.items()
216                          if key in {'articles', 'dates'}}
217 
218         # pagination
219         if paginated and template_name in self.settings['PAGINATED_TEMPLATES']:
220             # pagination needed
221             per_page = self.settings['PAGINATED_TEMPLATES'][template_name] \
222                 or self.settings['DEFAULT_PAGINATION']
223 
224             # init paginators
225             paginators = {key: Paginator(name, url, val, self.settings,
226                                          per_page)
227                           for key, val in paginated.items()}
228 
229             # generated pages, and write
230             for page_num in range(list(paginators.values())[0].num_pages):
231                 paginated_kwargs = kwargs.copy()
232                 for key in paginators.keys():
233                     paginator = paginators[key]
234                     previous_page = paginator.page(page_num) \
235                         if page_num > 0 else None
236                     page = paginator.page(page_num + 1)
237                     next_page = paginator.page(page_num + 2) \
238                         if page_num + 1 < paginator.num_pages else None
239                     paginated_kwargs.update(
240                         {'%s_paginator' % key: paginator,
241                          '%s_page' % key: page,
242                          '%s_previous_page' % key: previous_page,
243                          '%s_next_page' % key: next_page})
244 
245                 localcontext = _get_localcontext(
246                     context, page.save_as, paginated_kwargs, relative_urls)
247                 _write_file(template, localcontext, self.output_path,
248                             page.save_as, override_output)
249         else:
250             # no pagination
251             localcontext = _get_localcontext(
252                 context, name, kwargs, relative_urls)
253             _write_file(template, localcontext, self.output_path, name,
254                         override_output)
255
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pelican/writers.py b/pelican/writers.py
--- a/pelican/writers.py
+++ b/pelican/writers.py
@@ -55,17 +55,35 @@
     def _add_item_to_the_feed(self, feed, item):
         title = Markup(item.title).striptags()
         link = self.urljoiner(self.site_url, item.url)
-        is_rss = isinstance(feed, Rss201rev2Feed)
-        if not is_rss or self.settings.get('RSS_FEED_SUMMARY_ONLY'):
-            description = item.summary
+
+        if isinstance(feed, Rss201rev2Feed):
+            # RSS feeds use a single tag called 'description' for both the full
+            # content and the summary
+            content = None
+            if self.settings.get('RSS_FEED_SUMMARY_ONLY'):
+                description = item.summary
+            else:
+                description = item.get_content(self.site_url)
+
         else:
-            description = item.get_content(self.site_url)
+            # Atom feeds have two different tags for full content (called
+            # 'content' by feedgenerator) and summary (called 'description' by
+            # feedgenerator).
+            #
+            # It does not make sense to have the summary be the
+            # exact same thing as the full content. If we detect that
+            # they are we just remove the summary.
+            content = item.get_content(self.site_url)
+            description = item.summary
+            if description == content:
+                description = None
+
         feed.add_item(
             title=title,
             link=link,
             unique_id=get_tag_uri(link, item.date),
             description=description,
-            content=item.get_content(self.site_url),
+            content=content,
             categories=item.tags if hasattr(item, 'tags') else None,
             author_name=getattr(item, 'author', ''),
             pubdate=set_date_tzinfo(

{"golden_diff": "diff --git a/pelican/writers.py b/pelican/writers.py\n--- a/pelican/writers.py\n+++ b/pelican/writers.py\n@@ -55,17 +55,35 @@\n     def _add_item_to_the_feed(self, feed, item):\n         title = Markup(item.title).striptags()\n         link = self.urljoiner(self.site_url, item.url)\n-        is_rss = isinstance(feed, Rss201rev2Feed)\n-        if not is_rss or self.settings.get('RSS_FEED_SUMMARY_ONLY'):\n-            description = item.summary\n+\n+        if isinstance(feed, Rss201rev2Feed):\n+            # RSS feeds use a single tag called 'description' for both the full\n+            # content and the summary\n+            content = None\n+            if self.settings.get('RSS_FEED_SUMMARY_ONLY'):\n+                description = item.summary\n+            else:\n+                description = item.get_content(self.site_url)\n+\n         else:\n-            description = item.get_content(self.site_url)\n+            # Atom feeds have two different tags for full content (called\n+            # 'content' by feedgenerator) and summary (called 'description' by\n+            # feedgenerator).\n+            #\n+            # It does not make sense to have the summary be the\n+            # exact same thing as the full content. If we detect that\n+            # they are we just remove the summary.\n+            content = item.get_content(self.site_url)\n+            description = item.summary\n+            if description == content:\n+                description = None\n+\n         feed.add_item(\n             title=title,\n             link=link,\n             unique_id=get_tag_uri(link, item.date),\n             description=description,\n-            content=item.get_content(self.site_url),\n+            content=content,\n             categories=item.tags if hasattr(item, 'tags') else None,\n             author_name=getattr(item, 'author', ''),\n             pubdate=set_date_tzinfo(\n", "issue": "Full Atom feeds contain empty summaries\nWhen providing the full content of articles in an Atom feed, the generated file contains an empty `summary` in each entry. It should only contain a `content` and no `summary`.\r\n\r\nAccording to the [Atom RFC](https://tools.ietf.org/html/rfc4287):\r\n\r\n> It is advisable that each atom:entry element contain a non-empty atom:title element, a non-empty atom:content element when that element is present, and a non-empty atom:summary element when the entry contains no atom:content element.\r\n\r\nThe [W3C validator](https://validator.w3.org/feed/) raises a warning when it finds such empty summaries.\r\n\r\nSample configuration:\r\n\r\n```python\r\nFEED_DOMAIN = SITEURL\r\nFEED_ALL_ATOM = 'feeds/atom.xml'\r\nFEED_ALL_RSS = 'feeds/rss.xml'\r\nATOM_FEED_SUMMARY_ONLY = False\r\nRSS_FEED_SUMMARY_ONLY = False\r\nCATEGORY_FEED_ATOM = None\r\nTRANSLATION_FEED_ATOM = None\r\nAUTHOR_FEED_ATOM = None\r\nAUTHOR_FEED_RSS = None\r\nSUMMARY_MAX_LENGTH = 0\r\n```\r\n\r\nExcerpt of the generated Atom feed:\r\n```xml\r\n    <entry>\r\n        <title>Foo</title>\r\n        <link href=\"https://foo.com/bar.html\" rel=\"alternate\"></link>\r\n        <published>2018-03-13T18:27:00+01:00</published>\r\n        <updated>2018-03-13T18:27:00+01:00</updated>\r\n        <author>\r\n            <name>Foo</name>\r\n        </author>\r\n        <id>https://foo.com/bar.html</id>\r\n        <summary type=\"html\"></summary>\r\n        <content type=\"html\">This is the content.</content>\r\n    </entry>\r\n```\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\nfrom __future__ import print_function, unicode_literals, with_statement\n\nimport logging\nimport os\n\nfrom feedgenerator import Atom1Feed, Rss201rev2Feed, get_tag_uri\n\nfrom jinja2 import Markup\n\nimport six\nfrom six.moves.urllib.parse import urljoin\n\nfrom pelican import signals\nfrom pelican.paginator import Paginator\nfrom pelican.utils import (get_relative_path, is_selected_for_writing,\n                           path_to_url, sanitised_join, set_date_tzinfo)\n\nif not six.PY3:\n    from codecs import open\n\nlogger = logging.getLogger(__name__)\n\n\nclass Writer(object):\n\n    def __init__(self, output_path, settings=None):\n        self.output_path = output_path\n        self.reminder = dict()\n        self.settings = settings or {}\n        self._written_files = set()\n        self._overridden_files = set()\n\n        # See Content._link_replacer for details\n        if self.settings['RELATIVE_URLS']:\n            self.urljoiner = os.path.join\n        else:\n            self.urljoiner = lambda base, url: urljoin(\n                base if base.endswith('/') else base + '/', url)\n\n    def _create_new_feed(self, feed_type, feed_title, context):\n        feed_class = Rss201rev2Feed if feed_type == 'rss' else Atom1Feed\n        if feed_title:\n            feed_title = context['SITENAME'] + ' - ' + feed_title\n        else:\n            feed_title = context['SITENAME']\n        feed = feed_class(\n            title=Markup(feed_title).striptags(),\n            link=(self.site_url + '/'),\n            feed_url=self.feed_url,\n            description=context.get('SITESUBTITLE', ''),\n            subtitle=context.get('SITESUBTITLE', None))\n        return feed\n\n    def _add_item_to_the_feed(self, feed, item):\n        title = Markup(item.title).striptags()\n        link = self.urljoiner(self.site_url, item.url)\n        is_rss = isinstance(feed, Rss201rev2Feed)\n        if not is_rss or self.settings.get('RSS_FEED_SUMMARY_ONLY'):\n            description = item.summary\n        else:\n            description = item.get_content(self.site_url)\n        feed.add_item(\n            title=title,\n            link=link,\n            unique_id=get_tag_uri(link, item.date),\n            description=description,\n            content=item.get_content(self.site_url),\n            categories=item.tags if hasattr(item, 'tags') else None,\n            author_name=getattr(item, 'author', ''),\n            pubdate=set_date_tzinfo(\n                item.date, self.settings.get('TIMEZONE', None)),\n            updateddate=set_date_tzinfo(\n                item.modified, self.settings.get('TIMEZONE', None)\n                ) if hasattr(item, 'modified') else None)\n\n    def _open_w(self, filename, encoding, override=False):\n        \"\"\"Open a file to write some content to it.\n\n        Exit if we have already written to that file, unless one (and no more\n        than one) of the writes has the override parameter set to True.\n        \"\"\"\n        if filename in self._overridden_files:\n            if override:\n                raise RuntimeError('File %s is set to be overridden twice'\n                                   % filename)\n            else:\n                logger.info('Skipping %s', filename)\n                filename = os.devnull\n        elif filename in self._written_files:\n            if override:\n                logger.info('Overwriting %s', filename)\n            else:\n                raise RuntimeError('File %s is to be overwritten' % filename)\n        if override:\n            self._overridden_files.add(filename)\n        self._written_files.add(filename)\n        return open(filename, 'w', encoding=encoding)\n\n    def write_feed(self, elements, context, path=None, url=None,\n                   feed_type='atom', override_output=False, feed_title=None):\n        \"\"\"Generate a feed with the list of articles provided\n\n        Return the feed. If no path or output_path is specified, just\n        return the feed object.\n\n        :param elements: the articles to put on the feed.\n        :param context: the context to get the feed metadata.\n        :param path: the path to output.\n        :param url: the publicly visible feed URL; if None, path is used\n            instead\n        :param feed_type: the feed type to use (atom or rss)\n        :param override_output: boolean telling if we can override previous\n            output with the same name (and if next files written with the same\n            name should be skipped to keep that one)\n        :param feed_title: the title of the feed.o\n        \"\"\"\n        if not is_selected_for_writing(self.settings, path):\n            return\n\n        self.site_url = context.get(\n            'SITEURL', path_to_url(get_relative_path(path)))\n\n        self.feed_domain = context.get('FEED_DOMAIN')\n        self.feed_url = self.urljoiner(self.feed_domain, url if url else path)\n\n        feed = self._create_new_feed(feed_type, feed_title, context)\n\n        max_items = len(elements)\n        if self.settings['FEED_MAX_ITEMS']:\n            max_items = min(self.settings['FEED_MAX_ITEMS'], max_items)\n        for i in range(max_items):\n            self._add_item_to_the_feed(feed, elements[i])\n\n        signals.feed_generated.send(context, feed=feed)\n        if path:\n            complete_path = sanitised_join(self.output_path, path)\n\n            try:\n                os.makedirs(os.path.dirname(complete_path))\n            except Exception:\n                pass\n\n            encoding = 'utf-8' if six.PY3 else None\n            with self._open_w(complete_path, encoding, override_output) as fp:\n                feed.write(fp, 'utf-8')\n                logger.info('Writing %s', complete_path)\n\n            signals.feed_written.send(\n                complete_path, context=context, feed=feed)\n        return feed\n\n    def write_file(self, name, template, context, relative_urls=False,\n                   paginated=None, template_name=None, override_output=False,\n                   url=None, **kwargs):\n        \"\"\"Render the template and write the file.\n\n        :param name: name of the file to output\n        :param template: template to use to generate the content\n        :param context: dict to pass to the templates.\n        :param relative_urls: use relative urls or absolutes ones\n        :param paginated: dict of article list to paginate - must have the\n            same length (same list in different orders)\n        :param template_name: the template name, for pagination\n        :param override_output: boolean telling if we can override previous\n            output with the same name (and if next files written with the same\n            name should be skipped to keep that one)\n        :param url: url of the file (needed by the paginator)\n        :param **kwargs: additional variables to pass to the templates\n        \"\"\"\n\n        if name is False or \\\n           name == \"\" or \\\n           not is_selected_for_writing(self.settings,\n                                       os.path.join(self.output_path, name)):\n            return\n        elif not name:\n            # other stuff, just return for now\n            return\n\n        def _write_file(template, localcontext, output_path, name, override):\n            \"\"\"Render the template write the file.\"\"\"\n            # set localsiteurl for context so that Contents can adjust links\n            if localcontext['localsiteurl']:\n                context['localsiteurl'] = localcontext['localsiteurl']\n            output = template.render(localcontext)\n            path = sanitised_join(output_path, name)\n\n            try:\n                os.makedirs(os.path.dirname(path))\n            except Exception:\n                pass\n\n            with self._open_w(path, 'utf-8', override=override) as f:\n                f.write(output)\n            logger.info('Writing %s', path)\n\n            # Send a signal to say we're writing a file with some specific\n            # local context.\n            signals.content_written.send(path, context=localcontext)\n\n        def _get_localcontext(context, name, kwargs, relative_urls):\n            localcontext = context.copy()\n            localcontext['localsiteurl'] = localcontext.get(\n                'localsiteurl', None)\n            if relative_urls:\n                relative_url = path_to_url(get_relative_path(name))\n                localcontext['SITEURL'] = relative_url\n                localcontext['localsiteurl'] = relative_url\n            localcontext['output_file'] = name\n            localcontext.update(kwargs)\n            return localcontext\n\n        if paginated is None:\n            paginated = {key: val for key, val in kwargs.items()\n                         if key in {'articles', 'dates'}}\n\n        # pagination\n        if paginated and template_name in self.settings['PAGINATED_TEMPLATES']:\n            # pagination needed\n            per_page = self.settings['PAGINATED_TEMPLATES'][template_name] \\\n                or self.settings['DEFAULT_PAGINATION']\n\n            # init paginators\n            paginators = {key: Paginator(name, url, val, self.settings,\n                                         per_page)\n                          for key, val in paginated.items()}\n\n            # generated pages, and write\n            for page_num in range(list(paginators.values())[0].num_pages):\n                paginated_kwargs = kwargs.copy()\n                for key in paginators.keys():\n                    paginator = paginators[key]\n                    previous_page = paginator.page(page_num) \\\n                        if page_num > 0 else None\n                    page = paginator.page(page_num + 1)\n                    next_page = paginator.page(page_num + 2) \\\n                        if page_num + 1 < paginator.num_pages else None\n                    paginated_kwargs.update(\n                        {'%s_paginator' % key: paginator,\n                         '%s_page' % key: page,\n                         '%s_previous_page' % key: previous_page,\n                         '%s_next_page' % key: next_page})\n\n                localcontext = _get_localcontext(\n                    context, page.save_as, paginated_kwargs, relative_urls)\n                _write_file(template, localcontext, self.output_path,\n                            page.save_as, override_output)\n        else:\n            # no pagination\n            localcontext = _get_localcontext(\n                context, name, kwargs, relative_urls)\n            _write_file(template, localcontext, self.output_path, name,\n                        override_output)\n", "path": "pelican/writers.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\nfrom __future__ import print_function, unicode_literals, with_statement\n\nimport logging\nimport os\n\nfrom feedgenerator import Atom1Feed, Rss201rev2Feed, get_tag_uri\n\nfrom jinja2 import Markup\n\nimport six\nfrom six.moves.urllib.parse import urljoin\n\nfrom pelican import signals\nfrom pelican.paginator import Paginator\nfrom pelican.utils import (get_relative_path, is_selected_for_writing,\n                           path_to_url, sanitised_join, set_date_tzinfo)\n\nif not six.PY3:\n    from codecs import open\n\nlogger = logging.getLogger(__name__)\n\n\nclass Writer(object):\n\n    def __init__(self, output_path, settings=None):\n        self.output_path = output_path\n        self.reminder = dict()\n        self.settings = settings or {}\n        self._written_files = set()\n        self._overridden_files = set()\n\n        # See Content._link_replacer for details\n        if self.settings['RELATIVE_URLS']:\n            self.urljoiner = os.path.join\n        else:\n            self.urljoiner = lambda base, url: urljoin(\n                base if base.endswith('/') else base + '/', url)\n\n    def _create_new_feed(self, feed_type, feed_title, context):\n        feed_class = Rss201rev2Feed if feed_type == 'rss' else Atom1Feed\n        if feed_title:\n            feed_title = context['SITENAME'] + ' - ' + feed_title\n        else:\n            feed_title = context['SITENAME']\n        feed = feed_class(\n            title=Markup(feed_title).striptags(),\n            link=(self.site_url + '/'),\n            feed_url=self.feed_url,\n            description=context.get('SITESUBTITLE', ''),\n            subtitle=context.get('SITESUBTITLE', None))\n        return feed\n\n    def _add_item_to_the_feed(self, feed, item):\n        title = Markup(item.title).striptags()\n        link = self.urljoiner(self.site_url, item.url)\n\n        if isinstance(feed, Rss201rev2Feed):\n            # RSS feeds use a single tag called 'description' for both the full\n            # content and the summary\n            content = None\n            if self.settings.get('RSS_FEED_SUMMARY_ONLY'):\n                description = item.summary\n            else:\n                description = item.get_content(self.site_url)\n\n        else:\n            # Atom feeds have two different tags for full content (called\n            # 'content' by feedgenerator) and summary (called 'description' by\n            # feedgenerator).\n            #\n            # It does not make sense to have the summary be the\n            # exact same thing as the full content. If we detect that\n            # they are we just remove the summary.\n            content = item.get_content(self.site_url)\n            description = item.summary\n            if description == content:\n                description = None\n\n        feed.add_item(\n            title=title,\n            link=link,\n            unique_id=get_tag_uri(link, item.date),\n            description=description,\n            content=content,\n            categories=item.tags if hasattr(item, 'tags') else None,\n            author_name=getattr(item, 'author', ''),\n            pubdate=set_date_tzinfo(\n                item.date, self.settings.get('TIMEZONE', None)),\n            updateddate=set_date_tzinfo(\n                item.modified, self.settings.get('TIMEZONE', None)\n                ) if hasattr(item, 'modified') else None)\n\n    def _open_w(self, filename, encoding, override=False):\n        \"\"\"Open a file to write some content to it.\n\n        Exit if we have already written to that file, unless one (and no more\n        than one) of the writes has the override parameter set to True.\n        \"\"\"\n        if filename in self._overridden_files:\n            if override:\n                raise RuntimeError('File %s is set to be overridden twice'\n                                   % filename)\n            else:\n                logger.info('Skipping %s', filename)\n                filename = os.devnull\n        elif filename in self._written_files:\n            if override:\n                logger.info('Overwriting %s', filename)\n            else:\n                raise RuntimeError('File %s is to be overwritten' % filename)\n        if override:\n            self._overridden_files.add(filename)\n        self._written_files.add(filename)\n        return open(filename, 'w', encoding=encoding)\n\n    def write_feed(self, elements, context, path=None, url=None,\n                   feed_type='atom', override_output=False, feed_title=None):\n        \"\"\"Generate a feed with the list of articles provided\n\n        Return the feed. If no path or output_path is specified, just\n        return the feed object.\n\n        :param elements: the articles to put on the feed.\n        :param context: the context to get the feed metadata.\n        :param path: the path to output.\n        :param url: the publicly visible feed URL; if None, path is used\n            instead\n        :param feed_type: the feed type to use (atom or rss)\n        :param override_output: boolean telling if we can override previous\n            output with the same name (and if next files written with the same\n            name should be skipped to keep that one)\n        :param feed_title: the title of the feed.o\n        \"\"\"\n        if not is_selected_for_writing(self.settings, path):\n            return\n\n        self.site_url = context.get(\n            'SITEURL', path_to_url(get_relative_path(path)))\n\n        self.feed_domain = context.get('FEED_DOMAIN')\n        self.feed_url = self.urljoiner(self.feed_domain, url if url else path)\n\n        feed = self._create_new_feed(feed_type, feed_title, context)\n\n        max_items = len(elements)\n        if self.settings['FEED_MAX_ITEMS']:\n            max_items = min(self.settings['FEED_MAX_ITEMS'], max_items)\n        for i in range(max_items):\n            self._add_item_to_the_feed(feed, elements[i])\n\n        signals.feed_generated.send(context, feed=feed)\n        if path:\n            complete_path = sanitised_join(self.output_path, path)\n\n            try:\n                os.makedirs(os.path.dirname(complete_path))\n            except Exception:\n                pass\n\n            encoding = 'utf-8' if six.PY3 else None\n            with self._open_w(complete_path, encoding, override_output) as fp:\n                feed.write(fp, 'utf-8')\n                logger.info('Writing %s', complete_path)\n\n            signals.feed_written.send(\n                complete_path, context=context, feed=feed)\n        return feed\n\n    def write_file(self, name, template, context, relative_urls=False,\n                   paginated=None, template_name=None, override_output=False,\n                   url=None, **kwargs):\n        \"\"\"Render the template and write the file.\n\n        :param name: name of the file to output\n        :param template: template to use to generate the content\n        :param context: dict to pass to the templates.\n        :param relative_urls: use relative urls or absolutes ones\n        :param paginated: dict of article list to paginate - must have the\n            same length (same list in different orders)\n        :param template_name: the template name, for pagination\n        :param override_output: boolean telling if we can override previous\n            output with the same name (and if next files written with the same\n            name should be skipped to keep that one)\n        :param url: url of the file (needed by the paginator)\n        :param **kwargs: additional variables to pass to the templates\n        \"\"\"\n\n        if name is False or \\\n           name == \"\" or \\\n           not is_selected_for_writing(self.settings,\n                                       os.path.join(self.output_path, name)):\n            return\n        elif not name:\n            # other stuff, just return for now\n            return\n\n        def _write_file(template, localcontext, output_path, name, override):\n            \"\"\"Render the template write the file.\"\"\"\n            # set localsiteurl for context so that Contents can adjust links\n            if localcontext['localsiteurl']:\n                context['localsiteurl'] = localcontext['localsiteurl']\n            output = template.render(localcontext)\n            path = sanitised_join(output_path, name)\n\n            try:\n                os.makedirs(os.path.dirname(path))\n            except Exception:\n                pass\n\n            with self._open_w(path, 'utf-8', override=override) as f:\n                f.write(output)\n            logger.info('Writing %s', path)\n\n            # Send a signal to say we're writing a file with some specific\n            # local context.\n            signals.content_written.send(path, context=localcontext)\n\n        def _get_localcontext(context, name, kwargs, relative_urls):\n            localcontext = context.copy()\n            localcontext['localsiteurl'] = localcontext.get(\n                'localsiteurl', None)\n            if relative_urls:\n                relative_url = path_to_url(get_relative_path(name))\n                localcontext['SITEURL'] = relative_url\n                localcontext['localsiteurl'] = relative_url\n            localcontext['output_file'] = name\n            localcontext.update(kwargs)\n            return localcontext\n\n        if paginated is None:\n            paginated = {key: val for key, val in kwargs.items()\n                         if key in {'articles', 'dates'}}\n\n        # pagination\n        if paginated and template_name in self.settings['PAGINATED_TEMPLATES']:\n            # pagination needed\n            per_page = self.settings['PAGINATED_TEMPLATES'][template_name] \\\n                or self.settings['DEFAULT_PAGINATION']\n\n            # init paginators\n            paginators = {key: Paginator(name, url, val, self.settings,\n                                         per_page)\n                          for key, val in paginated.items()}\n\n            # generated pages, and write\n            for page_num in range(list(paginators.values())[0].num_pages):\n                paginated_kwargs = kwargs.copy()\n                for key in paginators.keys():\n                    paginator = paginators[key]\n                    previous_page = paginator.page(page_num) \\\n                        if page_num > 0 else None\n                    page = paginator.page(page_num + 1)\n                    next_page = paginator.page(page_num + 2) \\\n                        if page_num + 1 < paginator.num_pages else None\n                    paginated_kwargs.update(\n                        {'%s_paginator' % key: paginator,\n                         '%s_page' % key: page,\n                         '%s_previous_page' % key: previous_page,\n                         '%s_next_page' % key: next_page})\n\n                localcontext = _get_localcontext(\n                    context, page.save_as, paginated_kwargs, relative_urls)\n                _write_file(template, localcontext, self.output_path,\n                            page.save_as, override_output)\n        else:\n            # no pagination\n            localcontext = _get_localcontext(\n                context, name, kwargs, relative_urls)\n            _write_file(template, localcontext, self.output_path, name,\n                        override_output)\n", "path": "pelican/writers.py"}]}