Skip to content

Commit

Permalink
Merge pull request #3238 from avaris/ordered-blinker
Browse files Browse the repository at this point in the history
  • Loading branch information
justinmayer committed Nov 2, 2023
2 parents 14f1947 + 8a8b952 commit dc1b6ab
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 6 deletions.
10 changes: 6 additions & 4 deletions docs/plugins.rst
Expand Up @@ -94,9 +94,12 @@ which you map the signals to your plugin logic. Let's take a simple example::
your ``register`` callable or they will be garbage-collected before the
signal is emitted.

If multiple plugins connect to the same signal, there is no way to guarantee or
control in which order the plugins will be executed. This is a limitation
inherited from Blinker_, the dependency Pelican uses to implement signals.
If multiple plugins connect to the same signal, plugins will be executed in the
order they are connected. With ``PLUGINS`` setting, order will be as defined in
the setting. If you rely on auto-discovered namespace plugins, no ``PLUGINS``
setting, they will be connected in the same order they are discovered (same
order as ``pelican-plugins`` output). If you want to specify the order
explicitly, disable auto-discovery by defining ``PLUGINS`` in the desired order.

Namespace plugin structure
--------------------------
Expand Down Expand Up @@ -341,4 +344,3 @@ custom article, using the ``article_generator_pretaxonomy`` signal::

.. _Pip: https://pip.pypa.io/
.. _pelican-plugins bug #314: https://github.com/getpelican/pelican-plugins/issues/314
.. _Blinker: https://pythonhosted.org/blinker/
6 changes: 5 additions & 1 deletion pelican/plugins/signals.py
@@ -1,4 +1,8 @@
from blinker import signal
from blinker import signal, Signal
from ordered_set import OrderedSet

# Signals will call functions in the order of connection, i.e. plugin order
Signal.set_class = OrderedSet

# Run-level signals:

Expand Down
21 changes: 21 additions & 0 deletions pelican/tests/test_plugins.py
Expand Up @@ -8,6 +8,7 @@
load_plugins,
plugin_enabled,
)
from pelican.plugins.signals import signal
from pelican.tests.support import unittest


Expand Down Expand Up @@ -263,3 +264,23 @@ def get_plugin_names(plugins):
self.assertTrue(plugin_enabled("pelican.plugins.ns_plugin", plugins))
self.assertTrue(plugin_enabled("normal_plugin", plugins))
self.assertFalse(plugin_enabled("unknown", plugins))

def test_blinker_is_ordered(self):
"""ensure that call order is connetion order"""
dummy_signal = signal("dummpy_signal")

functions = []
expected = []
for i in range(50):
# function appends value of i to a list
def func(input, i=i):
input.append(i)

functions.append(func)
# we expect functions to be run in the connection order
dummy_signal.connect(func)
expected.append(i)

input = []
dummy_signal.send(input)
self.assertEqual(input, expected)
3 changes: 2 additions & 1 deletion pyproject.toml
Expand Up @@ -29,10 +29,11 @@ classifiers = [
]
requires-python = ">=3.8.1,<4.0"
dependencies = [
"blinker>=1.6.3",
"blinker>=1.7.0",
"docutils>=0.20.1",
"feedgenerator>=2.1.0",
"jinja2>=3.1.2",
"ordered-set>=4.1.0",
"pygments>=2.16.1",
"python-dateutil>=2.8.2",
"rich>=13.6.0",
Expand Down

0 comments on commit dc1b6ab

Please sign in to comment.