Skip to content

Commit

Permalink
preserve connection order in blinker
Browse files Browse the repository at this point in the history
  • Loading branch information
avaris committed Nov 2, 2023
1 parent 14f1947 commit 8a8b952
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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 8a8b952

Please sign in to comment.