We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add full GLOBAL_CONTEXT support to the post_list plugin
<!--
Before creating an issue:
* make sure you are using an up-to-date version of Nikola
* search for existing issues that might be related

Describe your requested features as precisely as possible. -->

I've got some data and functions in `GLOBAL_CONTEXT` that I'd like to use in a custom post list template.  Right now, it appears that only the locale's date format is passed along to the template context.

Would you accept a PR to make all of the `GLOBAL_CONTEXT` available to the plugin?

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `nikola/plugins/shortcode/post_list.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 # Copyright © 2013-2020 Udo Spallek, Roberto Alsina and others.
4 
5 # Permission is hereby granted, free of charge, to any
6 # person obtaining a copy of this software and associated
7 # documentation files (the "Software"), to deal in the
8 # Software without restriction, including without limitation
9 # the rights to use, copy, modify, merge, publish,
10 # distribute, sublicense, and/or sell copies of the
11 # Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice
15 # shall be included in all copies or substantial portions of
16 # the Software.
17 #
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21 # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
22 # OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 
27 """Post list shortcode."""
28 
29 
30 import operator
31 import os
32 import uuid
33 
34 import natsort
35 
36 from nikola import utils
37 from nikola.packages.datecond import date_in_range
38 from nikola.plugin_categories import ShortcodePlugin
39 
40 
41 class PostListShortcode(ShortcodePlugin):
42     """Provide a shortcode to create a list of posts.
43 
44     Post List
45     =========
46     :Directive Arguments: None.
47     :Directive Options: lang, start, stop, reverse, sort, date, tags, categories, sections, slugs, post_type, template, id
48     :Directive Content: None.
49 
50     The posts appearing in the list can be filtered by options.
51     *List slicing* is provided with the *start*, *stop* and *reverse* options.
52 
53     The following not required options are recognized:
54 
55     ``start`` : integer
56         The index of the first post to show.
57         A negative value like ``-3`` will show the *last* three posts in the
58         post-list.
59         Defaults to None.
60 
61     ``stop`` : integer
62         The index of the last post to show.
63         A value negative value like ``-1`` will show every post, but not the
64         *last* in the post-list.
65         Defaults to None.
66 
67     ``reverse`` : flag
68         Reverse the order of the post-list.
69         Defaults is to not reverse the order of posts.
70 
71     ``sort`` : string
72         Sort post list by one of each post's attributes, usually ``title`` or a
73         custom ``priority``.  Defaults to None (chronological sorting).
74 
75     ``date`` : string
76         Show posts that match date range specified by this option. Format:
77 
78         * comma-separated clauses (AND)
79         * clause: attribute comparison_operator value (spaces optional)
80           * attribute: year, month, day, hour, month, second, weekday, isoweekday; or empty for full datetime
81           * comparison_operator: == != <= >= < >
82           * value: integer, 'now', 'today', or dateutil-compatible date input
83 
84     ``tags`` : string [, string...]
85         Filter posts to show only posts having at least one of the ``tags``.
86         Defaults to None.
87 
88     ``require_all_tags`` : flag
89         Change tag filter behaviour to show only posts that have all specified ``tags``.
90         Defaults to False.
91 
92     ``categories`` : string [, string...]
93         Filter posts to show only posts having one of the ``categories``.
94         Defaults to None.
95 
96     ``sections`` : string [, string...]
97         Filter posts to show only posts having one of the ``sections``.
98         Defaults to None.
99 
100     ``slugs`` : string [, string...]
101         Filter posts to show only posts having at least one of the ``slugs``.
102         Defaults to None.
103 
104     ``post_type`` (or ``type``) : string
105         Show only ``posts``, ``pages`` or ``all``.
106         Replaces ``all``. Defaults to ``posts``.
107 
108     ``lang`` : string
109         The language of post *titles* and *links*.
110         Defaults to default language.
111 
112     ``template`` : string
113         The name of an alternative template to render the post-list.
114         Defaults to ``post_list_directive.tmpl``
115 
116     ``id`` : string
117         A manual id for the post list.
118         Defaults to a random name composed by 'post_list_' + uuid.uuid4().hex.
119     """
120 
121     name = "post_list"
122 
123     def set_site(self, site):
124         """Set the site."""
125         super().set_site(site)
126         site.register_shortcode('post-list', self.handler)
127 
128     def handler(self, start=None, stop=None, reverse=False, tags=None, require_all_tags=False, categories=None,
129                 sections=None, slugs=None, post_type='post', type=False,
130                 lang=None, template='post_list_directive.tmpl', sort=None,
131                 id=None, data=None, state=None, site=None, date=None, filename=None, post=None):
132         """Generate HTML for post-list."""
133         if lang is None:
134             lang = utils.LocaleBorg().current_lang
135         if site.invariant:  # for testing purposes
136             post_list_id = id or 'post_list_' + 'fixedvaluethatisnotauuid'
137         else:
138             post_list_id = id or 'post_list_' + uuid.uuid4().hex
139 
140         # Get post from filename if available
141         if filename:
142             self_post = site.post_per_input_file.get(filename)
143         else:
144             self_post = None
145 
146         if self_post:
147             self_post.register_depfile("####MAGIC####TIMELINE", lang=lang)
148 
149         # If we get strings for start/stop, make them integers
150         if start is not None:
151             start = int(start)
152         if stop is not None:
153             stop = int(stop)
154 
155         # Parse tags/categories/sections/slugs (input is strings)
156         categories = [c.strip().lower() for c in categories.split(',')] if categories else []
157         sections = [s.strip().lower() for s in sections.split(',')] if sections else []
158         slugs = [s.strip() for s in slugs.split(',')] if slugs else []
159 
160         filtered_timeline = []
161         posts = []
162         step = None if reverse is False else -1
163 
164         if type is not False:
165             post_type = type
166 
167         if post_type == 'page' or post_type == 'pages':
168             timeline = [p for p in site.timeline if not p.use_in_feeds]
169         elif post_type == 'all':
170             timeline = [p for p in site.timeline]
171         else:  # post
172             timeline = [p for p in site.timeline if p.use_in_feeds]
173 
174         # self_post should be removed from timeline because this is redundant
175         timeline = [p for p in timeline if p.source_path != filename]
176 
177         if categories:
178             timeline = [p for p in timeline if p.meta('category', lang=lang).lower() in categories]
179 
180         if sections:
181             timeline = [p for p in timeline if p.section_name(lang).lower() in sections]
182 
183         if tags:
184             tags = {t.strip().lower() for t in tags.split(',')}
185             if require_all_tags:
186                 compare = set.issubset
187             else:
188                 compare = operator.and_
189             for post in timeline:
190                 post_tags = {t.lower() for t in post.tags}
191                 if compare(tags, post_tags):
192                     filtered_timeline.append(post)
193         else:
194             filtered_timeline = timeline
195 
196         if sort:
197             filtered_timeline = natsort.natsorted(filtered_timeline, key=lambda post: post.meta[lang][sort], alg=natsort.ns.F | natsort.ns.IC)
198 
199         if date:
200             _now = utils.current_time()
201             filtered_timeline = [p for p in filtered_timeline if date_in_range(utils.html_unescape(date), p.date, now=_now)]
202 
203         for post in filtered_timeline[start:stop:step]:
204             if slugs:
205                 cont = True
206                 for slug in slugs:
207                     if slug == post.meta('slug'):
208                         cont = False
209 
210                 if cont:
211                     continue
212 
213             bp = post.translated_base_path(lang)
214             if os.path.exists(bp) and state:
215                 state.document.settings.record_dependencies.add(bp)
216             elif os.path.exists(bp) and self_post:
217                 self_post.register_depfile(bp, lang=lang)
218 
219             posts += [post]
220 
221         template_deps = site.template_system.template_deps(template)
222         if state:
223             # Register template as a dependency (Issue #2391)
224             for d in template_deps:
225                 state.document.settings.record_dependencies.add(d)
226         elif self_post:
227             for d in template_deps:
228                 self_post.register_depfile(d, lang=lang)
229 
230         template_data = {
231             'lang': lang,
232             'posts': posts,
233             # Need to provide str, not TranslatableSetting (Issue #2104)
234             'date_format': site.GLOBAL_CONTEXT.get('date_format')[lang],
235             'post_list_id': post_list_id,
236             'messages': site.MESSAGES,
237             '_link': site.link,
238         }
239         output = site.template_system.render_template(
240             template, None, template_data)
241         return output, template_deps
242 
243 
244 # Request file name from shortcode (Issue #2412)
245 PostListShortcode.handler.nikola_shortcode_pass_filename = True
246
```
--- 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/nikola/plugins/shortcode/post_list.py b/nikola/plugins/shortcode/post_list.py
--- a/nikola/plugins/shortcode/post_list.py
+++ b/nikola/plugins/shortcode/post_list.py
@@ -145,6 +145,7 @@
 
         if self_post:
             self_post.register_depfile("####MAGIC####TIMELINE", lang=lang)
