Exemple #1
0
def test_migrate_domain_raises_when_backup_location_exists(
    tmp_path: Path, migrate_file_only: bool
):
    domain_dir = tmp_path / "domain"
    domain_file_name = "domain.yml"
    domain_dir.mkdir()
    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        intents: []
        """,
        domain_file_name,
    )

    if not migrate_file_only:
        domain_path = domain_dir
        backup_location = tmp_path / migrate.ORIGINAL_DOMAIN
        backup_location.mkdir()
    else:
        domain_path = domain_dir / domain_file_name
        backup_location = domain_dir / (migrate.ORIGINAL_DOMAIN + migrate.YML_SUFFIX)
        with open(backup_location, "w"):
            pass

    with pytest.raises(
        RasaException, match="The domain could not be migrated since .* exists.*"
    ):
        migrate.migrate_domain_format(domain_path, None)
Exemple #2
0
def test_migrate_domain_raises_exception_for_non_domain_file(tmp_path: Path):
    domain_file = prepare_domain_path(
        tmp_path,
        """
        version: "2.0"
        nlu:
        - intent: greet
          examples: |
            - hey
            - hello
            - hi
            - hello there
            - good morning
            - good evening
            - moin
            - hey there
        """,
        "domain.yml",
    )

    new_domain_file = tmp_path / "new_domain.yml"

    with pytest.raises(
        RasaException,
        match=f"The file '{domain_file.as_posix()}' could not "
        f"be validated as a domain file.",
    ):
        migrate.migrate_domain_format(domain_file, new_domain_file)
Exemple #3
0
def test_migrate_domain_raises_for_non_domain_files(tmp_path: Path):
    domain_dir = tmp_path / "domain"
    domain_dir.mkdir()

    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        nlu:
        - intent: greet
          examples: |
            - hey
            - hello
            - hi
            - hello there
            - good morning
            - good evening
            - moin
            - hey there
        """,
        "domain.yml",
    )

    with pytest.raises(
        RasaException,
        match=f"The domain directory '{domain_dir.as_posix()}' does not contain any "
        f"domain files. Please make sure to include these for a successful "
        f"migration.",
    ):
        migrate.migrate_domain_format(domain_dir, None)
Exemple #4
0
def test_migrate_domain_format_with_custom_slot(tmp_path: Path,
                                                domain_out_file: Path):
    existing_domain_file = prepare_domain_path(
        tmp_path,
        """
        version: "2.0"
        intents:
        - greet
        - affirm
        - inform
        entities:
        - city
        - name
        slots:
          location:
            type: text
            influence_conversation: false
          name:
            type: text
            influence_conversation: false
            auto_fill: false
          email:
            type: text
            influence_conversation: false
        forms:
           booking_form:
               ignored_intents:
               - greet
               required_slots:
                 location:
                 - type: from_entity
                   entity: city
                 email:
                 - type: from_text
                   intent: inform
        """,
        "domain.yml",
    )

    with pytest.warns(UserWarning,
                      match="A custom mapping was added to slot 'name'."):
        migrate.migrate_domain_format(existing_domain_file, domain_out_file)

    domain = Domain.from_path(domain_out_file)
    assert domain

    migrated_domain = rasa.shared.utils.io.read_yaml_file(domain_out_file)
    migrated_slots = migrated_domain.get("slots")
    custom_slot = migrated_slots.get("name")
    assert custom_slot == {
        "type": "text",
        "influence_conversation": False,
        "mappings": [{
            "type": "custom"
        }],
    }
Exemple #5
0
def test_migrate_domain_with_no_requested_slot_for_from_entity_mappings(
        tmp_path: Path, domain_out_file: Path):
    existing_domain_file = prepare_domain_path(
        tmp_path,
        """
        version: "2.0"
        intents:
        - greet
        - affirm
        - inform
        entities:
        - city
        slots:
          location:
            type: text
            influence_conversation: false
          email:
            type: text
            influence_conversation: false
        forms:
            some_form:
                location:
                - entity: city
                  type: from_entity
                - intent: something
                  type: from_text
        """,
        "domain.yml",
    )

    migrate.migrate_domain_format(existing_domain_file, domain_out_file)

    domain = Domain.from_path(domain_out_file)
    assert domain

    migrated_domain = rasa.shared.utils.io.read_yaml_file(domain_out_file)
    migrated_slots = migrated_domain.get("slots")
    location_slot = migrated_slots.get("location")
    mappings = location_slot.get("mappings")
    assert mappings[0] == {
        "entity": "city",
        "type": "from_entity",
        "conditions": [{
            "active_loop": "some_form"
        }],
    }
    assert mappings[1] == {
        "intent": "something",
        "type": "from_text",
        "conditions": [{
            "active_loop": "some_form",
            "requested_slot": "location"
        }],
    }
