dc6079821b
CI Github Actions / Run Tests (push) Waiting to run
Automatic PR Merger / mergepal (push) Waiting to run
Semgrep / Semgrep Workflow Security Scan (push) Waiting to run
Docs Tests / Check for file changes (push) Has been cancelled
Docs Tests / Test Documentation (push) Has been cancelled
Docs Tests / Documentation Linting Checks (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.9) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.9) (push) Has been cancelled
Continuous Integration / Check for file changes (push) Has been cancelled
Continuous Integration / Wait for docs tests (push) Has been cancelled
Continuous Integration / Code Quality (push) Has been cancelled
Continuous Integration / Check for changelog (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Upload coverage reports to codeclimate (push) Has been cancelled
Continuous Integration / Run Non-Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Run Broker Integration Tests (push) Has been cancelled
Continuous Integration / Run Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Build Docker base images and setup environment (push) Has been cancelled
Continuous Integration / Build Docker (default) (push) Has been cancelled
Continuous Integration / Build Docker (full) (push) Has been cancelled
Continuous Integration / Build Docker (mitie-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-de) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-it) (push) Has been cancelled
Continuous Integration / Deploy to PyPI (push) Has been cancelled
Continuous Integration / Notify Slack & Publish Release Notes (push) Has been cancelled
Publish Documentation / Evaluate release tag (push) Has been cancelled
Publish Documentation / Prebuild Docs (push) Has been cancelled
Publish Documentation / Preview Docs (push) Has been cancelled
Publish Documentation / Check for file changes (push) Has been cancelled
Publish Documentation / Publish Docs (push) Has been cancelled
859 lines
28 KiB
Python
859 lines
28 KiB
Python
import textwrap
|
|
import warnings
|
|
from typing import Text
|
|
|
|
import pytest
|
|
from _pytest.logging import LogCaptureFixture
|
|
from rasa.shared.constants import LATEST_TRAINING_DATA_FORMAT_VERSION
|
|
|
|
from rasa.validator import Validator
|
|
|
|
from rasa.shared.importers.rasa import RasaFileImporter
|
|
from pathlib import Path
|
|
|
|
|
|
@pytest.fixture(scope="class")
|
|
def validator_under_test() -> Validator:
|
|
importer = RasaFileImporter(
|
|
domain_path="data/test_validation/domain.yml",
|
|
training_data_paths=[
|
|
"data/test_validation/data/nlu.yml",
|
|
"data/test_validation/data/stories.yml",
|
|
],
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
return validator
|
|
|
|
|
|
def test_verify_nlu_with_e2e_story(tmp_path: Path, nlu_data_path: Path):
|
|
story_file_name = tmp_path / "stories.yml"
|
|
with open(story_file_name, "w") as file:
|
|
file.write(
|
|
"""
|
|
stories:
|
|
- story: path 1
|
|
steps:
|
|
- user: |
|
|
hello assistant! Can you help me today?
|
|
- intent: greet
|
|
- action: utter_greet
|
|
- intent: affirm
|
|
- action: utter_greet
|
|
- intent: bot_challenge
|
|
- action: utter_greet
|
|
- intent: deny
|
|
- action: goodbye
|
|
- intent: goodbye
|
|
- action: utter_goodbye
|
|
- intent: mood_great
|
|
- action: utter_happy
|
|
- intent: mood_unhappy
|
|
- action: utter_cheer_up
|
|
- action: utter_did_that_help
|
|
- action: utter_iamabot
|
|
"""
|
|
)
|
|
importer = RasaFileImporter(
|
|
config_file="data/test_moodbot/config.yml",
|
|
domain_path="data/test_moodbot/domain.yml",
|
|
training_data_paths=[story_file_name, nlu_data_path],
|
|
)
|
|
|
|
validator = Validator.from_importer(importer)
|
|
# Since the nlu file actually fails validation,
|
|
# record warnings to make sure that the only raised warning
|
|
# is about the duplicate example 'good afternoon'
|
|
with pytest.warns(UserWarning) as record:
|
|
validator.verify_nlu(ignore_warnings=False)
|
|
assert len(record) == 1
|
|
assert (
|
|
"The example 'good afternoon' was found labeled with multiple different"
|
|
in record[0].message.args[0]
|
|
)
|
|
|
|
|
|
def test_verify_intents_does_not_fail_on_valid_data(nlu_data_path: Text):
|
|
importer = RasaFileImporter(
|
|
domain_path="data/test_moodbot/domain.yml", training_data_paths=[nlu_data_path]
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
# force validator to not ignore warnings (default is True)
|
|
assert validator.verify_intents(ignore_warnings=False)
|
|
|
|
|
|
def test_verify_intents_does_fail_on_invalid_data(nlu_data_path: Text):
|
|
# domain and nlu data are from different domain and should produce warnings
|
|
importer = RasaFileImporter(
|
|
domain_path="data/test_domains/default.yml", training_data_paths=[nlu_data_path]
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
# force validator to not ignore warnings (default is True)
|
|
assert not validator.verify_intents(ignore_warnings=False)
|
|
|
|
|
|
def test_verify_valid_responses():
|
|
importer = RasaFileImporter(
|
|
domain_path="data/test_domains/selectors.yml",
|
|
training_data_paths=[
|
|
"data/test_selectors/nlu.yml",
|
|
"data/test_selectors/stories.yml",
|
|
],
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
assert validator.verify_utterances_in_stories()
|
|
|
|
|
|
def test_verify_valid_responses_in_rules(nlu_data_path: Text):
|
|
importer = RasaFileImporter(
|
|
domain_path="data/test_domains/default.yml",
|
|
training_data_paths=[
|
|
nlu_data_path,
|
|
"data/test_yaml_stories/rules_without_stories_and_wrong_names.yml",
|
|
],
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
# force validator to not ignore warnings (default is True)
|
|
assert not validator.verify_utterances_in_stories(ignore_warnings=False)
|
|
|
|
|
|
def test_verify_story_structure(stories_path: Text):
|
|
importer = RasaFileImporter(
|
|
domain_path="data/test_domains/default.yml", training_data_paths=[stories_path]
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
# force validator to not ignore warnings (default is True)
|
|
assert validator.verify_story_structure(ignore_warnings=False)
|
|
|
|
|
|
def test_verify_bad_story_structure():
|
|
importer = RasaFileImporter(
|
|
domain_path="data/test_domains/default.yml",
|
|
training_data_paths=["data/test_yaml_stories/stories_conflicting_2.yml"],
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
# force validator to not ignore warnings (default is True)
|
|
assert not validator.verify_story_structure(ignore_warnings=False)
|
|
|
|
|
|
def test_verify_bad_e2e_story_structure_when_text_identical(tmp_path: Path):
|
|
story_file_name = tmp_path / "stories.yml"
|
|
story_file_name.write_text(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
stories:
|
|
- story: path 1
|
|
steps:
|
|
- user: |
|
|
amazing!
|
|
- action: utter_happy
|
|
- story: path 2 (should always conflict path 1)
|
|
steps:
|
|
- user: |
|
|
amazing!
|
|
- action: utter_cheer_up
|
|
"""
|
|
)
|
|
# The two stories with identical user texts
|
|
importer = RasaFileImporter(
|
|
config_file="data/test_config/config_defaults.yml",
|
|
domain_path="data/test_domains/default.yml",
|
|
training_data_paths=[story_file_name],
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
# force validator to not ignore warnings (default is True)
|
|
assert not validator.verify_story_structure(ignore_warnings=False)
|
|
|
|
|
|
def test_verify_correct_e2e_story_structure(tmp_path: Path):
|
|
story_file_name = tmp_path / "stories.yml"
|
|
with open(story_file_name, "w") as file:
|
|
file.write(
|
|
"""
|
|
stories:
|
|
- story: path 1
|
|
steps:
|
|
- user: |
|
|
hello assistant! Can you help me today?
|
|
- action: utter_greet
|
|
- story: path 2 - state is similar but different from the one in path 1
|
|
steps:
|
|
- user: |
|
|
hello assistant! you Can help me today?
|
|
- action: utter_goodbye
|
|
- story: path 3
|
|
steps:
|
|
- user: |
|
|
That's it for today. Chat again tomorrow!
|
|
- action: utter_goodbye
|
|
"""
|
|
)
|
|
importer = RasaFileImporter(
|
|
config_file="data/test_config/config_defaults.yml",
|
|
domain_path="data/test_domains/default.yml",
|
|
training_data_paths=[story_file_name],
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
# force validator to not ignore warnings (default is True)
|
|
assert validator.verify_story_structure(ignore_warnings=False)
|
|
|
|
|
|
def test_verify_correct_e2e_story_structure_with_intents(tmp_path: Path):
|
|
story_file_name = tmp_path / "stories.yml"
|
|
with open(story_file_name, "w") as file:
|
|
file.write(
|
|
"""
|
|
stories:
|
|
- story: path 1
|
|
steps:
|
|
- intent: greet
|
|
- action: utter_greet
|
|
- story: path 2
|
|
steps:
|
|
- intent: goodbye
|
|
- action: utter_goodbye
|
|
"""
|
|
)
|
|
importer = RasaFileImporter(
|
|
config_file="data/test_config/config_defaults.yml",
|
|
domain_path="data/test_domains/default.yml",
|
|
training_data_paths=[story_file_name],
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
# force validator to not ignore warnings (default is True)
|
|
assert validator.verify_story_structure(ignore_warnings=False)
|
|
|
|
|
|
def test_verify_story_structure_ignores_rules():
|
|
importer = RasaFileImporter(
|
|
domain_path="data/test_domains/default.yml",
|
|
training_data_paths=[
|
|
"data/test_yaml_stories/stories_with_rules_conflicting.yml"
|
|
],
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
assert validator.verify_story_structure(ignore_warnings=False)
|
|
|
|
|
|
def test_verify_bad_story_structure_ignore_warnings():
|
|
importer = RasaFileImporter(
|
|
domain_path="data/test_domains/default.yml",
|
|
training_data_paths=["data/test_yaml_stories/stories_conflicting_2.yml"],
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
assert validator.verify_story_structure(ignore_warnings=True)
|
|
|
|
|
|
def test_verify_there_is_example_repetition_in_intents(nlu_data_path: Text):
|
|
# moodbot nlu data already has duplicated example 'good afternoon'
|
|
# for intents greet and goodbye
|
|
|
|
importer = RasaFileImporter(
|
|
domain_path="data/test_moodbot/domain.yml", training_data_paths=[nlu_data_path]
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
# force validator to not ignore warnings (default is True)
|
|
assert not validator.verify_example_repetition_in_intents(ignore_warnings=False)
|
|
|
|
|
|
def test_verify_logging_message_for_intent_not_used_in_nlu(
|
|
caplog: LogCaptureFixture, validator_under_test: Validator
|
|
):
|
|
caplog.clear()
|
|
with pytest.warns(UserWarning) as record:
|
|
# force validator to not ignore warnings (default is True)
|
|
validator_under_test.verify_intents(ignore_warnings=False)
|
|
|
|
assert (
|
|
"The intent 'goodbye' is listed in the domain file, "
|
|
"but is not found in the NLU training data."
|
|
in (m.message.args[0] for m in record)
|
|
)
|
|
|
|
|
|
def test_verify_logging_message_for_intent_not_used_in_story(
|
|
caplog: LogCaptureFixture, validator_under_test: Validator
|
|
):
|
|
caplog.clear()
|
|
with pytest.warns(UserWarning) as record:
|
|
# force validator to not ignore warnings (default is True)
|
|
validator_under_test.verify_intents_in_stories(ignore_warnings=False)
|
|
|
|
assert "The intent 'goodbye' is not used in any story or rule." in (
|
|
m.message.args[0] for m in record
|
|
)
|
|
|
|
|
|
def test_verify_logging_message_for_unused_utterance(
|
|
caplog: LogCaptureFixture, validator_under_test: Validator
|
|
):
|
|
caplog.clear()
|
|
with pytest.warns(UserWarning) as record:
|
|
# force validator to not ignore warnings (default is True)
|
|
validator_under_test.verify_utterances_in_stories(ignore_warnings=False)
|
|
|
|
assert "The utterance 'utter_chatter' is not used in any story or rule." in (
|
|
m.message.args[0] for m in record
|
|
)
|
|
|
|
|
|
def test_verify_logging_message_for_repetition_in_intents(caplog, nlu_data_path: Text):
|
|
# moodbot nlu data already has duplicated example 'good afternoon'
|
|
# for intents greet and goodbye
|
|
importer = RasaFileImporter(
|
|
domain_path="data/test_moodbot/domain.yml", training_data_paths=[nlu_data_path]
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
caplog.clear() # clear caplog to avoid counting earlier debug messages
|
|
with pytest.warns(UserWarning) as record:
|
|
# force validator to not ignore warnings (default is True)
|
|
validator.verify_example_repetition_in_intents(ignore_warnings=False)
|
|
assert len(record) == 1
|
|
assert "You should fix that conflict " in record[0].message.args[0]
|
|
|
|
|
|
def test_early_exit_on_invalid_domain():
|
|
domain_path = "data/test_domains/duplicate_intents.yml"
|
|
|
|
importer = RasaFileImporter(domain_path=domain_path)
|
|
with pytest.warns(UserWarning) as record:
|
|
warnings.simplefilter("ignore", DeprecationWarning)
|
|
validator = Validator.from_importer(importer)
|
|
validator.verify_domain_validity()
|
|
|
|
# two for non-unique domains, 2 for auto-fill removal
|
|
assert len(record) == 4
|
|
|
|
non_unique_warnings = list(
|
|
filter(
|
|
lambda warning: f"Loading domain from '{domain_path}' failed. "
|
|
f"Using empty domain. Error: 'Intents are not unique! "
|
|
f"Found multiple intents with name(s) ['default', 'goodbye']. "
|
|
f"Either rename or remove the duplicate ones.'" in warning.message.args[0],
|
|
record,
|
|
)
|
|
)
|
|
assert len(non_unique_warnings) == 2
|
|
|
|
auto_fill_warnings = list(
|
|
filter(
|
|
lambda warning: "Slot auto-fill has been removed in 3.0"
|
|
in warning.message.args[0],
|
|
record,
|
|
)
|
|
)
|
|
assert len(auto_fill_warnings) == 2
|
|
|
|
|
|
def test_verify_there_is_not_example_repetition_in_intents():
|
|
importer = RasaFileImporter(
|
|
domain_path="data/test_moodbot/domain.yml",
|
|
training_data_paths=["examples/knowledgebasebot/data/nlu.yml"],
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
# force validator to not ignore warnings (default is True)
|
|
assert validator.verify_example_repetition_in_intents(ignore_warnings=False)
|
|
|
|
|
|
def test_verify_actions_in_stories_not_in_domain(tmp_path: Path, domain_path: Text):
|
|
story_file_name = tmp_path / "stories.yml"
|
|
story_file_name.write_text(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
stories:
|
|
- story: story path 1
|
|
steps:
|
|
- intent: greet
|
|
- action: action_test_1
|
|
"""
|
|
)
|
|
|
|
importer = RasaFileImporter(
|
|
domain_path=domain_path, training_data_paths=[story_file_name]
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
with pytest.warns(UserWarning) as warning:
|
|
validity = validator.verify_actions_in_stories_rules()
|
|
assert validity is False
|
|
|
|
assert (
|
|
"The action 'action_test_1' is used in the 'story path 1' block, "
|
|
"but it is not listed in the domain file." in warning[0].message.args[0]
|
|
)
|
|
|
|
|
|
def test_verify_actions_in_rules_not_in_domain(tmp_path: Path, domain_path: Text):
|
|
rules_file_name = tmp_path / "rules.yml"
|
|
rules_file_name.write_text(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
rules:
|
|
- rule: rule path 1
|
|
steps:
|
|
- intent: goodbye
|
|
- action: action_test_2
|
|
"""
|
|
)
|
|
importer = RasaFileImporter(
|
|
domain_path=domain_path, training_data_paths=[rules_file_name]
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
with pytest.warns(UserWarning) as warning:
|
|
validity = validator.verify_actions_in_stories_rules()
|
|
assert validity is False
|
|
|
|
assert (
|
|
"The action 'action_test_2' is used in the 'rule path 1' block, "
|
|
"but it is not listed in the domain file." in warning[0].message.args[0]
|
|
)
|
|
|
|
|
|
def test_verify_form_slots_invalid_domain(tmp_path: Path):
|
|
domain = tmp_path / "domain.yml"
|
|
domain.write_text(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
forms:
|
|
name_form:
|
|
required_slots:
|
|
- first_name
|
|
- last_nam
|
|
slots:
|
|
first_name:
|
|
type: text
|
|
mappings:
|
|
- type: from_text
|
|
last_name:
|
|
type: text
|
|
mappings:
|
|
- type: from_text
|
|
"""
|
|
)
|
|
importer = RasaFileImporter(domain_path=domain)
|
|
validator = Validator.from_importer(importer)
|
|
with pytest.warns(UserWarning) as w:
|
|
validity = validator.verify_form_slots()
|
|
assert validity is False
|
|
|
|
assert (
|
|
w[0].message.args[0] == "The form slot 'last_nam' in form 'name_form' "
|
|
"is not present in the domain slots."
|
|
"Please add the correct slot or check for typos."
|
|
)
|
|
|
|
|
|
def test_response_selector_responses_in_domain_no_errors():
|
|
importer = RasaFileImporter(
|
|
config_file="data/test_config/config_defaults.yml",
|
|
domain_path="data/test_domains/response_selector_responses_in_domain.yml",
|
|
training_data_paths=[
|
|
"data/test_yaml_stories/test_base_retrieval_intent_story.yml"
|
|
],
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
# force validator to not ignore warnings (default is True)
|
|
assert validator.verify_utterances_in_stories(ignore_warnings=False)
|
|
|
|
|
|
def test_invalid_domain_mapping_policy():
|
|
importer = RasaFileImporter(
|
|
domain_path="data/test_domains/default_with_mapping.yml"
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
assert validator.verify_domain_validity() is False
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("file_name", "data_type"), [("stories", "story"), ("rules", "rule")]
|
|
)
|
|
def test_valid_stories_rules_actions_in_domain(
|
|
file_name: Text, data_type: Text, tmp_path: Path
|
|
):
|
|
domain = tmp_path / "domain.yml"
|
|
domain.write_text(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
intents:
|
|
- greet
|
|
actions:
|
|
- action_greet
|
|
"""
|
|
)
|
|
file_name = tmp_path / f"{file_name}.yml"
|
|
file_name.write_text(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
{file_name}:
|
|
- {data_type}: test path
|
|
steps:
|
|
- intent: greet
|
|
- action: action_greet
|
|
"""
|
|
)
|
|
importer = RasaFileImporter(domain_path=domain, training_data_paths=[file_name])
|
|
validator = Validator.from_importer(importer)
|
|
assert validator.verify_actions_in_stories_rules()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("file_name", "data_type"), [("stories", "story"), ("rules", "rule")]
|
|
)
|
|
def test_valid_stories_rules_default_actions(
|
|
file_name: Text, data_type: Text, tmp_path: Path
|
|
):
|
|
domain = tmp_path / "domain.yml"
|
|
domain.write_text(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
intents:
|
|
- greet
|
|
"""
|
|
)
|
|
file_name = tmp_path / f"{file_name}.yml"
|
|
file_name.write_text(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
{file_name}:
|
|
- {data_type}: test path
|
|
steps:
|
|
- intent: greet
|
|
- action: action_restart
|
|
"""
|
|
)
|
|
importer = RasaFileImporter(domain_path=domain, training_data_paths=[file_name])
|
|
validator = Validator.from_importer(importer)
|
|
assert validator.verify_actions_in_stories_rules()
|
|
|
|
|
|
def test_valid_form_slots_in_domain(tmp_path: Path):
|
|
domain = tmp_path / "domain.yml"
|
|
domain.write_text(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
forms:
|
|
name_form:
|
|
required_slots:
|
|
- first_name
|
|
- last_name
|
|
slots:
|
|
first_name:
|
|
type: text
|
|
mappings:
|
|
- type: from_text
|
|
last_name:
|
|
type: text
|
|
mappings:
|
|
- type: from_text
|
|
"""
|
|
)
|
|
importer = RasaFileImporter(domain_path=domain)
|
|
validator = Validator.from_importer(importer)
|
|
assert validator.verify_form_slots()
|
|
|
|
|
|
def test_verify_slot_mappings_mapping_active_loop_not_in_forms(tmp_path: Path):
|
|
domain = tmp_path / "domain.yml"
|
|
slot_name = "some_slot"
|
|
domain.write_text(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
entities:
|
|
- some_entity
|
|
slots:
|
|
{slot_name}:
|
|
type: text
|
|
influence_conversation: false
|
|
mappings:
|
|
- type: from_entity
|
|
entity: some_entity
|
|
conditions:
|
|
- active_loop: som_form
|
|
forms:
|
|
some_form:
|
|
required_slots:
|
|
- {slot_name}
|
|
"""
|
|
)
|
|
importer = RasaFileImporter(domain_path=domain)
|
|
validator = Validator.from_importer(importer)
|
|
with pytest.warns(
|
|
UserWarning,
|
|
match=r"Slot 'some_slot' has a mapping condition "
|
|
r"for form 'som_form' which is not listed "
|
|
r"in domain forms.*",
|
|
):
|
|
assert not validator.verify_slot_mappings()
|
|
|
|
|
|
def test_verify_slot_mappings_slot_with_mapping_conditions_not_in_form(tmp_path: Path):
|
|
domain = tmp_path / "domain.yml"
|
|
domain.write_text(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
intents:
|
|
- activate_booking
|
|
entities:
|
|
- city
|
|
slots:
|
|
location:
|
|
type: text
|
|
influence_conversation: false
|
|
mappings:
|
|
- type: from_entity
|
|
entity: city
|
|
conditions:
|
|
- active_loop: booking_form
|
|
started_booking_form:
|
|
type: bool
|
|
influence_conversation: false
|
|
mappings:
|
|
- type: from_trigger_intent
|
|
intent: activate_booking
|
|
value: true
|
|
forms:
|
|
booking_form:
|
|
required_slots:
|
|
- started_booking_form
|
|
"""
|
|
)
|
|
importer = RasaFileImporter(domain_path=domain)
|
|
validator = Validator.from_importer(importer)
|
|
with pytest.warns(
|
|
UserWarning,
|
|
match=r"Slot 'location' has a mapping condition for form 'booking_form', "
|
|
r"but it's not present in 'booking_form' form's 'required_slots'.*",
|
|
):
|
|
assert not validator.verify_slot_mappings()
|
|
|
|
|
|
def test_verify_slot_mappings_valid(tmp_path: Path):
|
|
domain = tmp_path / "domain.yml"
|
|
domain.write_text(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
intents:
|
|
- activate_booking
|
|
entities:
|
|
- city
|
|
slots:
|
|
location:
|
|
type: text
|
|
influence_conversation: false
|
|
mappings:
|
|
- type: from_entity
|
|
entity: city
|
|
conditions:
|
|
- active_loop: booking_form
|
|
started_booking_form:
|
|
type: bool
|
|
influence_conversation: false
|
|
mappings:
|
|
- type: from_trigger_intent
|
|
intent: activate_booking
|
|
value: true
|
|
forms:
|
|
booking_form:
|
|
required_slots:
|
|
- started_booking_form
|
|
- location
|
|
"""
|
|
)
|
|
importer = RasaFileImporter(domain_path=domain)
|
|
validator = Validator.from_importer(importer)
|
|
assert validator.verify_slot_mappings()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("file_name", "data_type"), [("stories", "story"), ("rules", "rule")]
|
|
)
|
|
def test_default_action_as_active_loop_in_rules(
|
|
tmp_path: Path, file_name: Text, data_type: Text
|
|
) -> None:
|
|
config = tmp_path / "config.yml"
|
|
|
|
config.write_text(
|
|
textwrap.dedent(
|
|
"""
|
|
recipe: default.v1
|
|
language: en
|
|
pipeline:
|
|
- name: WhitespaceTokenizer
|
|
- name: RegexFeaturizer
|
|
- name: LexicalSyntacticFeaturizer
|
|
- name: CountVectorsFeaturizer
|
|
- name: CountVectorsFeaturizer
|
|
analyzer: char_wb
|
|
min_ngram: 1
|
|
max_ngram: 4
|
|
- name: DIETClassifier
|
|
epochs: 100
|
|
- name: EntitySynonymMapper
|
|
- name: ResponseSelector
|
|
epochs: 100
|
|
- name: FallbackClassifier
|
|
threshold: 0.3
|
|
ambiguity_threshold: 0.1
|
|
policies:
|
|
- name: MemoizationPolicy
|
|
- name: TEDPolicy
|
|
max_history: 5
|
|
epochs: 100
|
|
- name: RulePolicy
|
|
core_fallback_threshold: 0.3
|
|
core_fallback_action_name: "action_default_fallback"
|
|
enable_fallback_prediction: true
|
|
"""
|
|
)
|
|
)
|
|
|
|
domain = tmp_path / "domain.yml"
|
|
domain.write_text(
|
|
textwrap.dedent(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
intents:
|
|
- greet
|
|
- goodbye
|
|
- affirm
|
|
- deny
|
|
- mood_great
|
|
- mood_unhappy
|
|
- bot_challenge
|
|
responses:
|
|
utter_greet:
|
|
- text: "Hey! How are you?"
|
|
utter_cheer_up:
|
|
- text: "Here is something to cheer you up:"
|
|
image: "https://i.imgur.com/nGF1K8f.jpg"
|
|
utter_did_that_help:
|
|
- text: "Did that help you?"
|
|
utter_happy:
|
|
- text: "Great, carry on!"
|
|
utter_goodbye:
|
|
- text: "Bye"
|
|
utter_iamabot:
|
|
- text: "I am a bot, powered by Rasa."
|
|
session_config:
|
|
session_expiration_time: 60
|
|
carry_over_slots_to_new_session: true
|
|
"""
|
|
)
|
|
)
|
|
file = tmp_path / f"{file_name}.yml"
|
|
file.write_text(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
{file_name}:
|
|
- {data_type}: test
|
|
steps:
|
|
- intent: nlu_fallback
|
|
- action: action_two_stage_fallback
|
|
- active_loop: action_two_stage_fallback
|
|
"""
|
|
)
|
|
importer = RasaFileImporter(
|
|
config_file=str(config), domain_path=str(domain), training_data_paths=str(file)
|
|
)
|
|
validator = Validator.from_importer(importer)
|
|
assert validator.verify_forms_in_stories_rules()
|
|
|
|
|
|
def test_verify_from_trigger_intent_slot_mapping_not_in_forms_does_not_warn(
|
|
tmp_path: Path,
|
|
):
|
|
domain = tmp_path / "domain.yml"
|
|
slot_name = "started_booking_form"
|
|
domain.write_text(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
intents:
|
|
- activate_booking
|
|
entities:
|
|
- city
|
|
slots:
|
|
{slot_name}:
|
|
type: bool
|
|
influence_conversation: false
|
|
mappings:
|
|
- type: from_trigger_intent
|
|
intent: activate_booking
|
|
value: true
|
|
location:
|
|
type: text
|
|
mappings:
|
|
- type: from_entity
|
|
entity: city
|
|
forms:
|
|
booking_form:
|
|
required_slots:
|
|
- location
|
|
"""
|
|
)
|
|
importer = RasaFileImporter(domain_path=domain)
|
|
validator = Validator.from_importer(importer)
|
|
with warnings.catch_warnings():
|
|
warnings.simplefilter("error")
|
|
assert validator.verify_slot_mappings()
|
|
|
|
|
|
def test_verify_utterances_does_not_error_when_no_utterance_template_provided(
|
|
tmp_path: Path, nlu_data_path: Path
|
|
):
|
|
story_file_name = tmp_path / "stories.yml"
|
|
with open(story_file_name, "w") as file:
|
|
file.write(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
stories:
|
|
- story: path 1
|
|
steps:
|
|
- intent: greet
|
|
- action: utter_greet
|
|
"""
|
|
)
|
|
domain_file_name = tmp_path / "domain.yml"
|
|
with open(domain_file_name, "w") as file:
|
|
file.write(
|
|
f"""
|
|
version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
|
|
intents:
|
|
- greet
|
|
actions:
|
|
- utter_greet
|
|
"""
|
|
)
|
|
importer = RasaFileImporter(
|
|
config_file="data/test_moodbot/config.yml",
|
|
domain_path=domain_file_name,
|
|
training_data_paths=[story_file_name, nlu_data_path],
|
|
)
|
|
|
|
validator = Validator.from_importer(importer)
|
|
# force validator to not ignore warnings (default is True)
|
|
assert not validator.verify_utterances_in_stories(ignore_warnings=False)
|
|
# test whether ignoring warnings actually works
|
|
assert validator.verify_utterances_in_stories(ignore_warnings=True)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"config_file, message",
|
|
[
|
|
(
|
|
"data/test_config/config_defaults.yml",
|
|
"The config file is missing a unique value for "
|
|
"the 'assistant_id' mandatory key.",
|
|
),
|
|
(
|
|
"data/test_config/config_no_assistant_id.yml",
|
|
"The config file is missing the 'assistant_id' mandatory key.",
|
|
),
|
|
],
|
|
)
|
|
def test_warn_if_config_mandatory_keys_are_not_set_invalid_paths(
|
|
config_file: Text, message: Text
|
|
) -> None:
|
|
importer = RasaFileImporter(config_file=config_file)
|
|
validator = Validator.from_importer(importer)
|
|
|
|
with pytest.warns(UserWarning, match=message):
|
|
validator.warn_if_config_mandatory_keys_are_not_set()
|