Permalink
Browse files

Merge pull request #2789 from getnikola/template_hooks_dependencies

Save dependencies for template hooks properly
  • Loading branch information...
Kwpolska committed May 22, 2017
2 parents e4c5336 + 581e340 commit 815738737b35a7e1ec8dac01e6442c67513eef05
Showing with 32 additions and 8 deletions.
  1. +2 −0 CHANGES.txt
  2. +12 −4 docs/extending.txt
  3. +1 −1 nikola/nikola.py
  4. +1 −1 nikola/plugins/task/galleries.py
  5. +1 −1 nikola/plugins/task/listings.py
  6. +15 −1 nikola/utils.py
View
@@ -16,6 +16,8 @@ Features
Bugfixes
--------
+* Save dependencies for template hooks properly (using .__doc__ or
+ .template_registry_identifier for callables)
* Enable larger panorama thumbnails (Issue #2780)
* Disable ``archive_rss`` link handler, which was useless because no
such RSS was ever generated (Issue #2783)
View
@@ -537,21 +537,22 @@ HTML:
# In set_site
def generate_html_bit(name, ftype='js'):
+ """Generate HTML for an asset."""
return '<script src="/assets/{t}/{n}.{t}">'.format(n=name, t=ftype)
- site.template_hooks['extra_head'].append(generate_html_bit, False, 'fancyplugin', type='js')
+ site.template_hooks['extra_head'].append(generate_html_bit, False, 'fancyplugin', ftype='js')
The second argument to ``append()`` is used to determine whether the function
needs access to the current template context and the site. If it is set to
``True``, the function will also receive ``site`` and ``context`` keyword
arguments. Example use:
-
.. code-block:: python
# In set_site
def greeting(addr, endswith='', site=None, context=None):
+ """Greet someone."""
if context['lang'] == 'en':
greet = u'Hello'
elif context['lang'] == 'es':
@@ -564,6 +565,13 @@ arguments. Example use:
site.template_hooks['page_header'].append(greeting, True, u'Nikola Tesla', endswith=u'!')
+Dependencies for template hooks:
+
+* if the input is a string, the string value, alongside arguments to ``append``, is used for calculating dependencies
+* if the input is a callable, it attempts ``input.template_registry_identifier``, then ``input.__doc__``, and if neither is available, it uses a static string.
+
+Make sure to provide at least a docstring, or a identifier, to ensure rebuilds work properly.
+
Shortcodes
==========
@@ -579,7 +587,7 @@ So, if you are creating a plugin that generates markup, it may be a good idea
to register it as a shortcode in addition of to restructured text directive or
markdown extension, thus making it available to all markup formats.
-To implement your own shortcodes from a plugin, you can create a plugin inheriting ``ShortcodePlugin`` and
+To implement your own shortcodes from a plugin, you can create a plugin inheriting ``ShortcodePlugin`` and
from its ``set_site`` method, call
``Nikola.register_shortcode(name, func)`` with the following arguments:
@@ -610,7 +618,7 @@ variable keyword arguments):
between them, otherwise ``None``.
``lang``:
- The current language.
+ The current language.
If the shortcode tag has arguments of the form ``foo=bar`` they will be
passed as named arguments. Everything else will be passed as positional
View
@@ -2243,7 +2243,7 @@ def generic_renderer(self, lang, output_name, template_name, filters, file_deps=
deps_dict.update(post_deps_dict)
for k, v in self.GLOBAL_CONTEXT['template_hooks'].items():
- deps_dict['||template_hooks|{0}||'.format(k)] = v._items
+ deps_dict['||template_hooks|{0}||'.format(k)] = v.calculate_deps()
for k in self._GLOBAL_CONTEXT_TRANSLATABLE:
deps_dict[k] = deps_dict['global'][k](lang)
@@ -173,7 +173,7 @@ def gen_tasks(self):
self.image_ext_list.extend(self.site.config.get('EXTRA_IMAGE_EXTENSIONS', []))
for k, v in self.site.GLOBAL_CONTEXT['template_hooks'].items():
- self.kw['||template_hooks|{0}||'.format(k)] = v._items
+ self.kw['||template_hooks|{0}||'.format(k)] = v.calculate_deps()
self.site.scan_posts()
yield self.group_task()
@@ -187,7 +187,7 @@ def render_listing(in_name, out_name, input_folder, output_folder, folders=[], f
uptodate = {'c': self.site.GLOBAL_CONTEXT}
for k, v in self.site.GLOBAL_CONTEXT['template_hooks'].items():
- uptodate['||template_hooks|{0}||'.format(k)] = v._items
+ uptodate['||template_hooks|{0}||'.format(k)] = v.calculate_deps()
for k in self.site._GLOBAL_CONTEXT_TRANSLATABLE:
uptodate[k] = self.site.GLOBAL_CONTEXT[k](self.kw['default_lang'])
View
@@ -512,9 +512,23 @@ def append(self, inp, wants_site_and_context=False, *args, **kwargs):
c = callable(inp)
self._items.append((c, inp, wants_site_and_context, args, kwargs))
+ def calculate_deps(self):
+ """Calculate dependencies for a registry."""
+ deps = []
+ for is_callable, inp, wants_site_and_context, args, kwargs in self._items:
+ if not is_callable:
+ name = inp
+ elif hasattr(inp, 'template_registry_identifier'):
+ name = inp.template_registry_identifier
+ elif hasattr(inp, '__doc__'):
+ name = inp.__doc__
+ else:
+ name = '_undefined_callable_'
+ deps.append((is_callable, name, wants_site_and_context, args, kwargs))
+
def __hash__(self):
"""Return hash of a registry."""
- return hash(config_changed({self.name: self._items})._calc_digest())
+ return hash(config_changed({self.name: self.calculate_deps()})._calc_digest())
def __str__(self):
"""Stringify a registry."""

0 comments on commit 8157387

Please sign in to comment.