Exemple #6
0
def test_migrate_domain_format_from_dir(tmp_path: Path):
    domain_dir = tmp_path / "domain"
    domain_dir.mkdir()

    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        entities:
            - outdoor
        slots:
          outdoor_seating:
           type: bool
           influence_conversation: false
        """,
        "slots.yml",
    )

    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        forms:
          reservation_form:
            required_slots:
               outdoor_seating:
               - type: from_intent
                 value: true
                 intent: confirm
        """,
        "forms.yml",
    )

    domain_out_dir = tmp_path / "new_domain"
    domain_out_dir.mkdir()

    migrate.migrate_domain_format(domain_dir, domain_out_dir)
    domain = Domain.from_directory(str(domain_out_dir))

    assert domain

    old_domain_path = tmp_path / "original_domain"
    assert old_domain_path.exists()

    for file in old_domain_path.iterdir():
        assert file.name in ["slots.yml", "forms.yml"]

    for file in domain_out_dir.iterdir():
        assert file.name in ["slots.yml", "forms.yml"]
        migrated_file = rasa.shared.utils.io.read_yaml_file(file)

        migrated_training_data_version = migrated_file.get("version")
        assert migrated_training_data_version == LATEST_TRAINING_DATA_FORMAT_VERSION
Exemple #7
0
def test_migrate_domain_from_dir_with_other_sections(tmp_path: Path):
    domain_dir = tmp_path / "domain"
    domain_dir.mkdir()
    domain_file_one = "domain_one.yml"
    domain_file_two = "domain_two.yml"

    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        entities:
        - outdoor
        slots:
          outdoor_seating:
           type: bool
           influence_conversation: false
        """,
        domain_file_one,
    )

    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        intents:
        - greet
        forms:
          reservation_form:
            required_slots:
               outdoor_seating:
               - type: from_intent
                 value: true
                 intent: confirm
        """,
        domain_file_two,
    )

    new_domain_dir = tmp_path / "migrated_domain"
    migrate.migrate_domain_format(domain_dir, new_domain_dir)
    domain = Domain.from_directory(new_domain_dir)
    assert domain

    for file in new_domain_dir.iterdir():
        migrated = rasa.shared.utils.io.read_yaml_file(file)

        migrated_training_data_version = migrated.get("version")
        assert migrated_training_data_version == LATEST_TRAINING_DATA_FORMAT_VERSION

        if file.name == domain_file_one:
            assert migrated.get("entities") == ["outdoor"]
        elif file.name == domain_file_two:
            assert migrated.get("intents") == ["greet"]
Exemple #8
0
def test_migrate_domain_with_diff_slot_types(slot_type: Text, value: Any,
                                             tmp_path: Path,
                                             domain_out_file: Path):
    existing_domain_file = prepare_domain_path(
        tmp_path,
        f"""
        version: "2.0"
        entities:
            - outdoor
        slots:
          outdoor_seating:
           type: {slot_type}
           influence_conversation: false
        forms:
          reservation_form:
            required_slots:
               outdoor_seating:
               - type: from_intent
                 value: {value}
                 intent: confirm
        """,
        "domain.yml",
    )
    migrate.migrate_domain_format(existing_domain_file, domain_out_file)
    domain = Domain.from_path(domain_out_file)
    assert domain

    migrated_domain = rasa.shared.utils.io.read_yaml_file(domain_out_file)
    migrated_slots = migrated_domain.get("slots")
    expected_slots = {
        "outdoor_seating": {
            "type":
            slot_type,
            "influence_conversation":
            False,
            "mappings": [{
                "type":
                "from_intent",
                "value":
                value,
                "intent":
                "confirm",
                "conditions": [{
                    "active_loop": "reservation_form",
                    "requested_slot": "outdoor_seating",
                }],
            }],
        }
    }
    assert migrated_slots == expected_slots
