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

add pluggy on rasa_sdk #970

Merged
merged 9 commits into from
Apr 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ RUN pip install --no-cache-dir <A_REQUIRED_PACKAGE_ON_PYPI>
USER 1001
```


## Building from source

Rasa SDK uses Poetry for packaging and dependency management. If you want to build it from source,
Expand Down
1 change: 1 addition & 0 deletions changelog/970.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add pluggy to provide ability to create sanic extensions in rasa-sdk
10 changes: 5 additions & 5 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ Sanic-Cors = "^2.0.0"
prompt-toolkit = "^3.0,<3.0.29"
"ruamel.yaml" = ">=0.16.5,<0.18.0"
websockets = ">=10.0,<11.0"
pluggy = "^1.0.0"
souvikg10 marked this conversation as resolved.
Show resolved Hide resolved

[tool.poetry.dev-dependencies]
pytest-cov = "^4.0.0"
Expand Down
1 change: 1 addition & 0 deletions rasa_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import rasa_sdk.cli
import rasa_sdk.version
import rasa_sdk.plugin
from rasa_sdk.interfaces import Tracker, Action, ActionExecutionRejection # noqa: F401
from rasa_sdk.forms import ValidationAction, FormValidationAction # noqa: F401

Expand Down
4 changes: 4 additions & 0 deletions rasa_sdk/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from rasa_sdk.constants import DEFAULT_SERVER_PORT
from rasa_sdk.executor import ActionExecutor
from rasa_sdk.interfaces import ActionExecutionRejection, ActionNotFoundException
from rasa_sdk.plugin import plugin_manager

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -156,6 +157,9 @@ def run(
app = create_app(
action_package_name, cors_origins=cors_origins, auto_reload=auto_reload
)
## Attach additional sanic extensions: listeners, middleware and routing
logger.info("Starting plugins...")
plugin_manager().hook.attach_sanic_app_extensions(app=app)
ssl_context = create_ssl_context(ssl_certificate, ssl_keyfile, ssl_password)
protocol = "https" if ssl_context else "http"
host = os.environ.get("SANIC_HOST", "0.0.0.0")
Expand Down
36 changes: 36 additions & 0 deletions rasa_sdk/plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import functools
import sys
import logging
import pluggy

from sanic import Sanic

hookspec = pluggy.HookspecMarker("rasa_sdk")
logger = logging.getLogger(__name__)


@functools.lru_cache(maxsize=2)
def plugin_manager() -> pluggy.PluginManager:
"""Initialises a plugin manager which registers hook implementations."""
_plugin_manager = pluggy.PluginManager("rasa_sdk")
_plugin_manager.add_hookspecs(sys.modules["rasa_sdk.plugin"])
_discover_plugins(_plugin_manager)

return _plugin_manager


def _discover_plugins(manager: pluggy.PluginManager) -> None:
try:
# rasa_sdk_plugin is a custom package
# which extends existing functionality on rasa action server via plugins
import rasa_sdk_plugins

rasa_sdk_plugins.init_hooks(manager)
except ModuleNotFoundError as e:
logger.info("No plugins found", exc_info=e)
pass


@hookspec
def attach_sanic_app_extensions(app: Sanic) -> None:
"""Hook specification for attaching sanic listeners, routes and middlewares."""
40 changes: 40 additions & 0 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import warnings

from pytest import MonkeyPatch
from pluggy import PluginManager
from unittest.mock import MagicMock

from rasa_sdk import endpoint
from rasa_sdk.plugin import plugin_manager


def test_plugin_manager() -> None:
manager = plugin_manager()
assert isinstance(manager, PluginManager)

manager_2 = plugin_manager()
assert manager_2 == manager


def test_plugin_attach_sanic_app_extension(
monkeypatch: MonkeyPatch,
) -> None:
manager = plugin_manager()
monkeypatch.setattr(
manager.hook, "attach_sanic_app_extensions", MagicMock(return_value=None)
)
app_mock = MagicMock()

# Create a MagicMock object to replace the create_app() method
create_app_mock = MagicMock(return_value=app_mock)

# Set the create_app() method to return create_app_mock
monkeypatch.setattr("rasa_sdk.endpoint.create_app", create_app_mock)

# Set the return value of app_mock.run() to None
app_mock.run.return_value = None

with warnings.catch_warnings():
warnings.simplefilter("error")
endpoint.run("actions")
manager.hook.attach_sanic_app_extensions.assert_called_once_with(app=app_mock)