Fix PR feedback.
MODIFY
rasa_sdk/endpoint.py
rasa_sdk/endpoint.py
@@ -61,6 +61,17 @@ def create_app(
cors_origins: Union[Text, List[Text], None] = "*",
auto_reload: bool = False,
) -> Sanic:
+ """Create a Sanic application and return it.
+
+ Args:
+ action_package_name: Name of the package or module to load actions
+ from.
+ cors_origins: CORS origins to allow.
+ auto_reload: When `True`, auto-reloading of actions is enabled.
+
+ Returns:
+ A new Sanic application ready to be run.
+ """
app = Sanic(__name__, configure_logging=False)
configure_cors(app, cors_origins)

MODIFY
rasa_sdk/executor.py
rasa_sdk/executor.py
@@ -4,6 +4,7 @@ import logging
import pkgutil
import warnings
from typing import Text, List, Dict, Any, Type, Union, Callable, Optional
+from collections import namedtuple
import typing
import types
import sys
@@ -141,10 +142,12 @@ class CollectingDispatcher:
self.utter_message(image=image, **kwargs)
+TimestampModule = namedtuple("TimestampModule", ["timestamp", "module"])
+
class ActionExecutor:
def __init__(self):
self.actions = {}
- self._modules = {}
+ self._modules: Dict[Text, TimestampModule] = {}
def register_action(self, action: Union[Type["Action"], "Action"]) -> None:
if inspect.isclass(action):
@@ -230,7 +233,7 @@ class ActionExecutor:
# without __init__.py), then there's nothing to watch for the
# package itself.
timestamp = os.path.getmtime(module_file)
- self._modules[module_file] = (timestamp, module)
+ self._modules[module_file] = TimestampModule(timestamp, module)
return module
@@ -238,6 +241,9 @@ class ActionExecutor:
"""Register all the `Action` subclasses contained in a Python module or
package.
+ If an `ImportError` is raised when loading the module or package, the
+ action server is stopped with exit code 1.
+
Args:
package: Module or package name, or an already loaded Python module.
"""
@@ -266,18 +272,15 @@ class ActionExecutor:
):
self.register_action(action)
- def reload(self) -> None:
- """Reload all Python modules that have been loaded in the past.
-
- To check if a module should be reloaded, the file's last timestamp is
- checked against the current one. If the current last-modified timestamp
- is larger than the previous one, the module is re-imported using
- `importlib.reload`.
+ def _find_modules_to_reload(self) -> Dict[Text, TimestampModule]:
+ """Finds all Python modules that should be reloaded by checking their
+ files' timestamps.
- If one or more modules are reloaded during this process, the entire
- `Action` class hierarchy is scanned again to see what new classes can
- be registered.
+ Returns:
+ Dictionary containing file paths, new timestamps and Python modules
+ that should be reloaded.
"""
+
to_reload = {}
for path, (timestamp, module) in self._modules.items():
@@ -288,19 +291,34 @@ class ActionExecutor:
continue
if new_timestamp > timestamp:
- to_reload[path] = (new_timestamp, module)
+ to_reload[path] = TimestampModule(new_timestamp, module)
- module_reloaded = False
+ return to_reload
+
+ def reload(self) -> None:
+ """Reload all Python modules that have been loaded in the past.
+
+ To check if a module should be reloaded, the file's last timestamp is
+ checked against the current one. If the current last-modified timestamp
+ is larger than the previous one, the module is re-imported using
+ `importlib.reload`.
+
+ If one or more modules are reloaded during this process, the entire
+ `Action` class hierarchy is scanned again to see what new classes can
+ be registered.
+ """
+ to_reload = self._find_modules_to_reload()
+ any_module_reloaded = False
for path, (timestamp, module) in to_reload.items():
try:
new_module = importlib.reload(module)
- self._modules[path] = (timestamp, new_module)
+ self._modules[path] = TimestampModule(timestamp, new_module)
logger.info(
f"Reloaded module/package: '{module.__name__}' "
f"(file: '{os.path.relpath(path)}')"
)
- module_reloaded = True
+ any_module_reloaded = True
except (SyntaxError, ImportError):
logger.exception(
f"Error while reloading module/package: '{module.__name__}' "
@@ -308,7 +326,7 @@ class ActionExecutor:
)
logger.info("Please fix the error(s) in the Python file and try again.")
- if module_reloaded:
+ if any_module_reloaded:
self._register_all_actions()
@staticmethod

MODIFY
tests/test_executor.py
tests/test_executor.py
@@ -3,7 +3,7 @@ import shutil
import random
import string
import time
-from typing import Text
+from typing import Text, Optional, Generator
import pytest
from rasa_sdk.executor import ActionExecutor, CollectingDispatcher
@@ -28,7 +28,7 @@ def _write_action_file(
file_name: Text,
class_name: Text,
action_name: Text,
- message: Text = None,
+ message: Optional[Text] = None,
) -> None:
with open(os.path.join(package_path, file_name), "w") as f:
f.write(
@@ -68,7 +68,7 @@ def test_deprecated_utter_elements():
@pytest.fixture()
-def package_path() -> None:
+def package_path() -> Generator[Text, None, Text]:
# Create an empty directory somewhere reached by the Python import search
# paths
name = "".join(random.choice(string.ascii_lowercase) for _ in range(10))

Fix PR feedback.