Exemple #9
0
def test_migrate_domain_cleanups_after_raising(
    tmp_path: Path,
    test_case: Callable[[Path], Tuple[Text, Text]],
    default_out_dir: bool,
    out_dir_exists: bool,
):
    # input
    out_path = None if default_out_dir else (tmp_path / "custom_out_path")
    domain_path, error_msg_match = test_case(tmp_path)
    migrating_file_only = domain_path.is_file()
    domain_files = list(domain_path.iterdir())

    # paths to be used by migration tool
    domain_parent_dir = domain_path.parent
    expected_out_path = (
        out_path
        if out_path is not None
        else (domain_parent_dir / migrate.DEFAULT_NEW_DOMAIN)
    )
    expected_backup_path = domain_parent_dir / migrate.ORIGINAL_DOMAIN
    if migrating_file_only:
        expected_backup_path = f"{expected_backup_path}{migrate.YML_SUFFIX}"
        expected_out_path = f"{expected_out_path}{migrate.YML_SUFFIX}"

    # create the folder if needed
    if not migrating_file_only and out_dir_exists:
        expected_out_path.mkdir(parents=True)

    # migrate!
    with pytest.raises(RasaException, match=error_msg_match):
        migrate.migrate_domain_format(domain_path, out_path)
    assert Path.exists(domain_path)
    assert all(Path.exists(file) for file in domain_files)
    assert not Path.exists(expected_backup_path)
    if not migrating_file_only:
        # if and only if the folder didn't exist before, it should not exist afterwards
        assert Path.exists(expected_out_path) == out_dir_exists

    # ... and to assert we really did remove something:
    expected_to_be_removed = [call(expected_backup_path)]
    if not out_dir_exists:  # only removed if it didn't exist
        expected_to_be_removed.append(call(expected_out_path))
    patching = [shutil, "rmtree"] if not migrating_file_only else [Path, "unlink"]
    with patch.object(*patching) as removal:
        with pytest.raises(RasaException, match=error_msg_match):
            migrate.migrate_domain_format(domain_path, out_path)
        assert removal.call_count == 1 + (not out_dir_exists)
        removal.assert_has_calls(expected_to_be_removed)
Exemple #10
0
def test_migrate_domain_raises_when_migrated_files_are_found(tmp_path: Path):
    domain_dir = tmp_path / "domain"
    domain_dir.mkdir()
    prepare_domain_path(
        domain_dir,
        f"""
        version: "{LATEST_TRAINING_DATA_FORMAT_VERSION}"
        intents: []
        """,
        "domain.yml",
    )

    with pytest.raises(
        RasaException, match="Some of the given files (.*) have already been migrated.*"
    ):
        migrate.migrate_domain_format(domain_dir, None)
Exemple #11
0
def test_migrate_domain_all_keys(tmp_path: Path, domain_out_file: Path):
    existing_domain_file = prepare_domain_path(
        tmp_path,
        """
        version: "2.0"
        intents:
        - greet
        entities:
        - city
        slots:
          city:
            type: text
            influence_conversation: false
        responses:
            utter_greet:
            - text: "Hi there!"
        actions:
        - action_check_time
        forms:
          booking_form:
            required_slots:
              city:
              - type: from_entity
                entity: city
        """,
        "domain.yml",
    )
    migrate.migrate_domain_format(existing_domain_file, domain_out_file)
    domain = Domain.from_path(domain_out_file)
    assert domain

    migrated_domain = rasa.shared.utils.io.read_yaml_file(domain_out_file)
    migrated_intents = migrated_domain.get("intents")
    assert "greet" in migrated_intents

    migrated_entities = migrated_domain.get("entities")
    assert "city" in migrated_entities

    migrated_responses = migrated_domain.get("responses")
    assert "utter_greet" in migrated_responses

    migrated_actions = migrated_domain.get("actions")
    assert "action_check_time" in migrated_actions

    migrated_training_data_version = migrated_domain.get("version")
    assert migrated_training_data_version == LATEST_TRAINING_DATA_FORMAT_VERSION