+            self_post.register_depfile("####MAGIC####CONFIG:GLOBAL_CONTEXT", lang=lang)
 
         # If we get strings for start/stop, make them integers
         if start is not None:
@@ -227,7 +228,8 @@
             for d in template_deps:
                 self_post.register_depfile(d, lang=lang)
 
-        template_data = {
+        template_data = site.GLOBAL_CONTEXT.copy()
+        template_data.update({
             'lang': lang,
             'posts': posts,
             # Need to provide str, not TranslatableSetting (Issue #2104)
@@ -235,7 +237,7 @@
             'post_list_id': post_list_id,
             'messages': site.MESSAGES,
             '_link': site.link,
-        }
+        })
         output = site.template_system.render_template(
             template, None, template_data)
         return output, template_deps

{"golden_diff": "diff --git a/nikola/plugins/shortcode/post_list.py b/nikola/plugins/shortcode/post_list.py\n--- a/nikola/plugins/shortcode/post_list.py\n+++ b/nikola/plugins/shortcode/post_list.py\n@@ -145,6 +145,7 @@\n \n         if self_post:\n             self_post.register_depfile(\"####MAGIC####TIMELINE\", lang=lang)\n+            self_post.register_depfile(\"####MAGIC####CONFIG:GLOBAL_CONTEXT\", lang=lang)\n \n         # If we get strings for start/stop, make them integers\n         if start is not None:\n@@ -227,7 +228,8 @@\n             for d in template_deps:\n                 self_post.register_depfile(d, lang=lang)\n \n-        template_data = {\n+        template_data = site.GLOBAL_CONTEXT.copy()\n+        template_data.update({\n             'lang': lang,\n             'posts': posts,\n             # Need to provide str, not TranslatableSetting (Issue #2104)\n@@ -235,7 +237,7 @@\n             'post_list_id': post_list_id,\n             'messages': site.MESSAGES,\n             '_link': site.link,\n-        }\n+        })\n         output = site.template_system.render_template(\n             template, None, template_data)\n         return output, template_deps\n", "issue": "Add full GLOBAL_CONTEXT support to the post_list plugin\n<!--\r\nBefore creating an issue:\r\n* make sure you are using an up-to-date version of Nikola\r\n* search for existing issues that might be related\r\n\r\nDescribe your requested features as precisely as possible. -->\r\n\r\nI've got some data and functions in `GLOBAL_CONTEXT` that I'd like to use in a custom post list template.  Right now, it appears that only the locale's date format is passed along to the template context.\r\n\r\nWould you accept a PR to make all of the `GLOBAL_CONTEXT` available to the plugin?\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright \u00a9 2013-2020 Udo Spallek, Roberto Alsina and others.\n\n# Permission is hereby granted, free of charge, to any\n# person obtaining a copy of this software and associated\n# documentation files (the \"Software\"), to deal in the\n# Software without restriction, including without limitation\n# the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the\n# Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice\n# shall be included in all copies or substantial portions of\n# the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY\n# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR\n# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\n# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\"\"\"Post list shortcode.\"\"\"\n\n\nimport operator\nimport os\nimport uuid\n\nimport natsort\n\nfrom nikola import utils\nfrom nikola.packages.datecond import date_in_range\nfrom nikola.plugin_categories import ShortcodePlugin\n\n\nclass PostListShortcode(ShortcodePlugin):\n    \"\"\"Provide a shortcode to create a list of posts.\n\n    Post List\n    =========\n    :Directive Arguments: None.\n    :Directive Options: lang, start, stop, reverse, sort, date, tags, categories, sections, slugs, post_type, template, id\n    :Directive Content: None.\n\n    The posts appearing in the list can be filtered by options.\n    *List slicing* is provided with the *start*, *stop* and *reverse* options.\n\n    The following not required options are recognized:\n\n    ``start`` : integer\n        The index of the first post to show.\n        A negative value like ``-3`` will show the *last* three posts in the\n        post-list.\n        Defaults to None.\n\n    ``stop`` : integer\n        The index of the last post to show.\n        A value negative value like ``-1`` will show every post, but not the\n        *last* in the post-list.\n        Defaults to None.\n\n    ``reverse`` : flag\n        Reverse the order of the post-list.\n        Defaults is to not reverse the order of posts.\n\n    ``sort`` : string\n        Sort post list by one of each post's attributes, usually ``title`` or a\n        custom ``priority``.  Defaults to None (chronological sorting).\n\n    ``date`` : string\n        Show posts that match date range specified by this option. Format:\n\n        * comma-separated clauses (AND)\n        * clause: attribute comparison_operator value (spaces optional)\n          * attribute: year, month, day, hour, month, second, weekday, isoweekday; or empty for full datetime\n          * comparison_operator: == != <= >= < >\n          * value: integer, 'now', 'today', or dateutil-compatible date input\n\n    ``tags`` : string [, string...]\n        Filter posts to show only posts having at least one of the ``tags``.\n        Defaults to None.\n\n    ``require_all_tags`` : flag\n        Change tag filter behaviour to show only posts that have all specified ``tags``.\n        Defaults to False.\n\n    ``categories`` : string [, string...]\n        Filter posts to show only posts having one of the ``categories``.\n        Defaults to None.\n\n    ``sections`` : string [, string...]\n        Filter posts to show only posts having one of the ``sections``.\n        Defaults to None.\n\n    ``slugs`` : string [, string...]\n        Filter posts to show only posts having at least one of the ``slugs``.\n        Defaults to None.\n\n    ``post_type`` (or ``type``) : string\n        Show only ``posts``, ``pages`` or ``all``.\n        Replaces ``all``. Defaults to ``posts``.\n\n    ``lang`` : string\n        The language of post *titles* and *links*.\n        Defaults to default language.\n\n    ``template`` : string\n        The name of an alternative template to render the post-list.\n        Defaults to ``post_list_directive.tmpl``\n\n    ``id`` : string\n        A manual id for the post list.\n        Defaults to a random name composed by 'post_list_' + uuid.uuid4().hex.\n    \"\"\"\n\n    name = \"post_list\"\n\n    def set_site(self, site):\n        \"\"\"Set the site.\"\"\"\n        super().set_site(site)\n        site.register_shortcode('post-list', self.handler)\n\n    def handler(self, start=None, stop=None, reverse=False, tags=None, require_all_tags=False, categories=None,\n                sections=None, slugs=None, post_type='post', type=False,\n                lang=None, template='post_list_directive.tmpl', sort=None,\n                id=None, data=None, state=None, site=None, date=None, filename=None, post=None):\n        \"\"\"Generate HTML for post-list.\"\"\"\n        if lang is None:\n            lang = utils.LocaleBorg().current_lang\n        if site.invariant:  # for testing purposes\n            post_list_id = id or 'post_list_' + 'fixedvaluethatisnotauuid'\n        else:\n            post_list_id = id or 'post_list_' + uuid.uuid4().hex\n\n        # Get post from filename if available\n        if filename:\n            self_post = site.post_per_input_file.get(filename)\n        else:\n            self_post = None\n\n        if self_post:\n            self_post.register_depfile(\"####MAGIC####TIMELINE\", lang=lang)\n\n        # If we get strings for start/stop, make them integers\n        if start is not None:\n            start = int(start)\n        if stop is not None:\n            stop = int(stop)\n\n        # Parse tags/categories/sections/slugs (input is strings)\n        categories = [c.strip().lower() for c in categories.split(',')] if categories else []\n        sections = [s.strip().lower() for s in sections.split(',')] if sections else []\n        slugs = [s.strip() for s in slugs.split(',')] if slugs else []\n\n        filtered_timeline = []\n        posts = []\n        step = None if reverse is False else -1\n\n        if type is not False:\n            post_type = type\n\n        if post_type == 'page' or post_type == 'pages':\n            timeline = [p for p in site.timeline if not p.use_in_feeds]\n        elif post_type == 'all':\n            timeline = [p for p in site.timeline]\n        else:  # post\n            timeline = [p for p in site.timeline if p.use_in_feeds]\n\n        # self_post should be removed from timeline because this is redundant\n        timeline = [p for p in timeline if p.source_path != filename]\n\n        if categories:\n            timeline = [p for p in timeline if p.meta('category', lang=lang).lower() in categories]\n\n        if sections:\n            timeline = [p for p in timeline if p.section_name(lang).lower() in sections]\n\n        if tags:\n            tags = {t.strip().lower() for t in tags.split(',')}\n            if require_all_tags:\n                compare = set.issubset\n            else:\n                compare = operator.and_\n            for post in timeline:\n                post_tags = {t.lower() for t in post.tags}\n                if compare(tags, post_tags):\n                    filtered_timeline.append(post)\n        else:\n            filtered_timeline = timeline\n\n        if sort:\n            filtered_timeline = natsort.natsorted(filtered_timeline, key=lambda post: post.meta[lang][sort], alg=natsort.ns.F | natsort.ns.IC)\n\n        if date:\n            _now = utils.current_time()\n            filtered_timeline = [p for p in filtered_timeline if date_in_range(utils.html_unescape(date), p.date, now=_now)]\n\n        for post in filtered_timeline[start:stop:step]:\n            if slugs:\n                cont = True\n                for slug in slugs:\n                    if slug == post.meta('slug'):\n                        cont = False\n\n                if cont:\n                    continue\n\n            bp = post.translated_base_path(lang)\n            if os.path.exists(bp) and state:\n                state.document.settings.record_dependencies.add(bp)\n            elif os.path.exists(bp) and self_post:\n                self_post.register_depfile(bp, lang=lang)\n\n            posts += [post]\n\n        template_deps = site.template_system.template_deps(template)\n        if state:\n            # Register template as a dependency (Issue #2391)\n            for d in template_deps:\n                state.document.settings.record_dependencies.add(d)\n        elif self_post:\n            for d in template_deps:\n                self_post.register_depfile(d, lang=lang)\n\n        template_data = {\n            'lang': lang,\n            'posts': posts,\n            # Need to provide str, not TranslatableSetting (Issue #2104)\n            'date_format': site.GLOBAL_CONTEXT.get('date_format')[lang],\n            'post_list_id': post_list_id,\n            'messages': site.MESSAGES,\n            '_link': site.link,\n        }\n        output = site.template_system.render_template(\n            template, None, template_data)\n        return output, template_deps\n\n\n# Request file name from shortcode (Issue #2412)\nPostListShortcode.handler.nikola_shortcode_pass_filename = True\n", "path": "nikola/plugins/shortcode/post_list.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright \u00a9 2013-2020 Udo Spallek, Roberto Alsina and others.\n\n# Permission is hereby granted, free of charge, to any\n# person obtaining a copy of this software and associated\n# documentation files (the \"Software\"), to deal in the\n# Software without restriction, including without limitation\n# the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the\n# Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice\n# shall be included in all copies or substantial portions of\n# the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY\n# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR\n# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\n# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\"\"\"Post list shortcode.\"\"\"\n\n\nimport operator\nimport os\nimport uuid\n\nimport natsort\n\nfrom nikola import utils\nfrom nikola.packages.datecond import date_in_range\nfrom nikola.plugin_categories import ShortcodePlugin\n\n\nclass PostListShortcode(ShortcodePlugin):\n    \"\"\"Provide a shortcode to create a list of posts.\n\n    Post List\n    =========\n    :Directive Arguments: None.\n    :Directive Options: lang, start, stop, reverse, sort, date, tags, categories, sections, slugs, post_type, template, id\n    :Directive Content: None.\n\n    The posts appearing in the list can be filtered by options.\n    *List slicing* is provided with the *start*, *stop* and *reverse* options.\n\n    The following not required options are recognized:\n\n    ``start`` : integer\n        The index of the first post to show.\n        A negative value like ``-3`` will show the *last* three posts in the\n        post-list.\n        Defaults to None.\n\n    ``stop`` : integer\n        The index of the last post to show.\n        A value negative value like ``-1`` will show every post, but not the\n        *last* in the post-list.\n        Defaults to None.\n\n    ``reverse`` : flag\n        Reverse the order of the post-list.\n        Defaults is to not reverse the order of posts.\n\n    ``sort`` : string\n        Sort post list by one of each post's attributes, usually ``title`` or a\n        custom ``priority``.  Defaults to None (chronological sorting).\n\n    ``date`` : string\n        Show posts that match date range specified by this option. Format:\n\n        * comma-separated clauses (AND)\n        * clause: attribute comparison_operator value (spaces optional)\n          * attribute: year, month, day, hour, month, second, weekday, isoweekday; or empty for full datetime\n          * comparison_operator: == != <= >= < >\n          * value: integer, 'now', 'today', or dateutil-compatible date input\n\n    ``tags`` : string [, string...]\n        Filter posts to show only posts having at least one of the ``tags``.\n        Defaults to None.\n\n    ``require_all_tags`` : flag\n        Change tag filter behaviour to show only posts that have all specified ``tags``.\n        Defaults to False.\n\n    ``categories`` : string [, string...]\n        Filter posts to show only posts having one of the ``categories``.\n        Defaults to None.\n\n    ``sections`` : string [, string...]\n        Filter posts to show only posts having one of the ``sections``.\n        Defaults to None.\n\n    ``slugs`` : string [, string...]\n        Filter posts to show only posts having at least one of the ``slugs``.\n        Defaults to None.\n\n    ``post_type`` (or ``type``) : string\n        Show only ``posts``, ``pages`` or ``all``.\n        Replaces ``all``. Defaults to ``posts``.\n\n    ``lang`` : string\n        The language of post *titles* and *links*.\n        Defaults to default language.\n\n    ``template`` : string\n        The name of an alternative template to render the post-list.\n        Defaults to ``post_list_directive.tmpl``\n\n    ``id`` : string\n        A manual id for the post list.\n        Defaults to a random name composed by 'post_list_' + uuid.uuid4().hex.\n    \"\"\"\n\n    name = \"post_list\"\n\n    def set_site(self, site):\n        \"\"\"Set the site.\"\"\"\n        super().set_site(site)\n        site.register_shortcode('post-list', self.handler)\n\n    def handler(self, start=None, stop=None, reverse=False, tags=None, require_all_tags=False, categories=None,\n                sections=None, slugs=None, post_type='post', type=False,\n                lang=None, template='post_list_directive.tmpl', sort=None,\n                id=None, data=None, state=None, site=None, date=None, filename=None, post=None):\n        \"\"\"Generate HTML for post-list.\"\"\"\n        if lang is None:\n            lang = utils.LocaleBorg().current_lang\n        if site.invariant:  # for testing purposes\n            post_list_id = id or 'post_list_' + 'fixedvaluethatisnotauuid'\n        else:\n            post_list_id = id or 'post_list_' + uuid.uuid4().hex\n\n        # Get post from filename if available\n        if filename:\n            self_post = site.post_per_input_file.get(filename)\n        else:\n            self_post = None\n\n        if self_post:\n            self_post.register_depfile(\"####MAGIC####TIMELINE\", lang=lang)\n            self_post.register_depfile(\"####MAGIC####CONFIG:GLOBAL_CONTEXT\", lang=lang)\n\n        # If we get strings for start/stop, make them integers\n        if start is not None:\n            start = int(start)\n        if stop is not None:\n            stop = int(stop)\n\n        # Parse tags/categories/sections/slugs (input is strings)\n        categories = [c.strip().lower() for c in categories.split(',')] if categories else []\n        sections = [s.strip().lower() for s in sections.split(',')] if sections else []\n        slugs = [s.strip() for s in slugs.split(',')] if slugs else []\n\n        filtered_timeline = []\n        posts = []\n        step = None if reverse is False else -1\n\n        if type is not False:\n            post_type = type\n\n        if post_type == 'page' or post_type == 'pages':\n            timeline = [p for p in site.timeline if not p.use_in_feeds]\n        elif post_type == 'all':\n            timeline = [p for p in site.timeline]\n        else:  # post\n            timeline = [p for p in site.timeline if p.use_in_feeds]\n\n        # self_post should be removed from timeline because this is redundant\n        timeline = [p for p in timeline if p.source_path != filename]\n\n        if categories:\n            timeline = [p for p in timeline if p.meta('category', lang=lang).lower() in categories]\n\n        if sections:\n            timeline = [p for p in timeline if p.section_name(lang).lower() in sections]\n\n        if tags:\n            tags = {t.strip().lower() for t in tags.split(',')}\n            if require_all_tags:\n                compare = set.issubset\n            else:\n                compare = operator.and_\n            for post in timeline:\n                post_tags = {t.lower() for t in post.tags}\n                if compare(tags, post_tags):\n                    filtered_timeline.append(post)\n        else:\n            filtered_timeline = timeline\n\n        if sort:\n            filtered_timeline = natsort.natsorted(filtered_timeline, key=lambda post: post.meta[lang][sort], alg=natsort.ns.F | natsort.ns.IC)\n\n        if date:\n            _now = utils.current_time()\n            filtered_timeline = [p for p in filtered_timeline if date_in_range(utils.html_unescape(date), p.date, now=_now)]\n\n        for post in filtered_timeline[start:stop:step]:\n            if slugs:\n                cont = True\n                for slug in slugs:\n                    if slug == post.meta('slug'):\n                        cont = False\n\n                if cont:\n                    continue\n\n            bp = post.translated_base_path(lang)\n            if os.path.exists(bp) and state:\n                state.document.settings.record_dependencies.add(bp)\n            elif os.path.exists(bp) and self_post:\n                self_post.register_depfile(bp, lang=lang)\n\n            posts += [post]\n\n        template_deps = site.template_system.template_deps(template)\n        if state:\n            # Register template as a dependency (Issue #2391)\n            for d in template_deps:\n                state.document.settings.record_dependencies.add(d)\n        elif self_post:\n            for d in template_deps:\n                self_post.register_depfile(d, lang=lang)\n\n        template_data = site.GLOBAL_CONTEXT.copy()\n        template_data.update({\n            'lang': lang,\n            'posts': posts,\n            # Need to provide str, not TranslatableSetting (Issue #2104)\n            'date_format': site.GLOBAL_CONTEXT.get('date_format')[lang],\n            'post_list_id': post_list_id,\n            'messages': site.MESSAGES,\n            '_link': site.link,\n        })\n        output = site.template_system.render_template(\n            template, None, template_data)\n        return output, template_deps\n\n\n# Request file name from shortcode (Issue #2412)\nPostListShortcode.handler.nikola_shortcode_pass_filename = True\n", "path": "nikola/plugins/shortcode/post_list.py"}]}