Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A simple plugin system #380

Merged
merged 10 commits into from
Nov 13, 2020
8 changes: 5 additions & 3 deletions streamz/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,16 +307,18 @@ def wrapped(*args, **kwargs):
@classmethod
def register_plugin_entry_point(cls, entry_point, modifier=identity):
def stub(*args, **kwargs):
roveo marked this conversation as resolved.
Show resolved Hide resolved
""" Entrypoints-based streamz plugin. Will be loaded on first call. """
node = entry_point.load()
if not issubclass(node, Stream):
raise TypeError(
f"Error loading {entry_point.name} "
f"from module {entry_point.module_name}: "
f"{node.__class__.__name__} must be a subclass of Stream"
)
cls.register_api(
modifier=modifier, attribute_name=entry_point.name
)(node)
if getattr(cls, entry_point.name).__name__ == "stub":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this can be False, but it doesn't hurt to check.

Copy link
Contributor Author

@roveo roveo Nov 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is false when the plugin class returned from entry_point.load() is decorated with @Stream.register_api. Then it is registered right away when loaded, and so at the moment of this check stub has already been overwritten with the actual class.

cls.register_api(
modifier=modifier, attribute_name=entry_point.name
)(node)
return node(*args, **kwargs)
cls.register_api(modifier=modifier, attribute_name=entry_point.name)(stub)

Expand Down
24 changes: 4 additions & 20 deletions streamz/tests/test_plugins.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import inspect

import pytest
from streamz import Source, Stream

Expand Down Expand Up @@ -31,16 +33,12 @@ def test_register_plugin_entry_point_modifier():
class test_source(Source):
pass

def modifier(fn):
fn.__name__ = 'modified_name'
return staticmethod(fn)

entry_point = MockEntryPoint("from_test", test_source)
Stream.register_plugin_entry_point(entry_point, modifier)
Stream.register_plugin_entry_point(entry_point, staticmethod)

Stream.from_test()

assert Stream.from_test.__name__ == "modified_name"
assert inspect.isfunction(Stream().from_test)

roveo marked this conversation as resolved.
Show resolved Hide resolved

def test_register_plugin_entry_point_raises():
Expand All @@ -53,17 +51,3 @@ class invalid_node:

with pytest.raises(TypeError):
Stream.test()


def test_register_plugin_entry_point_already_registered():
@Stream.register_api()
class test(Stream):
pass

entry_point = MockEntryPoint("test_double", test, "test_module")

Stream.register_plugin_entry_point(entry_point)

assert Stream.test_double.__name__ == "stub"
Stream.test_double()
assert Stream.test_double.__name__ == "test"