Exemple #12
0
def test_migrate_domain_raises_when_output_location_is_used(
        tmp_path: Path, migrate_file_only: bool, default_location: bool):
    domain_dir = tmp_path / "domain"
    domain_file_name = "domain.yml"
    domain_dir.mkdir()
    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        intents: []
        """,
        domain_file_name,
    )

    if not migrate_file_only:
        domain_path = domain_dir
        if default_location:
            out_path = None
            non_empty_existing_dir = tmp_path / migrate.DEFAULT_NEW_DOMAIN
        else:
            out_path = tmp_path / "my_custom_new_domain_name"
            non_empty_existing_dir = out_path
        non_empty_existing_dir.mkdir()
        # in contrast to the backup location, the output directory may exist
        # but must be empty
        with open(non_empty_existing_dir / "bla.txt", "w"):
            pass

    else:
        domain_path = domain_dir / domain_file_name
        if default_location:
            out_path = None
            existing_file = tmp_path / (migrate.DEFAULT_NEW_DOMAIN +
                                        migrate.YML_SUFFIX)
        else:
            out_path = tmp_path / "my_custom_file_name.yml"
            existing_file = out_path
        with open(existing_file, "w"):
            pass

    with pytest.raises(
            RasaException,
            match=
            "The domain could not be migrated to .* because .* already exists.*",
    ):
        migrate.migrate_domain_format(domain_path, out_path)
Exemple #13
0
def test_migrate_folder_only_migrates_domain_files(tmp_path: Path):
    domain_dir = tmp_path / "domain"
    domain_dir.mkdir()

    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        entities:
            - outdoor
        slots:
          outdoor_seating:
           type: bool
           influence_conversation: false
        """,
        "slots.yml",
    )

    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        forms:
          reservation_form:
            required_slots:
               outdoor_seating:
               - type: from_intent
                 value: true
                 intent: confirm
        """,
        "forms.yml",
    )

    prepare_domain_path(
        domain_dir,
        """
        not a domain file.
        """,
        "not-a-domain-file.yml",
    )

    out_dir = tmp_path / "out_dir"
    migrate.migrate_domain_format(domain_dir, out_dir)
    assert set(f.name for f in out_dir.iterdir()) == {"forms.yml", "slots.yml"}
Exemple #14
0
def test_migrate_domain_dir_with_out_path_None(tmp_path: Path):
    domain_dir = tmp_path / "domain"
    domain_dir.mkdir()

    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        entities:
            - outdoor
        slots:
          outdoor_seating:
           type: bool
           influence_conversation: false
        """,
        "slots.yml",
    )

    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        forms:
          reservation_form:
            required_slots:
               outdoor_seating:
               - type: from_intent
                 value: true
                 intent: confirm
        """,
        "forms.yml",
    )

    migrate.migrate_domain_format(domain_dir, None)

    domain_out = tmp_path / "new_domain"
    assert domain_out.exists()

    for file in domain_out.iterdir():
        assert file.name in ["slots.yml", "forms.yml"]

    domain = Domain.from_directory(str(domain_out))
    assert domain
Exemple #15
0
def test_migrate_domain_raises_for_missing_slots_and_forms(tmp_path: Path):
    domain_dir = tmp_path / "domain"
    domain_dir.mkdir()

    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        entities:
        - bla
        """,
        "domain.yml",
    )

    with pytest.raises(
        RasaException,
        match=f"The files you have provided in '{re.escape(str(domain_dir))}' "
        f"are missing slots or forms. "
        f"Please make sure to include these for a successful migration.",
    ):
        migrate.migrate_domain_format(domain_dir, None)
Exemple #16
0
def test_migrate_domain_with_multiple_files_with_duplicate_forms(
        tmp_path: Path):
    domain_dir = tmp_path / "domain"
    domain_dir.mkdir()

    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        forms:
          reservation_form:
            required_slots:
               outdoor_seating:
               - type: from_intent
                 value: true
                 intent: confirm
        """,
        "forms_one.yml",
    )

    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        forms:
          reservation_form:
            required_slots:
               cuisine:
               - type: from_entity
                 entity: cuisine
        """,
        "forms_two.yml",
    )

    with pytest.raises(
            RasaException,
            match="Domain files with multiple 'forms' sections were provided.",
    ):
        migrate.migrate_domain_format(domain_dir, None)
