8000 Axsuarez/append choices fix (#324) · guidotorresmx/botbuilder-python@290af73 · GitHub
[go: up one dir, main page]

Skip to content

Commit 290af73

Browse files
authored
Axsuarez/append choices fix (microsoft#324)
* Concat Attachments if exist in Prompt
1 parent bb0b7ef commit 290af73

File tree

4 files changed

+127
-18
lines changed

4 files changed

+127
-18
lines changed

libraries/botbuilder-core/botbuilder/core/adapters/test_adapter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ async def assert_reply(
352352
:param timeout:
353353
:return:
354354
"""
355-
355+
# TODO: refactor method so expected can take a Callable[[Activity], None]
356356
def default_inspector(reply, description=None):
357357
if isinstance(expected, Activity):
358358
validate_activity(reply, expected)

libraries/botbuilder-dialogs/botbuilder/dialogs/choices/choice_factory.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Copyright (c) Microsoft Corporation. All rights reserved.
22
# Licensed under the MIT License.
33

4-
from typing import List
4+
from typing import List, Union
55

66
from botbuilder.core import CardFactory, MessageFactory
77
from botbuilder.schema import ActionTypes, Activity, CardAction, HeroCard, InputHints
@@ -17,7 +17,7 @@ class ChoiceFactory:
1717
@staticmethod
1818
def for_channel(
1919
channel_id: str,
20-
choices: List[Choice],
20+
choices: List[Union[str, Choice]],
2121
text: str = None,
2222
speak: str = None,
2323
options: ChoiceFactoryOptions = None,
@@ -36,8 +36,7 @@ def for_channel(
3636
if channel_id is None:
3737
channel_id = ""
3838

39-
if choices is None:
40-
choices = []
39+
choices = ChoiceFactory._to_choices(choices)
4140

4241
# Find maximum title length
4342
max_title_length = 0
@@ -74,7 +73,7 @@ def for_channel(
7473

7574
@staticmethod
7675
def inline(
77-
choices: List[Choice],
76+
choices: List[Union[str, Choice]],
7877
text: str = None,
7978
speak: str = None,
8079
options: ChoiceFactoryOptions = None,
@@ -89,8 +88,7 @@ def inline(
8988
speak: (Optional) SSML. Text to be spoken by your bot on a speech-enabled channel.
9089
options: (Optional) The formatting options to use to tweak rendering of list.
9190
"""
92-
if choices is None:
93-
choices = []
91+
choices = ChoiceFactory._to_choices(choices)
9492

9593
if options is None:
9694
options = ChoiceFactoryOptions()
@@ -134,7 +132,7 @@ def inline(
134132

135133
@staticmethod
136134
def list_style(
137-
choices: List[Choice],
135+
choices: List[Union[str, Choice]],
138136
text: str = None,
139137
speak: str = None,
140138
options: ChoiceFactoryOptions = None,
@@ -153,8 +151,7 @@ def list_style(
153151
154152
options: (Optional) The formatting options to use to tweak rendering of list.
155153
"""
156-
if choices is None:
157-
choices = []
154+
choices = ChoiceFactory._to_choices(choices)
158155
if options is None:
159156
options = ChoiceFactoryOptions()
160157

@@ -206,7 +203,7 @@ def suggested_action(
206203

207204
@staticmethod
208205
def hero_card(
209-
choices: List[Choice], text: str = None, speak: str = None
206+
choices: List[Union[Choice, str]], text: str = None, speak: str = None
210207
) -> Activity:
211208
"""
212209
Creates a message activity that includes a lsit of coices that have been added as `HeroCard`'s
@@ -221,18 +218,22 @@ def hero_card(
221218
)
222219

223220
@staticmethod
224-
def _to_choices(choices: List[str]) -> List[Choice]:
221+
def _to_choices(choices: List[Union[str, Choice]]) -> List[Choice]:
225222
"""
226223
Takes a list of strings and returns them as [`Choice`].
227224
"""
228225
if choices is None:
229226
return []
230-
return [Choice(value=choice.value) for choice in choices]
227+
return [
228+
Choice(value=choice) if isinstance(choice, str) else choice
229+
for choice in choices
230+
]
231231

232232
@staticmethod
233-
def _extract_actions(choices: List[Choice]) -> List[CardAction]:
233+
def _extract_actions(choices: List[Union[str, Choice]]) -> List[CardAction]:
234234
if choices is None:
235235
choices = []
236+
choices = ChoiceFactory._to_choices(choices)
236237
card_actions: List[CardAction] = []
237238
for choice in choices:
238239
if choice.action is not None:

libraries/botbuilder-dialogs/botbuilder/dialogs/prompts/prompt.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,11 @@ def default() -> Activity:
217217
):
218218
prompt.suggested_actions = msg.suggested_actions
219219

220-
if msg.attachments is not None and msg.attachments:
221-
prompt.attachments = msg.attachments
220+
if msg.attachments:
221+
if prompt.attachments:
222+
prompt.attachments.extend(msg.attachments)
223+
else:
224+
prompt.attachments = msg.attachments
222225

223226
return prompt
224227

libraries/botbuilder-dialogs/tests/test_choice_prompt.py

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import aiounittest
77
from recognizers_text import Culture
88

9-
from botbuilder.core import ConversationState, MemoryStorage, TurnContext
9+
from botbuilder.core import CardFactory, ConversationState, MemoryStorage, TurnContext
1010
from botbuilder.core.adapters import TestAdapter
1111
from botbuilder.dialogs import DialogSet, DialogTurnResult, DialogTurnStatus
1212
from botbuilder.dialogs.choices import Choice, ListStyle
@@ -588,3 +588,108 @@ async def exec_test(turn_context: TurnContext):
588588
)
589589
step3 = await step2.send("1")
590590
await step3.assert_reply("red")
591+
592+
async def test_should_display_choices_on_hero_card(self):
593+
size_choices = ["large", "medium", "small"]
594+
595+
async def exec_test(turn_context: TurnContext):
596+
dialog_context = await dialogs.create_context(turn_context)
597+
598+
results: DialogTurnResult = await dialog_context.continue_dialog()
599+
600+
if results.status == DialogTurnStatus.Empty:
601+
options = PromptOptions(
602+
prompt=Activity(
603+
type=ActivityTypes.message, text="Please choose a size."
604+
),
605+
choices=size_choices,
606+
)
607+
await dialog_context.prompt("prompt", options)
608+
elif results.status == DialogTurnStatus.Complete:
609+
selected_choice = results.result
610+
await turn_context.send_activity(selected_choice.value)
611+
612+
await convo_state.save_changes(turn_context)
613+
614+
def assert_expected_activity(
615+
activity: Activity, description
616+
): # pylint: disable=unused-argument
617+
assert len(activity.attachments) == 1
618+
assert (
619+
activity.attachments[0].content_type
620+
== CardFactory.content_types.hero_card
621+
)
622+
assert activity.attachments[0].content.text == "Please choose a size."
623+
624+
adapter = TestAdapter(exec_test)
625+
626+
convo_state = ConversationState(MemoryStorage())
627+
dialog_state = convo_state.create_property("dialogState")
628+
dialogs = DialogSet(dialog_state)
629+
630+
choice_prompt = ChoicePrompt("prompt")
631+
632+
# Change the ListStyle of the prompt to ListStyle.none.
633+
choice_prompt.style = ListStyle.hero_card
634+
635+
dialogs.add(choice_prompt)
636+
637+
step1 = await adapter.send("Hello")
638+
step2 = await step1.assert_reply(assert_expected_activity)
639+
step3 = await step2.send("1")
640+
await step3.assert_reply(size_choices[0])
641+
642+
async def test_should_display_choices_on_hero_card_with_additional_attachment(self):
643+
size_choices = ["large", "medium", "small"]
644+
card = CardFactory.adaptive_card(
645+
{
646+
"type": "AdaptiveCard",
647+
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
648+
"version": "1.2",
649+
"body": [],
650+
}
651+
)
652+
card_activity = Activity(attachments=[card])
653+
654+
async def exec_test(turn_context: TurnContext):
655+
dialog_context = await dialogs.create_context(turn_context)
656+
657+
results: DialogTurnResult = await dialog_context.continue_dialog()
658+
659+
if results.status == DialogTurnStatus.Empty:
660+
options< FFD3 /span> = PromptOptions(prompt=card_activity, choices=size_choices)
661+
await dialog_context.prompt("prompt", options)
662+
elif results.status == DialogTurnStatus.Complete:
663+
selected_choice = results.result
664+
await turn_context.send_activity(selected_choice.value)
665+
666+
await convo_state.save_changes(turn_context)
667+
668+
def assert_expected_activity(
669+
activity: Activity, description
670+
): # pylint: disable=unused-argument
671+
assert len(activity.attachments) == 2
672+
assert (
673+
activity.attachments[0].content_type
674+
== CardFactory.content_types.adaptive_card
675+
)
676+
assert (
677+
activity.attachments[1].content_type
678+
== CardFactory.content_types.hero_card
679+
)
680+
681+
adapter = TestAdapter(exec_test)
682+
683+
convo_state = ConversationState(MemoryStorage())
684+
dialog_state = convo_state.create_property("dialogState")
685+
dialogs = DialogSet(dialog_state)
686+
687+
choice_prompt = ChoicePrompt("prompt")
688+
689+
# Change the ListStyle of the prompt to ListStyle.none.
690+
choice_prompt.style = ListStyle.hero_card
691+
692+
dialogs.add(choice_prompt)
693+
694+
step1 = await adapter.send("Hello")
695+
await step1.assert_reply(assert_expected_activity)

0 commit comments

Comments
 (0)
0