diff --git a/changelog/6966.improvement.md b/changelog/6966.improvement.md new file mode 100644 index 000000000000..6f3a38eb70d8 --- /dev/null +++ b/changelog/6966.improvement.md @@ -0,0 +1 @@ +Added warning for when an option is provided for a [component](components.mdx) that is not listed as a key in the defaults for that component. diff --git a/rasa/nlu/components.py b/rasa/nlu/components.py index 8d27f91d8356..47bc38e5d902 100644 --- a/rasa/nlu/components.py +++ b/rasa/nlu/components.py @@ -91,13 +91,35 @@ def validate_requirements(component_names: List[Optional[Text]]) -> None: ) +def validate_component_keys( + component: "Component", component_config: Dict[Text, Any] +) -> None: + """Validates that all keys for a component are valid. + + Args: + component: The component class + component_config: The user-provided config for the component in the pipeline + """ + component_name = component_config.get("name") + allowed_keys = set(component.defaults.keys()) + provided_keys = set(component_config.keys()) + provided_keys.discard("name") + list_separator = "\n- " + for key in provided_keys: + if key not in allowed_keys: + rasa.shared.utils.io.raise_warning( + f"You have provided an invalid key `{key}` for component `{component_name}` in your pipeline. " + f"Valid options for `{component_name}` are:\n- " + f"{list_separator.join(allowed_keys)}" + ) + + def validate_empty_pipeline(pipeline: List["Component"]) -> None: """Ensures the pipeline is not empty. Args: pipeline: the list of the :class:`rasa.nlu.components.Component`. """ - if len(pipeline) == 0: raise InvalidConfigError( "Can not train an empty pipeline. " diff --git a/rasa/nlu/model.py b/rasa/nlu/model.py index bc89023c9a7e..241863aeb7da 100644 --- a/rasa/nlu/model.py +++ b/rasa/nlu/model.py @@ -161,13 +161,13 @@ def _build_pipeline( self, cfg: RasaNLUModelConfig, component_builder: ComponentBuilder ) -> List[Component]: """Transform the passed names of the pipeline components into classes.""" - pipeline = [] # Transform the passed names of the pipeline components into classes - for i in range(len(cfg.pipeline)): - component_cfg = cfg.for_component(i) + for index, pipeline_component in enumerate(cfg.pipeline): + component_cfg = cfg.for_component(index) component = component_builder.create_component(component_cfg, cfg) + components.validate_component_keys(component, pipeline_component) pipeline.append(component) if not self.skip_validation: diff --git a/tests/nlu/test_components.py b/tests/nlu/test_components.py index 3362b8848d76..54636294086c 100644 --- a/tests/nlu/test_components.py +++ b/tests/nlu/test_components.py @@ -7,6 +7,7 @@ from rasa.nlu.components import Component, ComponentBuilder, find_unavailable_packages from rasa.nlu.config import InvalidConfigError, RasaNLUModelConfig from rasa.nlu.model import Interpreter, Metadata +from tests.nlu.conftest import DEFAULT_DATA_PATH @pytest.mark.parametrize("component_class", registry.component_classes) @@ -98,7 +99,7 @@ async def test_example_component(component_builder: ComponentBuilder, tmp_path: (trainer, trained, persisted_path) = await train( _config, - data="./data/examples/rasa/demo-rasa.json", + data=DEFAULT_DATA_PATH, path=str(tmp_path), component_builder=component_builder, ) @@ -198,5 +199,19 @@ async def test_validate_requirements_raises_exception_on_component_without_name( with pytest.raises(InvalidConfigError): await train( - _config, data="./data/examples/rasa/demo-rasa.json", path=str(tmp_path), + _config, data=DEFAULT_DATA_PATH, path=str(tmp_path), ) + + +async def test_validate_component_keys_raises_warning_on_invalid_key(tmp_path: Path,): + _config = RasaNLUModelConfig( + # config with a component that does not have a `confidence_threshold ` property + {"pipeline": [{"name": "WhitespaceTokenizer", "confidence_threshold": 0.7}]} + ) + + with pytest.warns(UserWarning) as record: + await train( + _config, data=DEFAULT_DATA_PATH, path=str(tmp_path), + ) + + assert "You have provided an invalid key" in record[0].message.args[0]