Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ def inline(
inline_separator=options.inline_separator or ", ",
inline_or=options.inline_or or " or ",
inline_or_more=options.inline_or_more or ", or ",
include_numbers=options.include_numbers or True,
include_numbers=(
options.include_numbers if options.include_numbers is not None else True
),
)

# Format list of choices
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@
# Licensed under the MIT License.

from typing import Dict
from recognizers_choice import recognize_boolean
from botbuilder.core.turn_context import TurnContext
from botbuilder.schema import ActivityTypes, Activity
from botbuilder.dialogs.choices import Choice, ChoiceFactoryOptions, ListStyle
from botbuilder.dialogs.choices import (
Choice,
ChoiceFactoryOptions,
ChoiceRecognizers,
ListStyle,
)
from .prompt import Prompt
from .prompt_options import PromptOptions
from .prompt_recognizer_result import PromptRecognizerResult
Expand Down Expand Up @@ -93,7 +99,7 @@ async def on_prompt(
if self.confirm_choices is not None
else (defaults[0], defaults[1])
)
choices = {confirms[0], confirms[1]}
choices = [confirms[0], confirms[1]]
if is_retry and options.retry_prompt is not None:
prompt = self.append_choices(
options.retry_prompt, channel_id, choices, self.style, choice_opts
Expand All @@ -110,7 +116,6 @@ async def on_recognize(
state: Dict[str, object],
options: PromptOptions,
) -> PromptRecognizerResult:
# pylint: disable=undefined-variable
if not turn_context:
raise TypeError("ConfirmPrompt.on_prompt(): turn_context cannot be None.")

Expand All @@ -119,13 +124,12 @@ async def on_recognize(
# Recognize utterance
message = turn_context.activity
culture = self.determine_culture(turn_context.activity)
# TODO: Port ChoiceRecognizer
results = ChoiceRecognizer.recognize_boolean(message.text, culture)
if results.Count > 0:
results = recognize_boolean(message.text, culture)
if results:
first = results[0]
if "value" in first.Resolution:
if "value" in first.resolution:
result.succeeded = True
result.value = str(first.Resolution["value"])
result.value = first.resolution["value"]
else:
# First check whether the prompt was sent to the user with numbers
# if it was we should recognize numbers
Expand All @@ -138,15 +142,14 @@ async def on_recognize(

# This logic reflects the fact that IncludeNumbers is nullable and True is the default set in
# Inline style
if opts.include_numbers.has_value or opts.include_numbers.value:
if opts.include_numbers is None or opts.include_numbers:
# The text may be a number in which case we will interpret that as a choice.
confirm_choices = (
self.confirm_choices
if self.confirm_choices is not None
else (defaults[0], defaults[1])
)
choices = {confirm_choices[0], confirm_choices[1]}
# TODO: Port ChoiceRecognizer
second_attempt_results = ChoiceRecognizers.recognize_choices(
message.text, choices
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ def default() -> Activity:
msg = switcher.get(int(style.value), default)()

# Update prompt with text, actions and attachments
if not prompt:
if prompt:
# clone the prompt the set in the options (note ActivityEx has Properties so this is the safest mechanism)
prompt = copy.copy(prompt)

Expand Down
11 changes: 7 additions & 4 deletions libraries/botbuilder-dialogs/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
from setuptools import setup

REQUIRES = [
"recognizers-date-time>=1.0.0a1",
"recognizers-number-with-unit>=1.0.0a1",
"recognizers-number>=1.0.0a2",
"recognizers-text>=1.0.0a1",
"recognizers-text-date-time>=1.0.1a0",
"recognizers-text-number-with-unit>=1.0.1a0",
"recognizers-text-number>=1.0.1a0",
"recognizers-text>=1.0.1a0",
"recognizers-text-choice>=1.0.1a0",
"grapheme>=0.5.0",
"emoji>=0.5.2",
"botbuilder-schema>=4.4.0b1",
"botframework-connector>=4.4.0b1",
"botbuilder-core>=4.4.0b1",
Expand Down
276 changes: 276 additions & 0 deletions libraries/botbuilder-dialogs/tests/test_confirm_prompt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import aiounittest
from botbuilder.core import (
ConversationState,
MemoryStorage,
TurnContext,
MessageFactory,
)
from botbuilder.core.adapters import TestAdapter
from botbuilder.dialogs import DialogSet, DialogTurnResult, DialogTurnStatus
from botbuilder.dialogs.choices import ChoiceFactoryOptions, ListStyle
from botbuilder.dialogs.prompts import ConfirmPrompt
from botbuilder.dialogs.prompts import PromptOptions
from botbuilder.schema import Activity, ActivityTypes


class ConfirmPromptTest(aiounittest.AsyncTestCase):
def test_confirm_prompt_with_empty_id_should_fail(self):
empty_id = ""

with self.assertRaises(TypeError):
ConfirmPrompt(empty_id)

def test_confirm_prompt_with_none_id_should_fail(self):
none_id = None

with self.assertRaises(TypeError):
ConfirmPrompt(none_id)

async def test_confirm_prompt(self):
async def exec_test(turn_context: TurnContext):
dialog_context = await dialogs.create_context(turn_context)

results: DialogTurnResult = await dialog_context.continue_dialog()

if results.status == DialogTurnStatus.Empty:
options = PromptOptions(
prompt=Activity(type=ActivityTypes.message, text="Please confirm.")
)
await dialog_context.prompt("ConfirmPrompt", options)
elif results.status == DialogTurnStatus.Complete:
message_text = "Confirmed" if results.result else "Not confirmed"
await turn_context.send_activity(MessageFactory.text(message_text))

await convo_state.save_changes(turn_context)

# Initialize TestAdapter.
adapter = TestAdapter(exec_test)

# Create new ConversationState with MemoryStorage and register the state as middleware.
convo_state = ConversationState(MemoryStorage())

# Create a DialogState property, DialogSet, and ChoicePrompt.
dialog_state = convo_state.create_property("dialogState")
dialogs = DialogSet(dialog_state)
confirm_prompt = ConfirmPrompt("ConfirmPrompt", default_locale="English")
dialogs.add(confirm_prompt)

step1 = await adapter.send("hello")
step2 = await step1.assert_reply("Please confirm. (1) Yes or (2) No")
step3 = await step2.send("yes")
await step3.assert_reply("Confirmed")

async def test_confirm_prompt_retry(self):
async def exec_test(turn_context: TurnContext):
dialog_context = await dialogs.create_context(turn_context)

results: DialogTurnResult = await dialog_context.continue_dialog()

if results.status == DialogTurnStatus.Empty:
options = PromptOptions(
prompt=Activity(type=ActivityTypes.message, text="Please confirm."),
retry_prompt=Activity(
type=ActivityTypes.message,
text="Please confirm, say 'yes' or 'no' or something like that.",
),
)
await dialog_context.prompt("ConfirmPrompt", options)
elif results.status == DialogTurnStatus.Complete:
message_text = "Confirmed" if results.result else "Not confirmed"
await turn_context.send_activity(MessageFactory.text(message_text))

await convo_state.save_changes(turn_context)

# Initialize TestAdapter.
adapter = TestAdapter(exec_test)

# Create new ConversationState with MemoryStorage and register the state as middleware.
convo_state = ConversationState(MemoryStorage())

# Create a DialogState property, DialogSet, and ChoicePrompt.
dialog_state = convo_state.create_property("dialogState")
dialogs = DialogSet(dialog_state)
confirm_prompt = ConfirmPrompt("ConfirmPrompt", default_locale="English")
dialogs.add(confirm_prompt)

step1 = await adapter.send("hello")
step2 = await step1.assert_reply("Please confirm. (1) Yes or (2) No")
step3 = await step2.send("lala")
step4 = await step3.assert_reply(
"Please confirm, say 'yes' or 'no' or something like that. (1) Yes or (2) No"
)
step5 = await step4.send("no")
await step5.assert_reply("Not confirmed")

async def test_confirm_prompt_no_options(self):
async def exec_test(turn_context: TurnContext):
dialog_context = await dialogs.create_context(turn_context)

results: DialogTurnResult = await dialog_context.continue_dialog()

if results.status == DialogTurnStatus.Empty:
await dialog_context.prompt("ConfirmPrompt", PromptOptions())
elif results.status == DialogTurnStatus.Complete:
message_text = "Confirmed" if results.result else "Not confirmed"
await turn_context.send_activity(MessageFactory.text(message_text))

await convo_state.save_changes(turn_context)

# Initialize TestAdapter.
adapter = TestAdapter(exec_test)

# Create new ConversationState with MemoryStorage and register the state as middleware.
convo_state = ConversationState(MemoryStorage())

# Create a DialogState property, DialogSet, and ChoicePrompt.
dialog_state = convo_state.create_property("dialogState")
dialogs = DialogSet(dialog_state)
confirm_prompt = ConfirmPrompt("ConfirmPrompt", default_locale="English")
dialogs.add(confirm_prompt)

step1 = await adapter.send("hello")
step2 = await step1.assert_reply(" (1) Yes or (2) No")
step3 = await step2.send("lala")
step4 = await step3.assert_reply(" (1) Yes or (2) No")
step5 = await step4.send("no")
await step5.assert_reply("Not confirmed")

async def test_confirm_prompt_choice_options_numbers(self):
async def exec_test(turn_context: TurnContext):
dialog_context = await dialogs.create_context(turn_context)

results: DialogTurnResult = await dialog_context.continue_dialog()

if results.status == DialogTurnStatus.Empty:
options = PromptOptions(
prompt=Activity(type=ActivityTypes.message, text="Please confirm."),
retry_prompt=Activity(
type=ActivityTypes.message,
text="Please confirm, say 'yes' or 'no' or something like that.",
),
)
await dialog_context.prompt("ConfirmPrompt", options)
elif results.status == DialogTurnStatus.Complete:
message_text = "Confirmed" if results.result else "Not confirmed"
await turn_context.send_activity(MessageFactory.text(message_text))

await convo_state.save_changes(turn_context)

# Initialize TestAdapter.
adapter = TestAdapter(exec_test)

# Create new ConversationState with MemoryStorage and register the state as middleware.
convo_state = ConversationState(MemoryStorage())

# Create a DialogState property, DialogSet, and ChoicePrompt.
dialog_state = convo_state.create_property("dialogState")
dialogs = DialogSet(dialog_state)
confirm_prompt = ConfirmPrompt("ConfirmPrompt", default_locale="English")
confirm_prompt.choice_options = ChoiceFactoryOptions(include_numbers=True)
confirm_prompt.style = ListStyle.in_line
dialogs.add(confirm_prompt)

step1 = await adapter.send("hello")
step2 = await step1.assert_reply("Please confirm. (1) Yes or (2) No")
step3 = await step2.send("lala")
step4 = await step3.assert_reply(
"Please confirm, say 'yes' or 'no' or something like that. (1) Yes or (2) No"
)
step5 = await step4.send("2")
await step5.assert_reply("Not confirmed")

async def test_confirm_prompt_choice_options_multiple_attempts(self):
async def exec_test(turn_context: TurnContext):
dialog_context = await dialogs.create_context(turn_context)

results: DialogTurnResult = await dialog_context.continue_dialog()

if results.status == DialogTurnStatus.Empty:
options = PromptOptions(
prompt=Activity(type=ActivityTypes.message, text="Please confirm."),
retry_prompt=Activity(
type=ActivityTypes.message,
text="Please confirm, say 'yes' or 'no' or something like that.",
),
)
await dialog_context.prompt("ConfirmPrompt", options)
elif results.status == DialogTurnStatus.Complete:
message_text = "Confirmed" if results.result else "Not confirmed"
await turn_context.send_activity(MessageFactory.text(message_text))

await convo_state.save_changes(turn_context)

# Initialize TestAdapter.
adapter = TestAdapter(exec_test)

# Create new ConversationState with MemoryStorage and register the state as middleware.
convo_state = ConversationState(MemoryStorage())

# Create a DialogState property, DialogSet, and ChoicePrompt.
dialog_state = convo_state.create_property("dialogState")
dialogs = DialogSet(dialog_state)
confirm_prompt = ConfirmPrompt("ConfirmPrompt", default_locale="English")
confirm_prompt.choice_options = ChoiceFactoryOptions(include_numbers=True)
confirm_prompt.style = ListStyle.in_line
dialogs.add(confirm_prompt)

step1 = await adapter.send("hello")
step2 = await step1.assert_reply("Please confirm. (1) Yes or (2) No")
step3 = await step2.send("lala")
step4 = await step3.assert_reply(
"Please confirm, say 'yes' or 'no' or something like that. (1) Yes or (2) No"
)
step5 = await step4.send("what")
step6 = await step5.assert_reply(
"Please confirm, say 'yes' or 'no' or something like that. (1) Yes or (2) No"
)
step7 = await step6.send("2")
await step7.assert_reply("Not confirmed")

async def test_confirm_prompt_options_no_numbers(self):
async def exec_test(turn_context: TurnContext):
dialog_context = await dialogs.create_context(turn_context)

results: DialogTurnResult = await dialog_context.continue_dialog()

if results.status == DialogTurnStatus.Empty:
options = PromptOptions(
prompt=Activity(type=ActivityTypes.message, text="Please confirm."),
retry_prompt=Activity(
type=ActivityTypes.message,
text="Please confirm, say 'yes' or 'no' or something like that.",
),
)
await dialog_context.prompt("ConfirmPrompt", options)
elif results.status == DialogTurnStatus.Complete:
message_text = "Confirmed" if results.result else "Not confirmed"
await turn_context.send_activity(MessageFactory.text(message_text))

await convo_state.save_changes(turn_context)

# Initialize TestAdapter.
adapter = TestAdapter(exec_test)

# Create new ConversationState with MemoryStorage and register the state as middleware.
convo_state = ConversationState(MemoryStorage())

# Create a DialogState property, DialogSet, and ChoicePrompt.
dialog_state = convo_state.create_property("dialogState")
dialogs = DialogSet(dialog_state)
confirm_prompt = ConfirmPrompt("ConfirmPrompt", default_locale="English")
confirm_prompt.choice_options = ChoiceFactoryOptions(
include_numbers=False, inline_separator="~"
)
dialogs.add(confirm_prompt)

step1 = await adapter.send("hello")
step2 = await step1.assert_reply("Please confirm. Yes or No")
step3 = await step2.send("2")
step4 = await step3.assert_reply(
"Please confirm, say 'yes' or 'no' or something like that. Yes or No"
)
step5 = await step4.send("no")
await step5.assert_reply("Not confirmed")