Exemple #17
0
def test_migrate_domain_multiple_files_with_duplicate_slots(tmp_path: Path):
    domain_dir = tmp_path / "domain"
    domain_dir.mkdir()

    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        entities:
            - outdoor
        slots:
          outdoor_seating:
           type: bool
           influence_conversation: false
        """,
        "slots_one.yml",
    )

    prepare_domain_path(
        domain_dir,
        """
        version: "2.0"
        entities:
            - outdoor
        slots:
          cuisine:
           type: text
           influence_conversation: false
        """,
        "slots_two.yml",
    )

    with pytest.raises(
        RasaException,
        match="Domain files with multiple 'slots' sections were provided.",
    ):
        migrate.migrate_domain_format(domain_dir, None)
Exemple #18
0
def test_migrate_domain_format_duplicated_slots_in_forms(
    tmp_path: Path, domain_out_file: Path
):
    existing_domain_file = prepare_domain_path(
        tmp_path,
        """
        version: "2.0"
        intents:
        - greet
        - affirm
        - inform
        entities:
        - city
        slots:
          name:
            type: text
            influence_conversation: false
          location:
             type: text
             influence_conversation: false
        forms:
           form_one:
               required_slots:
                 name:
                 - type: from_text
                   intent: inform
                 location:
                 - type: from_text
                   intent: greet
           form_two:
               required_slots:
                 name:
                 - type: from_text
                   intent: inform
                 - type: from_intent
                   intent: deny
                   value: demo
                 location:
                 - type: from_entity
                   entity: city
        """,
        "domain.yml",
    )
    migrate.migrate_domain_format(existing_domain_file, domain_out_file)

    domain = Domain.from_path(domain_out_file)
    assert domain

    migrated_domain = rasa.shared.utils.io.read_yaml_file(domain_out_file)
    migrated_slots = migrated_domain.get("slots")
    slot_with_duplicate_mappings = migrated_slots.get("name")
    assert slot_with_duplicate_mappings == {
        "type": "text",
        "influence_conversation": False,
        "mappings": [
            {
                "type": "from_text",
                "intent": "inform",
                "conditions": [
                    {"active_loop": "form_one", "requested_slot": "name"},
                    {"active_loop": "form_two", "requested_slot": "name"},
                ],
            },
            {
                "type": "from_intent",
                "intent": "deny",
                "value": "demo",
                "conditions": [{"active_loop": "form_two", "requested_slot": "name"}],
            },
        ],
    }
    slot_with_different_mapping_conditions = migrated_slots.get("location")
    assert slot_with_different_mapping_conditions == {
        "type": "text",
        "influence_conversation": False,
        "mappings": [
            {
                "type": "from_text",
                "intent": "greet",
                "conditions": [
                    {"active_loop": "form_one", "requested_slot": "location"}
                ],
            },
            {
                "type": "from_entity",
                "entity": "city",
                "conditions": [{"active_loop": "form_two"}],
            },
        ],
    }
Exemple #19
0
def test_migrate_domain_format_with_required_slots(
    tmp_path: Path, domain_out_file: Path
):
    existing_domain_file = prepare_domain_path(
        tmp_path,
        """
        version: "2.0"
        intents:
        - greet
        - affirm
        - inform
        entities:
        - city
        - name
        slots:
          location:
            type: text
            influence_conversation: false
          name:
            type: text
            influence_conversation: false
            auto_fill: false
          email:
            type: text
            influence_conversation: false
        forms:
           booking_form:
               ignored_intents:
               - greet
               required_slots:
                 location:
                 - type: from_entity
                   entity: city
                 email:
                 - type: from_text
                   intent: inform
                 name:
                 - type: from_entity
                   entity: surname
        """,
        "domain.yml",
    )

    migrate.migrate_domain_format(existing_domain_file, domain_out_file)

    domain = Domain.from_path(domain_out_file)
    assert domain

    old_domain_path = tmp_path / "original_domain.yml"
    assert old_domain_path

    migrated_domain = rasa.shared.utils.io.read_yaml_file(domain_out_file)

    migrated_training_data_version = migrated_domain.get("version")
    assert migrated_training_data_version == LATEST_TRAINING_DATA_FORMAT_VERSION

    migrated_slots = migrated_domain.get("slots")
    expected_slots = {
        "location": {
            "type": "text",
            "influence_conversation": False,
            "mappings": [
                {
                    "type": "from_entity",
                    "entity": "city",
                    "conditions": [{"active_loop": "booking_form"}],
                }
            ],
        },
        "name": {
            "type": "text",
            "influence_conversation": False,
            "mappings": [
                {
                    "type": "from_entity",
                    "entity": "surname",
                    "conditions": [{"active_loop": "booking_form"}],
                }
            ],
        },
        "email": {
            "type": "text",
            "influence_conversation": False,
            "mappings": [
                {
                    "type": "from_text",
                    "intent": "inform",
                    "conditions": [
                        {"active_loop": "booking_form", "requested_slot": "email"}
                    ],
                }
            ],
        },
    }
    assert migrated_slots == expected_slots

    migrated_forms = migrated_domain.get("forms")
    expected_forms = {
        "booking_form": {
            "ignored_intents": ["greet"],
            "required_slots": ["location", "email", "name"],
        }
    }
    assert migrated_forms == expected_forms