From 4a77258aaea75d9395bb11edb3839867fa593e88 Mon Sep 17 00:00:00 2001 From: Tracy Boehrer Date: Tue, 12 Nov 2019 10:54:07 -0600 Subject: [PATCH] pylint and black changes. No logic changes. --- .../adapter/console_adapter.py | 25 +++-- samples/01.console-echo/main.py | 14 +-- samples/02.echo-bot/app.py | 5 +- samples/03.welcome-user/app.py | 14 ++- .../03.welcome-user/bots/welcome_user_bot.py | 104 ++++++++++-------- samples/05.multi-turn-prompt/app.py | 9 +- .../05.multi-turn-prompt/bots/dialog_bot.py | 22 ++-- .../dialogs/user_profile_dialog.py | 99 +++++++++-------- samples/06.using-cards/app.py | 9 +- samples/06.using-cards/bots/dialog_bot.py | 2 - samples/06.using-cards/bots/rich_cards_bot.py | 10 +- samples/06.using-cards/dialogs/main_dialog.py | 31 +++--- .../06.using-cards/helpers/activity_helper.py | 7 +- samples/08.suggested-actions/app.py | 20 ++-- .../bots/suggested_actions_bot.py | 45 ++++---- .../13.core-bot/adapter_with_error_handler.py | 10 +- samples/13.core-bot/booking_details.py | 6 +- .../bots/dialog_and_welcome_bot.py | 8 +- samples/13.core-bot/bots/dialog_bot.py | 2 - samples/13.core-bot/dialogs/booking_dialog.py | 62 +++++------ .../dialogs/cancel_and_help_dialog.py | 4 +- .../dialogs/date_resolver_dialog.py | 7 +- samples/13.core-bot/dialogs/main_dialog.py | 4 +- samples/13.core-bot/helpers/luis_helper.py | 9 +- samples/15.handling-attachments/app.py | 16 ++- .../bots/attachments_bot.py | 93 ++++++++-------- samples/16.proactive-messages/app.py | 26 +++-- .../bots/proactive_bot.py | 20 ++-- samples/17.multilingual-bot/app.py | 14 ++- .../bots/multilingual_bot.py | 57 ++++++---- .../translation/microsoft_translator.py | 20 ++-- .../translation/translation_middleware.py | 54 +++++---- samples/18.bot-authentication/app.py | 14 ++- .../18.bot-authentication/bots/auth_bot.py | 14 +-- .../18.bot-authentication/bots/dialog_bot.py | 2 - .../dialogs/logout_dialog.py | 4 +- .../dialogs/main_dialog.py | 45 +++++--- samples/19.custom-dialogs/app.py | 14 ++- samples/19.custom-dialogs/bots/dialog_bot.py | 7 +- .../19.custom-dialogs/dialogs/root_dialog.py | 88 +++++++-------- .../19.custom-dialogs/dialogs/slot_details.py | 27 +++-- .../dialogs/slot_filling_dialog.py | 45 +++++--- samples/21.corebot-app-insights/app.py | 9 +- .../bots/dialog_bot.py | 4 - samples/21.corebot-app-insights/config.py | 4 +- .../dialogs/booking_dialog.py | 19 ++-- .../dialogs/cancel_and_help_dialog.py | 4 +- .../dialogs/date_resolver_dialog.py | 22 ++-- .../dialogs/main_dialog.py | 14 +-- .../helpers/luis_helper.py | 4 +- samples/43.complex-dialog/app.py | 11 +- .../bots/dialog_and_welcome_bot.py | 8 +- .../data_models/user_profile.py | 4 +- .../43.complex-dialog/dialogs/main_dialog.py | 22 ++-- .../dialogs/review_selection_dialog.py | 54 +++++---- .../dialogs/top_level_dialog.py | 37 +++---- samples/44.prompt-users-for-input/app.py | 11 +- .../bots/custom_prompt_bot.py | 101 ++++++++++++----- .../data_models/conversation_flow.py | 3 +- samples/47.inspection/app.py | 24 ++-- samples/47.inspection/bots/echo_bot.py | 32 ++++-- 61 files changed, 829 insertions(+), 646 deletions(-) diff --git a/samples/01.console-echo/adapter/console_adapter.py b/samples/01.console-echo/adapter/console_adapter.py index 9ee38f065..28f4b4f8e 100644 --- a/samples/01.console-echo/adapter/console_adapter.py +++ b/samples/01.console-echo/adapter/console_adapter.py @@ -116,7 +116,7 @@ async def send_activities(self, context: TurnContext, activities: List[Activity] raise TypeError( "ConsoleAdapter.send_activities(): `context` argument cannot be None." ) - if type(activities) != list: + if not isinstance(activities, list): raise TypeError( "ConsoleAdapter.send_activities(): `activities` argument must be a list." ) @@ -130,24 +130,27 @@ async def next_activity(i: int): if i < len(activities): responses.append(ResourceResponse()) - a = activities[i] + activity = activities[i] - if a.type == "delay": - await asyncio.sleep(a.delay) + if activity.type == "delay": + await asyncio.sleep(activity.delay) await next_activity(i + 1) - elif a.type == ActivityTypes.message: - if a.attachments is not None and len(a.attachments) > 0: + elif activity.type == ActivityTypes.message: + if ( + activity.attachments is not None + and len(activity.attachments) > 0 + ): append = ( "(1 attachment)" - if len(a.attachments) == 1 - else f"({len(a.attachments)} attachments)" + if len(activity.attachments) == 1 + else f"({len(activity.attachments)} attachments)" ) - print(f"{a.text} {append}") + print(f"{activity.text} {append}") else: - print(a.text) + print(activity.text) await next_activity(i + 1) else: - print(f"[{a.type}]") + print(f"[{activity.type}]") await next_activity(i + 1) else: return responses diff --git a/samples/01.console-echo/main.py b/samples/01.console-echo/main.py index 351ff1879..73801d1b8 100644 --- a/samples/01.console-echo/main.py +++ b/samples/01.console-echo/main.py @@ -2,26 +2,24 @@ # Licensed under the MIT License. import asyncio -from botbuilder.core import TurnContext, ConversationState, UserState, MemoryStorage -from botbuilder.schema import ActivityTypes from adapter import ConsoleAdapter from bot import EchoBot # Create adapter -adapter = ConsoleAdapter() -bot = EchoBot() +ADAPTER = ConsoleAdapter() +BOT = EchoBot() -loop = asyncio.get_event_loop() +LOOP = asyncio.get_event_loop() if __name__ == "__main__": try: # Greet user print("Hi... I'm an echobot. Whatever you say I'll echo back.") - loop.run_until_complete(adapter.process_activity(bot.on_turn)) + LOOP.run_until_complete(ADAPTER.process_activity(BOT.on_turn)) except KeyboardInterrupt: pass finally: - loop.stop() - loop.close() + LOOP.stop() + LOOP.close() diff --git a/samples/02.echo-bot/app.py b/samples/02.echo-bot/app.py index e1de9d56a..5cc960eb8 100644 --- a/samples/02.echo-bot/app.py +++ b/samples/02.echo-bot/app.py @@ -4,7 +4,6 @@ import asyncio import sys from datetime import datetime -from types import MethodType from flask import Flask, request, Response from botbuilder.core import BotFrameworkAdapterSettings, TurnContext, BotFrameworkAdapter @@ -24,7 +23,7 @@ # Catch-all for errors. -async def on_error(self, context: TurnContext, error: Exception): +async def on_error(context: TurnContext, error: Exception): # This check writes out errors to console log .vs. app insights. # NOTE: In production environment, you should consider logging this to Azure # application insights. @@ -47,7 +46,7 @@ async def on_error(self, context: TurnContext, error: Exception): # Send a trace activity, which will be displayed in Bot Framework Emulator await context.send_activity(trace_activity) -ADAPTER.on_turn_error = MethodType(on_error, ADAPTER) +ADAPTER.on_turn_error = on_error # Create the Bot BOT = EchoBot() diff --git a/samples/03.welcome-user/app.py b/samples/03.welcome-user/app.py index 7a771763d..7941afeb1 100644 --- a/samples/03.welcome-user/app.py +++ b/samples/03.welcome-user/app.py @@ -4,7 +4,6 @@ import asyncio import sys from datetime import datetime -from types import MethodType from flask import Flask, request, Response from botbuilder.core import ( @@ -30,7 +29,7 @@ # Catch-all for errors. -async def on_error(self, context: TurnContext, error: Exception): +async def on_error(context: TurnContext, error: Exception): # This check writes out errors to console log .vs. app insights. # NOTE: In production environment, you should consider logging this to Azure # application insights. @@ -38,9 +37,11 @@ async def on_error(self, context: TurnContext, error: Exception): # Send a message to the user await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") + await context.send_activity( + "To continue to run this bot, please fix the bot source code." + ) # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': + if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", @@ -48,12 +49,13 @@ async def on_error(self, context: TurnContext, error: Exception): timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", - value_type="https://www.botframework.com/schemas/error" + value_type="https://www.botframework.com/schemas/error", ) # Send a trace activity, which will be displayed in Bot Framework Emulator await context.send_activity(trace_activity) -ADAPTER.on_turn_error = MethodType(on_error, ADAPTER) + +ADAPTER.on_turn_error = on_error # Create MemoryStorage, UserState MEMORY = MemoryStorage() diff --git a/samples/03.welcome-user/bots/welcome_user_bot.py b/samples/03.welcome-user/bots/welcome_user_bot.py index 8fca0919f..9aa584732 100644 --- a/samples/03.welcome-user/bots/welcome_user_bot.py +++ b/samples/03.welcome-user/bots/welcome_user_bot.py @@ -1,8 +1,20 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -from botbuilder.core import ActivityHandler, TurnContext, UserState, CardFactory, MessageFactory -from botbuilder.schema import ChannelAccount, HeroCard, CardImage, CardAction, ActionTypes +from botbuilder.core import ( + ActivityHandler, + TurnContext, + UserState, + CardFactory, + MessageFactory, +) +from botbuilder.schema import ( + ChannelAccount, + HeroCard, + CardImage, + CardAction, + ActionTypes, +) from data_models import WelcomeUserState @@ -18,76 +30,76 @@ def __init__(self, user_state: UserState): self.user_state_accessor = self.user_state.create_property("WelcomeUserState") - self.WELCOME_MESSAGE = """This is a simple Welcome Bot sample. This bot will introduce you - to welcoming and greeting users. You can say 'intro' to see the - introduction card. If you are running this bot in the Bot Framework - Emulator, press the 'Restart Conversation' button to simulate user joining + self.WELCOME_MESSAGE = """This is a simple Welcome Bot sample. This bot will introduce you + to welcoming and greeting users. You can say 'intro' to see the + introduction card. If you are running this bot in the Bot Framework + Emulator, press the 'Restart Conversation' button to simulate user joining a bot or a channel""" - + async def on_turn(self, turn_context: TurnContext): await super().on_turn(turn_context) # save changes to WelcomeUserState after each turn await self.user_state.save_changes(turn_context) - """ - Greet when users are added to the conversation. - Note that all channels do not send the conversation update activity. - If you find that this bot works in the emulator, but does not in - another channel the reason is most likely that the channel does not - send this activity. - """ - async def on_members_added_activity( self, members_added: [ChannelAccount], turn_context: TurnContext ): + """ + Greet when users are added to the conversation. + Note that all channels do not send the conversation update activity. + If you find that this bot works in the emulator, but does not in + another channel the reason is most likely that the channel does not + send this activity. + """ for member in members_added: if member.id != turn_context.activity.recipient.id: await turn_context.send_activity( f"Hi there { member.name }. " + self.WELCOME_MESSAGE ) - await turn_context.send_activity("""You are seeing this message because the bot received at least one - 'ConversationUpdate' event, indicating you (and possibly others) - joined the conversation. If you are using the emulator, pressing - the 'Start Over' button to trigger this event again. The specifics - of the 'ConversationUpdate' event depends on the channel. You can + await turn_context.send_activity( + """You are seeing this message because the bot received at least one + 'ConversationUpdate' event, indicating you (and possibly others) + joined the conversation. If you are using the emulator, pressing + the 'Start Over' button to trigger this event again. The specifics + of the 'ConversationUpdate' event depends on the channel. You can read more information at: https://aka.ms/about-botframework-welcome-user""" ) - await turn_context.send_activity("""It is a good pattern to use this event to send general greeting - to user, explaining what your bot can do. In this example, the bot + await turn_context.send_activity( + """It is a good pattern to use this event to send general greeting + to user, explaining what your bot can do. In this example, the bot handles 'hello', 'hi', 'help' and 'intro'. Try it now, type 'hi'""" ) - """ - Respond to messages sent from the user. - """ - async def on_message_activity(self, turn_context: TurnContext): + """ + Respond to messages sent from the user. + """ # Get the state properties from the turn context. - welcome_user_state = await self.user_state_accessor.get(turn_context, WelcomeUserState) + welcome_user_state = await self.user_state_accessor.get( + turn_context, WelcomeUserState + ) if not welcome_user_state.did_welcome_user: welcome_user_state.did_welcome_user = True await turn_context.send_activity( "You are seeing this message because this was your first message ever to this bot." - ) + ) name = turn_context.activity.from_property.name await turn_context.send_activity( - f"It is a good practice to welcome the user and provide personal greeting. For example: Welcome { name }" + f"It is a good practice to welcome the user and provide personal greeting. For example: Welcome {name}" ) - + else: # This example hardcodes specific utterances. You should use LUIS or QnA for more advance language # understanding. text = turn_context.activity.text.lower() if text in ("hello", "hi"): - await turn_context.send_activity( - f"You said { text }" - ) + await turn_context.send_activity(f"You said { text }") elif text in ("intro", "help"): await self.__send_intro_card(turn_context) else: @@ -97,37 +109,35 @@ async def __send_intro_card(self, turn_context: TurnContext): card = HeroCard( title="Welcome to Bot Framework!", text="Welcome to Welcome Users bot sample! This Introduction card " - "is a great way to introduce your Bot to the user and suggest " - "some things to get them started. We use this opportunity to " - "recommend a few next steps for learning more creating and deploying bots.", - images=[ - CardImage( - url="https://aka.ms/bf-welcome-card-image" - ) - ], + "is a great way to introduce your Bot to the user and suggest " + "some things to get them started. We use this opportunity to " + "recommend a few next steps for learning more creating and deploying bots.", + images=[CardImage(url="https://aka.ms/bf-welcome-card-image")], buttons=[ CardAction( type=ActionTypes.open_url, title="Get an overview", text="Get an overview", display_text="Get an overview", - value="https://docs.microsoft.com/en-us/azure/bot-service/?view=azure-bot-service-4.0" + value="https://docs.microsoft.com/en-us/azure/bot-service/?view=azure-bot-service-4.0", ), CardAction( type=ActionTypes.open_url, title="Ask a question", text="Ask a question", display_text="Ask a question", - value="https://stackoverflow.com/questions/tagged/botframework" + value="https://stackoverflow.com/questions/tagged/botframework", ), CardAction( type=ActionTypes.open_url, title="Learn how to deploy", text="Learn how to deploy", display_text="Learn how to deploy", - value="https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-deploy-azure?view=azure-bot-service-4.0" - ) - ] + value="https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-deploy-azure?view=azure-bot-service-4.0", + ), + ], ) - return await turn_context.send_activity(MessageFactory.attachment(CardFactory.hero_card(card))) + return await turn_context.send_activity( + MessageFactory.attachment(CardFactory.hero_card(card)) + ) diff --git a/samples/05.multi-turn-prompt/app.py b/samples/05.multi-turn-prompt/app.py index 790c2019c..fd68f6667 100644 --- a/samples/05.multi-turn-prompt/app.py +++ b/samples/05.multi-turn-prompt/app.py @@ -39,9 +39,11 @@ async def on_error(context: TurnContext, error: Exception): # Send a message to the user await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") + await context.send_activity( + "To continue to run this bot, please fix the bot source code." + ) # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': + if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", @@ -49,7 +51,7 @@ async def on_error(context: TurnContext, error: Exception): timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", - value_type="https://www.botframework.com/schemas/error" + value_type="https://www.botframework.com/schemas/error", ) # Send a trace activity, which will be displayed in Bot Framework Emulator @@ -58,6 +60,7 @@ async def on_error(context: TurnContext, error: Exception): # Clear out state await CONVERSATION_STATE.delete(context) + # Set the error handler on the Adapter. # In this case, we want an unbound method, so MethodType is not needed. ADAPTER.on_turn_error = on_error diff --git a/samples/05.multi-turn-prompt/bots/dialog_bot.py b/samples/05.multi-turn-prompt/bots/dialog_bot.py index 37a140966..c66d73755 100644 --- a/samples/05.multi-turn-prompt/bots/dialog_bot.py +++ b/samples/05.multi-turn-prompt/bots/dialog_bot.py @@ -5,21 +5,21 @@ from botbuilder.dialogs import Dialog from helpers.dialog_helper import DialogHelper -""" -This Bot implementation can run any type of Dialog. The use of type parameterization is to allows multiple -different bots to be run at different endpoints within the same project. This can be achieved by defining distinct -Controller types each with dependency on distinct Bot types. The ConversationState is used by the Dialog system. The -UserState isn't, however, it might have been used in a Dialog implementation, and the requirement is that all -BotState objects are saved at the end of a turn. -""" - class DialogBot(ActivityHandler): + """ + This Bot implementation can run any type of Dialog. The use of type parameterization is to allows multiple + different bots to be run at different endpoints within the same project. This can be achieved by defining distinct + Controller types each with dependency on distinct Bot types. The ConversationState is used by the Dialog system. The + UserState isn't, however, it might have been used in a Dialog implementation, and the requirement is that all + BotState objects are saved at the end of a turn. + """ + def __init__( - self, - conversation_state: ConversationState, + self, + conversation_state: ConversationState, user_state: UserState, - dialog: Dialog + dialog: Dialog, ): if conversation_state is None: raise TypeError( diff --git a/samples/05.multi-turn-prompt/dialogs/user_profile_dialog.py b/samples/05.multi-turn-prompt/dialogs/user_profile_dialog.py index 86eea641b..dad1f6d18 100644 --- a/samples/05.multi-turn-prompt/dialogs/user_profile_dialog.py +++ b/samples/05.multi-turn-prompt/dialogs/user_profile_dialog.py @@ -5,15 +5,15 @@ ComponentDialog, WaterfallDialog, WaterfallStepContext, - DialogTurnResult + DialogTurnResult, ) from botbuilder.dialogs.prompts import ( - TextPrompt, - NumberPrompt, - ChoicePrompt, - ConfirmPrompt, + TextPrompt, + NumberPrompt, + ChoicePrompt, + ConfirmPrompt, PromptOptions, - PromptValidatorContext + PromptValidatorContext, ) from botbuilder.dialogs.choices import Choice from botbuilder.core import MessageFactory, UserState @@ -22,47 +22,45 @@ class UserProfileDialog(ComponentDialog): - def __init__( - self, user_state: UserState - ): + def __init__(self, user_state: UserState): super(UserProfileDialog, self).__init__(UserProfileDialog.__name__) self.user_profile_accessor = user_state.create_property("UserProfile") self.add_dialog( WaterfallDialog( - WaterfallDialog.__name__, [ - self.transport_step, + WaterfallDialog.__name__, + [ + self.transport_step, self.name_step, self.name_confirm_step, self.age_step, self.confirm_step, - self.summary_step - ] + self.summary_step, + ], ) ) self.add_dialog(TextPrompt(TextPrompt.__name__)) self.add_dialog( - NumberPrompt( - NumberPrompt.__name__, - UserProfileDialog.age_prompt_validator - ) + NumberPrompt(NumberPrompt.__name__, UserProfileDialog.age_prompt_validator) ) self.add_dialog(ChoicePrompt(ChoicePrompt.__name__)) self.add_dialog(ConfirmPrompt(ConfirmPrompt.__name__)) self.initial_dialog_id = WaterfallDialog.__name__ - async def transport_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: - # WaterfallStep always finishes with the end of the Waterfall or with another dialog; - # here it is a Prompt Dialog. Running a prompt here means the next WaterfallStep will + async def transport_step( + self, step_context: WaterfallStepContext + ) -> DialogTurnResult: + # WaterfallStep always finishes with the end of the Waterfall or with another dialog; + # here it is a Prompt Dialog. Running a prompt here means the next WaterfallStep will # be run when the users response is received. return await step_context.prompt( - ChoicePrompt.__name__, + ChoicePrompt.__name__, PromptOptions( prompt=MessageFactory.text("Please enter your mode of transport."), - choices=[Choice("Car"), Choice("Bus"), Choice("Bicycle")] - ) + choices=[Choice("Car"), Choice("Bus"), Choice("Bicycle")], + ), ) async def name_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: @@ -70,12 +68,12 @@ async def name_step(self, step_context: WaterfallStepContext) -> DialogTurnResul return await step_context.prompt( TextPrompt.__name__, - PromptOptions( - prompt=MessageFactory.text("Please enter your name.") - ) + PromptOptions(prompt=MessageFactory.text("Please enter your name.")), ) - async def name_confirm_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: + async def name_confirm_step( + self, step_context: WaterfallStepContext + ) -> DialogTurnResult: step_context.values["name"] = step_context.result # We can send messages to the user at any point in the WaterfallStep. @@ -83,19 +81,19 @@ async def name_confirm_step(self, step_context: WaterfallStepContext) -> DialogT MessageFactory.text(f"Thanks {step_context.result}") ) - # WaterfallStep always finishes with the end of the Waterfall or + # WaterfallStep always finishes with the end of the Waterfall or # with another dialog; here it is a Prompt Dialog. return await step_context.prompt( ConfirmPrompt.__name__, PromptOptions( prompt=MessageFactory.text("Would you like to give your age?") - ) + ), ) async def age_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: if step_context.result: # User said "yes" so we will be prompting for the age. - # WaterfallStep always finishes with the end of the Waterfall or with another dialog, + # WaterfallStep always finishes with the end of the Waterfall or with another dialog, # here it is a Prompt Dialog. return await step_context.prompt( NumberPrompt.__name__, @@ -103,36 +101,44 @@ async def age_step(self, step_context: WaterfallStepContext) -> DialogTurnResult prompt=MessageFactory.text("Please enter your age."), retry_prompt=MessageFactory.text( "The value entered must be greater than 0 and less than 150." - ) - ) + ), + ), ) - else: - # User said "no" so we will skip the next step. Give -1 as the age. - return await step_context.next(-1) - async def confirm_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: + # User said "no" so we will skip the next step. Give -1 as the age. + return await step_context.next(-1) + + async def confirm_step( + self, step_context: WaterfallStepContext + ) -> DialogTurnResult: age = step_context.result step_context.values["age"] = step_context.result - msg = "No age given." if step_context.result == -1 else f"I have your age as {age}." + msg = ( + "No age given." + if step_context.result == -1 + else f"I have your age as {age}." + ) # We can send messages to the user at any point in the WaterfallStep. await step_context.context.send_activity(MessageFactory.text(msg)) - # WaterfallStep always finishes with the end of the Waterfall or + # WaterfallStep always finishes with the end of the Waterfall or # with another dialog; here it is a Prompt Dialog. return await step_context.prompt( ConfirmPrompt.__name__, - PromptOptions( - prompt=MessageFactory.text("Is this ok?") - ) + PromptOptions(prompt=MessageFactory.text("Is this ok?")), ) - async def summary_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: + async def summary_step( + self, step_context: WaterfallStepContext + ) -> DialogTurnResult: if step_context.result: # Get the current profile object from user state. Changes to it # will saved during Bot.on_turn. - user_profile = await self.user_profile_accessor.get(step_context.context, UserProfile) + user_profile = await self.user_profile_accessor.get( + step_context.context, UserProfile + ) user_profile.transport = step_context.values["transport"] user_profile.name = step_context.values["name"] @@ -148,11 +154,14 @@ async def summary_step(self, step_context: WaterfallStepContext) -> DialogTurnRe MessageFactory.text("Thanks. Your profile will not be kept.") ) - # WaterfallStep always finishes with the end of the Waterfall or with another + # WaterfallStep always finishes with the end of the Waterfall or with another # dialog, here it is the end. return await step_context.end_dialog() @staticmethod async def age_prompt_validator(prompt_context: PromptValidatorContext) -> bool: # This condition is our validation rule. You can also change the value at this point. - return prompt_context.recognized.succeeded and 0 < prompt_context.recognized.value < 150 + return ( + prompt_context.recognized.succeeded + and 0 < prompt_context.recognized.value < 150 + ) diff --git a/samples/06.using-cards/app.py b/samples/06.using-cards/app.py index fe0c69b56..257474898 100644 --- a/samples/06.using-cards/app.py +++ b/samples/06.using-cards/app.py @@ -42,9 +42,11 @@ async def on_error(context: TurnContext, error: Exception): # Send a message to the user await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") + await context.send_activity( + "To continue to run this bot, please fix the bot source code." + ) # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': + if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", @@ -52,7 +54,7 @@ async def on_error(context: TurnContext, error: Exception): timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", - value_type="https://www.botframework.com/schemas/error" + value_type="https://www.botframework.com/schemas/error", ) # Send a trace activity, which will be displayed in Bot Framework Emulator await context.send_activity(trace_activity) @@ -60,6 +62,7 @@ async def on_error(context: TurnContext, error: Exception): # Clear out state await CONVERSATION_STATE.delete(context) + # Set the error handler on the Adapter. # In this case, we want an unbound method, so MethodType is not needed. ADAPTER.on_turn_error = on_error diff --git a/samples/06.using-cards/bots/dialog_bot.py b/samples/06.using-cards/bots/dialog_bot.py index 2702db884..ff4473e85 100644 --- a/samples/06.using-cards/bots/dialog_bot.py +++ b/samples/06.using-cards/bots/dialog_bot.py @@ -1,8 +1,6 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -import asyncio - from helpers.dialog_helper import DialogHelper from botbuilder.core import ActivityHandler, ConversationState, UserState, TurnContext from botbuilder.dialogs import Dialog diff --git a/samples/06.using-cards/bots/rich_cards_bot.py b/samples/06.using-cards/bots/rich_cards_bot.py index d307465a0..54da137db 100644 --- a/samples/06.using-cards/bots/rich_cards_bot.py +++ b/samples/06.using-cards/bots/rich_cards_bot.py @@ -5,13 +5,13 @@ from botbuilder.schema import ChannelAccount from .dialog_bot import DialogBot -""" - RichCardsBot prompts a user to select a Rich Card and then returns the card - that matches the user's selection. -""" - class RichCardsBot(DialogBot): + """ + RichCardsBot prompts a user to select a Rich Card and then returns the card + that matches the user's selection. + """ + def __init__(self, conversation_state, user_state, dialog): super().__init__(conversation_state, user_state, dialog) diff --git a/samples/06.using-cards/dialogs/main_dialog.py b/samples/06.using-cards/dialogs/main_dialog.py index 1a574e44c..9490933e7 100644 --- a/samples/06.using-cards/dialogs/main_dialog.py +++ b/samples/06.using-cards/dialogs/main_dialog.py @@ -4,8 +4,6 @@ from botbuilder.core import CardFactory, MessageFactory from botbuilder.dialogs import ( ComponentDialog, - DialogSet, - DialogTurnStatus, WaterfallDialog, WaterfallStepContext, ) @@ -28,8 +26,8 @@ ReceiptItem, ) -from .resources.adaptive_card_example import ADAPTIVE_CARD_CONTENT from helpers.activity_helper import create_activity_reply +from .resources.adaptive_card_example import ADAPTIVE_CARD_CONTENT MAIN_WATERFALL_DIALOG = "mainWaterfallDialog" @@ -49,12 +47,11 @@ def __init__(self): # The initial child Dialog to run. self.initial_dialog_id = MAIN_WATERFALL_DIALOG - """ - 1. Prompts the user if the user is not in the middle of a dialog. - 2. Re-prompts the user when an invalid input is received. - """ - async def choice_card_step(self, step_context: WaterfallStepContext): + """ + 1. Prompts the user if the user is not in the middle of a dialog. + 2. Re-prompts the user when an invalid input is received. + """ menu_text = ( "Which card would you like to see?\n" "(1) Adaptive Card\n" @@ -73,12 +70,12 @@ async def choice_card_step(self, step_context: WaterfallStepContext): "TextPrompt", PromptOptions(prompt=MessageFactory.text(menu_text)) ) - """ - Send a Rich Card response to the user based on their choice. - self method is only called when a valid prompt response is parsed from the user's response to the ChoicePrompt. - """ - async def show_card_step(self, step_context: WaterfallStepContext): + """ + Send a Rich Card response to the user based on their choice. + self method is only called when a valid prompt response is parsed from the user's + response to the ChoicePrompt. + """ response = step_context.result.lower().strip() choice_dict = { "1": [self.create_adaptive_card], @@ -141,11 +138,9 @@ async def show_card_step(self, step_context: WaterfallStepContext): return await step_context.end_dialog() - """ - ====================================== - Helper functions used to create cards. - ====================================== - """ + # ====================================== + # Helper functions used to create cards. + # ====================================== # Methods to generate cards def create_adaptive_card(self) -> Attachment: diff --git a/samples/06.using-cards/helpers/activity_helper.py b/samples/06.using-cards/helpers/activity_helper.py index 16188a3ad..354317c3e 100644 --- a/samples/06.using-cards/helpers/activity_helper.py +++ b/samples/06.using-cards/helpers/activity_helper.py @@ -5,7 +5,6 @@ from botbuilder.schema import ( Activity, ActivityTypes, - Attachment, ChannelAccount, ConversationAccount, ) @@ -15,9 +14,11 @@ def create_activity_reply( activity: Activity, text: str = None, locale: str = None, - attachments: [Attachment] = [], + attachments=None, ): - attachments_aux = [attachment for attachment in attachments] + if attachments is None: + attachments = [] + attachments_aux = attachments.copy() return Activity( type=ActivityTypes.message, diff --git a/samples/08.suggested-actions/app.py b/samples/08.suggested-actions/app.py index 4e9403486..1504563d3 100644 --- a/samples/08.suggested-actions/app.py +++ b/samples/08.suggested-actions/app.py @@ -4,10 +4,13 @@ import asyncio import sys from datetime import datetime -from types import MethodType from flask import Flask, request, Response -from botbuilder.core import BotFrameworkAdapterSettings, BotFrameworkAdapter, TurnContext +from botbuilder.core import ( + BotFrameworkAdapterSettings, + BotFrameworkAdapter, + TurnContext, +) from botbuilder.schema import Activity, ActivityTypes from bots import SuggestActionsBot @@ -24,7 +27,7 @@ # Catch-all for errors. -async def on_error(self, context: TurnContext, error: Exception): +async def on_error(context: TurnContext, error: Exception): # This check writes out errors to console log .vs. app insights. # NOTE: In production environment, you should consider logging this to Azure # application insights. @@ -32,9 +35,11 @@ async def on_error(self, context: TurnContext, error: Exception): # Send a message to the user await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") + await context.send_activity( + "To continue to run this bot, please fix the bot source code." + ) # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': + if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", @@ -42,12 +47,13 @@ async def on_error(self, context: TurnContext, error: Exception): timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", - value_type="https://www.botframework.com/schemas/error" + value_type="https://www.botframework.com/schemas/error", ) # Send a trace activity, which will be displayed in Bot Framework Emulator await context.send_activity(trace_activity) -ADAPTER.on_turn_error = MethodType(on_error, ADAPTER) + +ADAPTER.on_turn_error = on_error # Create Bot BOT = SuggestActionsBot() diff --git a/samples/08.suggested-actions/bots/suggested_actions_bot.py b/samples/08.suggested-actions/bots/suggested_actions_bot.py index 5bee547be..3daa70d5e 100644 --- a/samples/08.suggested-actions/bots/suggested_actions_bot.py +++ b/samples/08.suggested-actions/bots/suggested_actions_bot.py @@ -4,15 +4,17 @@ from botbuilder.core import ActivityHandler, MessageFactory, TurnContext from botbuilder.schema import ChannelAccount, CardAction, ActionTypes, SuggestedActions -""" -This bot will respond to the user's input with suggested actions. -Suggested actions enable your bot to present buttons that the user -can tap to provide input. -""" - class SuggestActionsBot(ActivityHandler): - async def on_members_added_activity(self, members_added: [ChannelAccount], turn_context: TurnContext): + """ + This bot will respond to the user's input with suggested actions. + Suggested actions enable your bot to present buttons that the user + can tap to provide input. + """ + + async def on_members_added_activity( + self, members_added: [ChannelAccount], turn_context: TurnContext + ): """ Send a welcome message to the user and tell them what actions they may perform to use this bot """ @@ -34,10 +36,13 @@ async def on_message_activity(self, turn_context: TurnContext): async def _send_welcome_message(self, turn_context: TurnContext): for member in turn_context.activity.members_added: if member.id != turn_context.activity.recipient.id: - await turn_context.send_activity(MessageFactory.text( - f"Welcome to SuggestedActionsBot {member.name}. This bot will introduce you to suggestedActions. " - f"Please answer the question: " - )) + await turn_context.send_activity( + MessageFactory.text( + f"Welcome to SuggestedActionsBot {member.name}." + f" This bot will introduce you to suggestedActions." + f" Please answer the question: " + ) + ) await self._send_suggested_actions(turn_context) @@ -67,21 +72,9 @@ async def _send_suggested_actions(self, turn_context: TurnContext): reply.suggested_actions = SuggestedActions( actions=[ - CardAction( - title="Red", - type=ActionTypes.im_back, - value="Read" - ), - CardAction( - title="Yellow", - type=ActionTypes.im_back, - value="Yellow" - ), - CardAction( - title="Blue", - type=ActionTypes.im_back, - value="Blue" - ) + CardAction(title="Red", type=ActionTypes.im_back, value="Red"), + CardAction(title="Yellow", type=ActionTypes.im_back, value="Yellow"), + CardAction(title="Blue", type=ActionTypes.im_back, value="Blue"), ] ) diff --git a/samples/13.core-bot/adapter_with_error_handler.py b/samples/13.core-bot/adapter_with_error_handler.py index 8a4bcaf54..1826e1e47 100644 --- a/samples/13.core-bot/adapter_with_error_handler.py +++ b/samples/13.core-bot/adapter_with_error_handler.py @@ -9,7 +9,7 @@ ConversationState, TurnContext, ) -from botbuilder.schema import InputHints, ActivityTypes, Activity +from botbuilder.schema import ActivityTypes, Activity class AdapterWithErrorHandler(BotFrameworkAdapter): @@ -30,9 +30,11 @@ async def on_error(context: TurnContext, error: Exception): # Send a message to the user await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") + await context.send_activity( + "To continue to run this bot, please fix the bot source code." + ) # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': + if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", @@ -40,7 +42,7 @@ async def on_error(context: TurnContext, error: Exception): timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", - value_type="https://www.botframework.com/schemas/error" + value_type="https://www.botframework.com/schemas/error", ) # Send a trace activity, which will be displayed in Bot Framework Emulator await context.send_activity(trace_activity) diff --git a/samples/13.core-bot/booking_details.py b/samples/13.core-bot/booking_details.py index 24c7a1df8..9c2d2a1bc 100644 --- a/samples/13.core-bot/booking_details.py +++ b/samples/13.core-bot/booking_details.py @@ -1,8 +1,6 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -from typing import List - class BookingDetails: def __init__( @@ -10,8 +8,10 @@ def __init__( destination: str = None, origin: str = None, travel_date: str = None, - unsupported_airports: List[str] = [], + unsupported_airports=None, ): + if unsupported_airports is None: + unsupported_airports = [] self.destination = destination self.origin = origin self.travel_date = travel_date diff --git a/samples/13.core-bot/bots/dialog_and_welcome_bot.py b/samples/13.core-bot/bots/dialog_and_welcome_bot.py index b392e2e1f..bfe8957af 100644 --- a/samples/13.core-bot/bots/dialog_and_welcome_bot.py +++ b/samples/13.core-bot/bots/dialog_and_welcome_bot.py @@ -5,16 +5,14 @@ import os.path from typing import List -from botbuilder.core import CardFactory from botbuilder.core import ( - ActivityHandler, ConversationState, MessageFactory, UserState, TurnContext, ) from botbuilder.dialogs import Dialog -from botbuilder.schema import Activity, Attachment, ChannelAccount +from botbuilder.schema import Attachment, ChannelAccount from helpers.dialog_helper import DialogHelper from .dialog_bot import DialogBot @@ -51,8 +49,8 @@ async def on_members_added_activity( def create_adaptive_card_attachment(self): relative_path = os.path.abspath(os.path.dirname(__file__)) path = os.path.join(relative_path, "../cards/welcomeCard.json") - with open(path) as f: - card = json.load(f) + with open(path) as in_file: + card = json.load(in_file) return Attachment( content_type="application/vnd.microsoft.card.adaptive", content=card diff --git a/samples/13.core-bot/bots/dialog_bot.py b/samples/13.core-bot/bots/dialog_bot.py index fc563d2ec..eb560a1be 100644 --- a/samples/13.core-bot/bots/dialog_bot.py +++ b/samples/13.core-bot/bots/dialog_bot.py @@ -1,8 +1,6 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -import asyncio - from botbuilder.core import ActivityHandler, ConversationState, UserState, TurnContext from botbuilder.dialogs import Dialog from helpers.dialog_helper import DialogHelper diff --git a/samples/13.core-bot/dialogs/booking_dialog.py b/samples/13.core-bot/dialogs/booking_dialog.py index 297dff07c..5b4381919 100644 --- a/samples/13.core-bot/dialogs/booking_dialog.py +++ b/samples/13.core-bot/dialogs/booking_dialog.py @@ -1,6 +1,8 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. +from datatypes_date_time.timex import Timex + from botbuilder.dialogs import WaterfallDialog, WaterfallStepContext, DialogTurnResult from botbuilder.dialogs.prompts import ConfirmPrompt, TextPrompt, PromptOptions from botbuilder.core import MessageFactory @@ -8,8 +10,6 @@ from .cancel_and_help_dialog import CancelAndHelpDialog from .date_resolver_dialog import DateResolverDialog -from datatypes_date_time.timex import Timex - class BookingDialog(CancelAndHelpDialog): def __init__(self, dialog_id: str = None): @@ -33,15 +33,14 @@ def __init__(self, dialog_id: str = None): self.initial_dialog_id = WaterfallDialog.__name__ - """ - If a destination city has not been provided, prompt for one. - :param step_context: - :return DialogTurnResult: - """ - async def destination_step( self, step_context: WaterfallStepContext ) -> DialogTurnResult: + """ + If a destination city has not been provided, prompt for one. + :param step_context: + :return DialogTurnResult: + """ booking_details = step_context.options if booking_details.destination is None: @@ -54,13 +53,12 @@ async def destination_step( ) return await step_context.next(booking_details.destination) - """ - If an origin city has not been provided, prompt for one. - :param step_context: - :return DialogTurnResult: - """ - async def origin_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: + """ + If an origin city has not been provided, prompt for one. + :param step_context: + :return DialogTurnResult: + """ booking_details = step_context.options # Capture the response to the previous step's prompt @@ -75,16 +73,15 @@ async def origin_step(self, step_context: WaterfallStepContext) -> DialogTurnRes ) return await step_context.next(booking_details.origin) - """ - If a travel date has not been provided, prompt for one. - This will use the DATE_RESOLVER_DIALOG. - :param step_context: - :return DialogTurnResult: - """ - async def travel_date_step( self, step_context: WaterfallStepContext ) -> DialogTurnResult: + """ + If a travel date has not been provided, prompt for one. + This will use the DATE_RESOLVER_DIALOG. + :param step_context: + :return DialogTurnResult: + """ booking_details = step_context.options # Capture the results of the previous step @@ -97,15 +94,14 @@ async def travel_date_step( ) return await step_context.next(booking_details.travel_date) - """ - Confirm the information the user has provided. - :param step_context: - :return DialogTurnResult: - """ - async def confirm_step( self, step_context: WaterfallStepContext ) -> DialogTurnResult: + """ + Confirm the information the user has provided. + :param step_context: + :return DialogTurnResult: + """ booking_details = step_context.options # Capture the results of the previous step @@ -123,14 +119,12 @@ async def confirm_step( ConfirmPrompt.__name__, PromptOptions(prompt=prompt_message) ) - """ - Complete the interaction and end the dialog. - :param step_context: - :return DialogTurnResult: - """ - async def final_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: - + """ + Complete the interaction and end the dialog. + :param step_context: + :return DialogTurnResult: + """ if step_context.result: booking_details = step_context.options diff --git a/samples/13.core-bot/dialogs/cancel_and_help_dialog.py b/samples/13.core-bot/dialogs/cancel_and_help_dialog.py index 93c71d7df..f8bcc77d0 100644 --- a/samples/13.core-bot/dialogs/cancel_and_help_dialog.py +++ b/samples/13.core-bot/dialogs/cancel_and_help_dialog.py @@ -31,7 +31,7 @@ async def interrupt(self, inner_dc: DialogContext) -> DialogTurnResult: help_message_text, help_message_text, InputHints.expecting_input ) - if text == "help" or text == "?": + if text in ("help", "?"): await inner_dc.context.send_activity(help_message) return DialogTurnResult(DialogTurnStatus.Waiting) @@ -40,7 +40,7 @@ async def interrupt(self, inner_dc: DialogContext) -> DialogTurnResult: cancel_message_text, cancel_message_text, InputHints.ignoring_input ) - if text == "cancel" or text == "quit": + if text in ("cancel", "quit"): await inner_dc.context.send_activity(cancel_message) return await inner_dc.cancel_all_dialogs() diff --git a/samples/13.core-bot/dialogs/date_resolver_dialog.py b/samples/13.core-bot/dialogs/date_resolver_dialog.py index a375b6fa4..a34f47a7a 100644 --- a/samples/13.core-bot/dialogs/date_resolver_dialog.py +++ b/samples/13.core-bot/dialogs/date_resolver_dialog.py @@ -1,6 +1,8 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. +from datatypes_date_time.timex import Timex + from botbuilder.core import MessageFactory from botbuilder.dialogs import WaterfallDialog, DialogTurnResult, WaterfallStepContext from botbuilder.dialogs.prompts import ( @@ -12,8 +14,6 @@ from botbuilder.schema import InputHints from .cancel_and_help_dialog import CancelAndHelpDialog -from datatypes_date_time.timex import Timex - class DateResolverDialog(CancelAndHelpDialog): def __init__(self, dialog_id: str = None): @@ -44,7 +44,8 @@ async def initial_step( prompt_msg_text, prompt_msg_text, InputHints.expecting_input ) - reprompt_msg_text = "I'm sorry, for best results, please enter your travel date including the month, day and year." + reprompt_msg_text = "I'm sorry, for best results, please enter your travel date including the month, " \ + "day and year. " reprompt_msg = MessageFactory.text( reprompt_msg_text, reprompt_msg_text, InputHints.expecting_input ) diff --git a/samples/13.core-bot/dialogs/main_dialog.py b/samples/13.core-bot/dialogs/main_dialog.py index d85242375..82dfaa00b 100644 --- a/samples/13.core-bot/dialogs/main_dialog.py +++ b/samples/13.core-bot/dialogs/main_dialog.py @@ -11,10 +11,10 @@ from botbuilder.core import MessageFactory, TurnContext from botbuilder.schema import InputHints -from .booking_dialog import BookingDialog from booking_details import BookingDetails from flight_booking_recognizer import FlightBookingRecognizer from helpers.luis_helper import LuisHelper, Intent +from .booking_dialog import BookingDialog class MainDialog(ComponentDialog): @@ -81,7 +81,7 @@ async def act_step(self, step_context: WaterfallStepContext) -> DialogTurnResult # Run the BookingDialog giving it whatever details we have from the LUIS call. return await step_context.begin_dialog(self._booking_dialog_id, luis_result) - elif intent == Intent.GET_WEATHER.value: + if intent == Intent.GET_WEATHER.value: get_weather_text = "TODO: get weather flow here" get_weather_message = MessageFactory.text( get_weather_text, get_weather_text, InputHints.ignoring_input diff --git a/samples/13.core-bot/helpers/luis_helper.py b/samples/13.core-bot/helpers/luis_helper.py index fc59d8969..3e28bc47e 100644 --- a/samples/13.core-bot/helpers/luis_helper.py +++ b/samples/13.core-bot/helpers/luis_helper.py @@ -81,8 +81,9 @@ async def execute_luis_query( from_entities[0]["text"].capitalize() ) - # This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the Time part. - # TIMEX is a format that represents DateTime expressions that include some ambiguity. e.g. missing a Year. + # This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop + # the Time part. TIMEX is a format that represents DateTime expressions that include some ambiguity. + # e.g. missing a Year. date_entities = recognizer_result.entities.get("datetime", []) if date_entities: timex = date_entities[0]["timex"] @@ -95,7 +96,7 @@ async def execute_luis_query( else: result.travel_date = None - except Exception as e: - print(e) + except Exception as exception: + print(exception) return intent, result diff --git a/samples/15.handling-attachments/app.py b/samples/15.handling-attachments/app.py index 7a67a1231..47758a1e3 100644 --- a/samples/15.handling-attachments/app.py +++ b/samples/15.handling-attachments/app.py @@ -4,10 +4,13 @@ import asyncio import sys from datetime import datetime -from types import MethodType from flask import Flask, request, Response -from botbuilder.core import BotFrameworkAdapterSettings, TurnContext, BotFrameworkAdapter +from botbuilder.core import ( + BotFrameworkAdapterSettings, + TurnContext, + BotFrameworkAdapter, +) from botbuilder.schema import Activity, ActivityTypes from bots import AttachmentsBot @@ -32,9 +35,11 @@ async def on_error(context: TurnContext, error: Exception): # Send a message to the user await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") + await context.send_activity( + "To continue to run this bot, please fix the bot source code." + ) # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': + if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", @@ -42,11 +47,12 @@ async def on_error(context: TurnContext, error: Exception): timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", - value_type="https://www.botframework.com/schemas/error" + value_type="https://www.botframework.com/schemas/error", ) # Send a trace activity, which will be displayed in Bot Framework Emulator await context.send_activity(trace_activity) + ADAPTER.on_turn_error = on_error # Create the Bot diff --git a/samples/15.handling-attachments/bots/attachments_bot.py b/samples/15.handling-attachments/bots/attachments_bot.py index 194b83564..51fd8bb50 100644 --- a/samples/15.handling-attachments/bots/attachments_bot.py +++ b/samples/15.handling-attachments/bots/attachments_bot.py @@ -16,25 +16,30 @@ Attachment, AttachmentData, Activity, - ActionTypes + ActionTypes, ) -""" -Represents a bot that processes incoming activities. -For each user interaction, an instance of this class is created and the OnTurnAsync method is called. -This is a Transient lifetime service. Transient lifetime services are created -each time they're requested. For each Activity received, a new instance of this -class is created. Objects that are expensive to construct, or have a lifetime -beyond the single turn, should be carefully managed. -""" - class AttachmentsBot(ActivityHandler): - async def on_members_added_activity(self, members_added: [ChannelAccount], turn_context: TurnContext): + """ + Represents a bot that processes incoming activities. + For each user interaction, an instance of this class is created and the OnTurnAsync method is called. + This is a Transient lifetime service. Transient lifetime services are created + each time they're requested. For each Activity received, a new instance of this + class is created. Objects that are expensive to construct, or have a lifetime + beyond the single turn, should be carefully managed. + """ + + async def on_members_added_activity( + self, members_added: [ChannelAccount], turn_context: TurnContext + ): await self._send_welcome_message(turn_context) async def on_message_activity(self, turn_context: TurnContext): - if turn_context.activity.attachments and len(turn_context.activity.attachments) > 0: + if ( + turn_context.activity.attachments + and len(turn_context.activity.attachments) > 0 + ): await self._handle_incoming_attachment(turn_context) else: await self._handle_outgoing_attachment(turn_context) @@ -49,8 +54,10 @@ async def _send_welcome_message(self, turn_context: TurnContext): """ for member in turn_context.activity.members_added: if member.id != turn_context.activity.recipient.id: - await turn_context.send_activity(f"Welcome to AttachmentsBot {member.name}. This bot will introduce " - f"you to Attachments. Please select an option") + await turn_context.send_activity( + f"Welcome to AttachmentsBot {member.name}. This bot will introduce " + f"you to Attachments. Please select an option" + ) await self._display_options(turn_context) async def _handle_incoming_attachment(self, turn_context: TurnContext): @@ -68,7 +75,8 @@ async def _handle_incoming_attachment(self, turn_context: TurnContext): attachment_info = await self._download_attachment_and_write(attachment) if "filename" in attachment_info: await turn_context.send_activity( - f"Attachment {attachment_info['filename']} has been received to {attachment_info['local_path']}") + f"Attachment {attachment_info['filename']} has been received to {attachment_info['local_path']}" + ) async def _download_attachment_and_write(self, attachment: Attachment) -> dict: """ @@ -91,18 +99,13 @@ async def _download_attachment_and_write(self, attachment: Attachment) -> dict: with open(local_filename, "wb") as out_file: out_file.write(data) - return { - "filename": attachment.name, - "local_path": local_filename - } - except Exception as e: - print(e) + return {"filename": attachment.name, "local_path": local_filename} + except Exception as exception: + print(exception) return {} async def _handle_outgoing_attachment(self, turn_context: TurnContext): - reply = Activity( - type=ActivityTypes.message - ) + reply = Activity(type=ActivityTypes.message) first_char = turn_context.activity.text[0] if first_char == "1": @@ -133,21 +136,15 @@ async def _display_options(self, turn_context: TurnContext): text="You can upload an image or select one of the following choices", buttons=[ CardAction( - type=ActionTypes.im_back, - title="1. Inline Attachment", - value="1" + type=ActionTypes.im_back, title="1. Inline Attachment", value="1" ), CardAction( - type=ActionTypes.im_back, - title="2. Internet Attachment", - value="2" + type=ActionTypes.im_back, title="2. Internet Attachment", value="2" ), CardAction( - type=ActionTypes.im_back, - title="3. Uploaded Attachment", - value="3" - ) - ] + type=ActionTypes.im_back, title="3. Uploaded Attachment", value="3" + ), + ], ) reply = MessageFactory.attachment(CardFactory.hero_card(card)) @@ -169,7 +166,7 @@ def _get_inline_attachment(self) -> Attachment: return Attachment( name="architecture-resize.png", content_type="image/png", - content_url=f"data:image/png;base64,{base64_image}" + content_url=f"data:image/png;base64,{base64_image}", ) async def _get_upload_attachment(self, turn_context: TurnContext) -> Attachment: @@ -178,29 +175,35 @@ async def _get_upload_attachment(self, turn_context: TurnContext) -> Attachment: :param turn_context: :return: Attachment """ - with open(os.path.join(os.getcwd(), "resources/architecture-resize.png"), "rb") as in_file: + with open( + os.path.join(os.getcwd(), "resources/architecture-resize.png"), "rb" + ) as in_file: image_data = in_file.read() - connector = turn_context.adapter.create_connector_client(turn_context.activity.service_url) + connector = turn_context.adapter.create_connector_client( + turn_context.activity.service_url + ) conversation_id = turn_context.activity.conversation.id response = await connector.conversations.upload_attachment( conversation_id, AttachmentData( name="architecture-resize.png", original_base64=image_data, - type="image/png" - ) + type="image/png", + ), ) base_uri: str = connector.config.base_url - attachment_uri = (base_uri - + ("" if base_uri.endswith("/") else "/") - + f"v3/attachments/{response.id}/views/original") + attachment_uri = ( + base_uri + + ("" if base_uri.endswith("/") else "/") + + f"v3/attachments/{response.id}/views/original" + ) return Attachment( name="architecture-resize.png", content_type="image/png", - content_url=attachment_uri + content_url=attachment_uri, ) def _get_internet_attachment(self) -> Attachment: @@ -211,5 +214,5 @@ def _get_internet_attachment(self) -> Attachment: return Attachment( name="architecture-resize.png", content_type="image/png", - content_url="https://docs.microsoft.com/en-us/bot-framework/media/how-it-works/architecture-resize.png" + content_url="https://docs.microsoft.com/en-us/bot-framework/media/how-it-works/architecture-resize.png", ) diff --git a/samples/16.proactive-messages/app.py b/samples/16.proactive-messages/app.py index 8abfdaeda..b00709eff 100644 --- a/samples/16.proactive-messages/app.py +++ b/samples/16.proactive-messages/app.py @@ -5,11 +5,14 @@ import sys import uuid from datetime import datetime -from types import MethodType from typing import Dict from flask import Flask, request, Response -from botbuilder.core import BotFrameworkAdapterSettings, TurnContext, BotFrameworkAdapter +from botbuilder.core import ( + BotFrameworkAdapterSettings, + TurnContext, + BotFrameworkAdapter, +) from botbuilder.schema import Activity, ActivityTypes, ConversationReference from bots import ProactiveBot @@ -26,7 +29,7 @@ # Catch-all for errors. -async def on_error(self, context: TurnContext, error: Exception): +async def on_error(context: TurnContext, error: Exception): # This check writes out errors to console log .vs. app insights. # NOTE: In production environment, you should consider logging this to Azure # application insights. @@ -34,9 +37,11 @@ async def on_error(self, context: TurnContext, error: Exception): # Send a message to the user await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") + await context.send_activity( + "To continue to run this bot, please fix the bot source code." + ) # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': + if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", @@ -44,12 +49,13 @@ async def on_error(self, context: TurnContext, error: Exception): timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", - value_type="https://www.botframework.com/schemas/error" + value_type="https://www.botframework.com/schemas/error", ) # Send a trace activity, which will be displayed in Bot Framework Emulator await context.send_activity(trace_activity) -ADAPTER.on_turn_error = MethodType(on_error, ADAPTER) + +ADAPTER.on_turn_error = on_error # Create a shared dictionary. The Bot will add conversation references when users # join the conversation and send messages. @@ -91,9 +97,7 @@ def messages(): @APP.route("/api/notify") def notify(): try: - task = LOOP.create_task( - _send_proactive_message() - ) + task = LOOP.create_task(_send_proactive_message()) LOOP.run_until_complete(task) return Response(status=201, response="Proactive messages have been sent") @@ -108,7 +112,7 @@ async def _send_proactive_message(): return await ADAPTER.continue_conversation( APP_ID, conversation_reference, - lambda turn_context: turn_context.send_activity("proactive hello") + lambda turn_context: turn_context.send_activity("proactive hello"), ) diff --git a/samples/16.proactive-messages/bots/proactive_bot.py b/samples/16.proactive-messages/bots/proactive_bot.py index 79cc2df71..c65626899 100644 --- a/samples/16.proactive-messages/bots/proactive_bot.py +++ b/samples/16.proactive-messages/bots/proactive_bot.py @@ -8,9 +8,7 @@ class ProactiveBot(ActivityHandler): - def __init__( - self, conversation_references: Dict[str, ConversationReference] - ): + def __init__(self, conversation_references: Dict[str, ConversationReference]): self.conversation_references = conversation_references async def on_conversation_update_activity(self, turn_context: TurnContext): @@ -22,13 +20,17 @@ async def on_members_added_activity( ): for member in members_added: if member.id != turn_context.activity.recipient.id: - await turn_context.send_activity("Welcome to the Proactive Bot sample. Navigate to " - "http://localhost:3978/api/notify to proactively message everyone " - "who has previously messaged this bot.") + await turn_context.send_activity( + "Welcome to the Proactive Bot sample. Navigate to " + "http://localhost:3978/api/notify to proactively message everyone " + "who has previously messaged this bot." + ) async def on_message_activity(self, turn_context: TurnContext): self._add_conversation_reference(turn_context.activity) - return await turn_context.send_activity(f"You sent: {turn_context.activity.text}") + return await turn_context.send_activity( + f"You sent: {turn_context.activity.text}" + ) def _add_conversation_reference(self, activity: Activity): """ @@ -38,4 +40,6 @@ def _add_conversation_reference(self, activity: Activity): :return: """ conversation_reference = TurnContext.get_conversation_reference(activity) - self.conversation_references[conversation_reference.user.id] = conversation_reference + self.conversation_references[ + conversation_reference.user.id + ] = conversation_reference diff --git a/samples/17.multilingual-bot/app.py b/samples/17.multilingual-bot/app.py index 20b1490b4..bdba1af1a 100644 --- a/samples/17.multilingual-bot/app.py +++ b/samples/17.multilingual-bot/app.py @@ -4,7 +4,6 @@ import asyncio import sys from datetime import datetime -from types import MethodType from flask import Flask, request, Response from botbuilder.core import ( @@ -40,9 +39,11 @@ async def on_error(context: TurnContext, error: Exception): # Send a message to the user await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") + await context.send_activity( + "To continue to run this bot, please fix the bot source code." + ) # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': + if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", @@ -50,11 +51,12 @@ async def on_error(context: TurnContext, error: Exception): timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", - value_type="https://www.botframework.com/schemas/error" + value_type="https://www.botframework.com/schemas/error", ) # Send a trace activity, which will be displayed in Bot Framework Emulator await context.send_activity(trace_activity) + ADAPTER.on_turn_error = on_error # Create MemoryStorage and state @@ -62,7 +64,9 @@ async def on_error(context: TurnContext, error: Exception): USER_STATE = UserState(MEMORY) # Create translation middleware and add to adapter -TRANSLATOR = MicrosoftTranslator(app.config["SUBSCRIPTION_KEY"], app.config["SUBSCRIPTION_REGION"]) +TRANSLATOR = MicrosoftTranslator( + app.config["SUBSCRIPTION_KEY"], app.config["SUBSCRIPTION_REGION"] +) TRANSLATION_MIDDLEWARE = TranslationMiddleware(TRANSLATOR, USER_STATE) ADAPTER.use(TRANSLATION_MIDDLEWARE) diff --git a/samples/17.multilingual-bot/bots/multilingual_bot.py b/samples/17.multilingual-bot/bots/multilingual_bot.py index 8ff3de599..b2bcf24fa 100644 --- a/samples/17.multilingual-bot/bots/multilingual_bot.py +++ b/samples/17.multilingual-bot/bots/multilingual_bot.py @@ -4,19 +4,31 @@ import json import os -from botbuilder.core import ActivityHandler, TurnContext, UserState, CardFactory, MessageFactory -from botbuilder.schema import ChannelAccount, Attachment, SuggestedActions, CardAction, ActionTypes +from botbuilder.core import ( + ActivityHandler, + TurnContext, + UserState, + CardFactory, + MessageFactory, +) +from botbuilder.schema import ( + ChannelAccount, + Attachment, + SuggestedActions, + CardAction, + ActionTypes, +) from translation.translation_settings import TranslationSettings -""" -This bot demonstrates how to use Microsoft Translator. -More information can be found at: -https://docs.microsoft.com/en-us/azure/cognitive-services/translator/translator-info-overview" -""" - class MultiLingualBot(ActivityHandler): + """ + This bot demonstrates how to use Microsoft Translator. + More information can be found at: + https://docs.microsoft.com/en-us/azure/cognitive-services/translator/translator-info-overview" + """ + def __init__(self, user_state: UserState): if user_state is None: raise TypeError( @@ -25,10 +37,12 @@ def __init__(self, user_state: UserState): self.user_state = user_state - self.language_preference_accessor = self.user_state.create_property("LanguagePreference") + self.language_preference_accessor = self.user_state.create_property( + "LanguagePreference" + ) async def on_members_added_activity( - self, members_added: [ChannelAccount], turn_context: TurnContext + self, members_added: [ChannelAccount], turn_context: TurnContext ): # Greet anyone that was not the target (recipient) of this message. # To learn more about Adaptive Cards, see https://aka.ms/msbot-adaptivecards for more details. @@ -38,7 +52,7 @@ async def on_members_added_activity( MessageFactory.attachment(self._create_adaptive_card_attachment()) ) await turn_context.send_activity( - "This bot will introduce you to translation middleware. Say \'hi\' to get started." + "This bot will introduce you to translation middleware. Say 'hi' to get started." ) async def on_message_activity(self, turn_context: TurnContext): @@ -49,8 +63,9 @@ async def on_message_activity(self, turn_context: TurnContext): # selected language. # If Spanish was selected by the user, the reply below will actually be shown in Spanish to the user. current_language = turn_context.activity.text.lower() - if current_language == TranslationSettings.english_english.value \ - or current_language == TranslationSettings.spanish_english.value: + if current_language in ( + TranslationSettings.english_english.value, TranslationSettings.spanish_english.value + ): lang = TranslationSettings.english_english.value else: lang = TranslationSettings.english_spanish.value @@ -71,13 +86,13 @@ async def on_message_activity(self, turn_context: TurnContext): CardAction( title="Español", type=ActionTypes.post_back, - value=TranslationSettings.english_spanish.value + value=TranslationSettings.english_spanish.value, ), CardAction( title="English", type=ActionTypes.post_back, - value=TranslationSettings.english_english.value - ) + value=TranslationSettings.english_english.value, + ), ] ) @@ -99,7 +114,9 @@ def _is_language_change_requested(self, utterance: str) -> bool: return False utterance = utterance.lower() - return (utterance == TranslationSettings.english_spanish.value - or utterance == TranslationSettings.english_english.value - or utterance == TranslationSettings.spanish_spanish.value - or utterance == TranslationSettings.spanish_english.value) + return utterance in ( + TranslationSettings.english_spanish.value, + TranslationSettings.english_english.value, + TranslationSettings.spanish_spanish.value, + TranslationSettings.spanish_english.value + ) diff --git a/samples/17.multilingual-bot/translation/microsoft_translator.py b/samples/17.multilingual-bot/translation/microsoft_translator.py index 4b9a796c8..9af148fc6 100644 --- a/samples/17.multilingual-bot/translation/microsoft_translator.py +++ b/samples/17.multilingual-bot/translation/microsoft_translator.py @@ -1,8 +1,8 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -import requests import uuid +import requests class MicrosoftTranslator: @@ -16,22 +16,20 @@ def __init__(self, subscription_key: str, subscription_region: str): # will grab these values from our web app, and use them in the request. # See main.js for Ajax calls. async def translate(self, text_input, language_output): - base_url = 'https://api.cognitive.microsofttranslator.com' - path = '/translate?api-version=3.0' - params = '&to=' + language_output + base_url = "https://api.cognitive.microsofttranslator.com" + path = "/translate?api-version=3.0" + params = "&to=" + language_output constructed_url = base_url + path + params headers = { - 'Ocp-Apim-Subscription-Key': self.subscription_key, - 'Ocp-Apim-Subscription-Region': self.subscription_region, - 'Content-type': 'application/json', - 'X-ClientTraceId': str(uuid.uuid4()) + "Ocp-Apim-Subscription-Key": self.subscription_key, + "Ocp-Apim-Subscription-Region": self.subscription_region, + "Content-type": "application/json", + "X-ClientTraceId": str(uuid.uuid4()), } # You can pass more than one object in body. - body = [{ - 'text': text_input - }] + body = [{"text": text_input}] response = requests.post(constructed_url, headers=headers, json=body) json_response = response.json() diff --git a/samples/17.multilingual-bot/translation/translation_middleware.py b/samples/17.multilingual-bot/translation/translation_middleware.py index 3b2ee0930..b983b2acb 100644 --- a/samples/17.multilingual-bot/translation/translation_middleware.py +++ b/samples/17.multilingual-bot/translation/translation_middleware.py @@ -9,39 +9,43 @@ from translation import MicrosoftTranslator from translation.translation_settings import TranslationSettings -""" -Middleware for translating text between the user and bot. -Uses the Microsoft Translator Text API. -""" - class TranslationMiddleware(Middleware): + """ + Middleware for translating text between the user and bot. + Uses the Microsoft Translator Text API. + """ + def __init__(self, translator: MicrosoftTranslator, user_state: UserState): self.translator = translator - self.language_preference_accessor = user_state.create_property("LanguagePreference") + self.language_preference_accessor = user_state.create_property( + "LanguagePreference" + ) async def on_turn( - self, turn_context: TurnContext, logic: Callable[[TurnContext], Awaitable] + self, context: TurnContext, logic: Callable[[TurnContext], Awaitable] ): """ Processes an incoming activity. - :param turn_context: + :param context: :param logic: :return: """ - translate = await self._should_translate(turn_context) - if translate and turn_context.activity.type == ActivityTypes.message: - turn_context.activity.text = await self.translator.translate( - turn_context.activity.text, TranslationSettings.default_language.value + translate = await self._should_translate(context) + if translate and context.activity.type == ActivityTypes.message: + context.activity.text = await self.translator.translate( + context.activity.text, TranslationSettings.default_language.value ) async def aux_on_send( - context: TurnContext, activities: List[Activity], next_send: Callable + ctx: TurnContext, activities: List[Activity], next_send: Callable ): user_language = await self.language_preference_accessor.get( - context, TranslationSettings.default_language.value + ctx, TranslationSettings.default_language.value + ) + should_translate = ( + user_language != TranslationSettings.default_language.value ) - should_translate = user_language != TranslationSettings.default_language.value # Translate messages sent to the user to user language if should_translate: @@ -51,12 +55,14 @@ async def aux_on_send( return await next_send() async def aux_on_update( - context: TurnContext, activity: Activity, next_update: Callable + ctx: TurnContext, activity: Activity, next_update: Callable ): user_language = await self.language_preference_accessor.get( - context, TranslationSettings.default_language.value + ctx, TranslationSettings.default_language.value + ) + should_translate = ( + user_language != TranslationSettings.default_language.value ) - should_translate = user_language != TranslationSettings.default_language.value # Translate messages sent to the user to user language if should_translate and activity.type == ActivityTypes.message: @@ -64,15 +70,19 @@ async def aux_on_update( return await next_update() - turn_context.on_send_activities(aux_on_send) - turn_context.on_update_activity(aux_on_update) + context.on_send_activities(aux_on_send) + context.on_update_activity(aux_on_update) await logic() async def _should_translate(self, turn_context: TurnContext) -> bool: - user_language = await self.language_preference_accessor.get(turn_context, TranslationSettings.default_language.value) + user_language = await self.language_preference_accessor.get( + turn_context, TranslationSettings.default_language.value + ) return user_language != TranslationSettings.default_language.value async def _translate_message_activity(self, activity: Activity, target_locale: str): if activity.type == ActivityTypes.message: - activity.text = await self.translator.translate(activity.text, target_locale) + activity.text = await self.translator.translate( + activity.text, target_locale + ) diff --git a/samples/18.bot-authentication/app.py b/samples/18.bot-authentication/app.py index 70d9e8334..c8910b155 100644 --- a/samples/18.bot-authentication/app.py +++ b/samples/18.bot-authentication/app.py @@ -4,7 +4,6 @@ import asyncio import sys from datetime import datetime -from types import MethodType from flask import Flask, request, Response from botbuilder.core import ( @@ -33,7 +32,7 @@ # Catch-all for errors. -async def on_error(self, context: TurnContext, error: Exception): +async def on_error(context: TurnContext, error: Exception): # This check writes out errors to console log .vs. app insights. # NOTE: In production environment, you should consider logging this to Azure # application insights. @@ -41,10 +40,12 @@ async def on_error(self, context: TurnContext, error: Exception): # Send a message to the user await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") + await context.send_activity( + "To continue to run this bot, please fix the bot source code." + ) # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': + if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", @@ -52,12 +53,13 @@ async def on_error(self, context: TurnContext, error: Exception): timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", - value_type="https://www.botframework.com/schemas/error" + value_type="https://www.botframework.com/schemas/error", ) # Send a trace activity, which will be displayed in Bot Framework Emulator await context.send_activity(trace_activity) -ADAPTER.on_turn_error = MethodType(on_error, ADAPTER) + +ADAPTER.on_turn_error = on_error # Create MemoryStorage and state MEMORY = MemoryStorage() diff --git a/samples/18.bot-authentication/bots/auth_bot.py b/samples/18.bot-authentication/bots/auth_bot.py index c1d1d936f..93166f655 100644 --- a/samples/18.bot-authentication/bots/auth_bot.py +++ b/samples/18.bot-authentication/bots/auth_bot.py @@ -21,9 +21,7 @@ def __init__( user_state: UserState, dialog: Dialog, ): - super(AuthBot, self).__init__( - conversation_state, user_state, dialog - ) + super(AuthBot, self).__init__(conversation_state, user_state, dialog) async def on_members_added_activity( self, members_added: List[ChannelAccount], turn_context: TurnContext @@ -32,12 +30,12 @@ async def on_members_added_activity( # Greet anyone that was not the target (recipient) of this message. # To learn more about Adaptive Cards, see https://aka.ms/msbot-adaptivecards for more details. if member.id != turn_context.activity.recipient.id: - await turn_context.send_activity("Welcome to AuthenticationBot. Type anything to get logged in. Type " - "'logout' to sign-out.") + await turn_context.send_activity( + "Welcome to AuthenticationBot. Type anything to get logged in. Type " + "'logout' to sign-out." + ) - async def on_token_response_event( - self, turn_context: TurnContext - ): + async def on_token_response_event(self, turn_context: TurnContext): # Run the Dialog with the new Token Response Event Activity. await DialogHelper.run_dialog( self.dialog, diff --git a/samples/18.bot-authentication/bots/dialog_bot.py b/samples/18.bot-authentication/bots/dialog_bot.py index fc563d2ec..eb560a1be 100644 --- a/samples/18.bot-authentication/bots/dialog_bot.py +++ b/samples/18.bot-authentication/bots/dialog_bot.py @@ -1,8 +1,6 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -import asyncio - from botbuilder.core import ActivityHandler, ConversationState, UserState, TurnContext from botbuilder.dialogs import Dialog from helpers.dialog_helper import DialogHelper diff --git a/samples/18.bot-authentication/dialogs/logout_dialog.py b/samples/18.bot-authentication/dialogs/logout_dialog.py index b8d420a40..de77e5c04 100644 --- a/samples/18.bot-authentication/dialogs/logout_dialog.py +++ b/samples/18.bot-authentication/dialogs/logout_dialog.py @@ -12,7 +12,9 @@ def __init__(self, dialog_id: str, connection_name: str): self.connection_name = connection_name - async def on_begin_dialog(self, inner_dc: DialogContext, options: object) -> DialogTurnResult: + async def on_begin_dialog( + self, inner_dc: DialogContext, options: object + ) -> DialogTurnResult: return await inner_dc.begin_dialog(self.initial_dialog_id, options) async def on_continue_dialog(self, inner_dc: DialogContext) -> DialogTurnResult: diff --git a/samples/18.bot-authentication/dialogs/main_dialog.py b/samples/18.bot-authentication/dialogs/main_dialog.py index 3e7a80287..964a3aff2 100644 --- a/samples/18.bot-authentication/dialogs/main_dialog.py +++ b/samples/18.bot-authentication/dialogs/main_dialog.py @@ -6,16 +6,15 @@ WaterfallDialog, WaterfallStepContext, DialogTurnResult, - PromptOptions) + PromptOptions, +) from botbuilder.dialogs.prompts import OAuthPrompt, OAuthPromptSettings, ConfirmPrompt from dialogs import LogoutDialog class MainDialog(LogoutDialog): - def __init__( - self, connection_name: str - ): + def __init__(self, connection_name: str): super(MainDialog, self).__init__(MainDialog.__name__, connection_name) self.add_dialog( @@ -25,8 +24,8 @@ def __init__( connection_name=connection_name, text="Please Sign In", title="Sign In", - timeout=300000 - ) + timeout=300000, + ), ) ) @@ -34,12 +33,13 @@ def __init__( self.add_dialog( WaterfallDialog( - "WFDialog", [ + "WFDialog", + [ self.prompt_step, self.login_step, self.display_token_phase1, - self.display_token_phase2 - ] + self.display_token_phase2, + ], ) ) @@ -53,14 +53,21 @@ async def login_step(self, step_context: WaterfallStepContext) -> DialogTurnResu # token directly from the prompt itself. There is an example of this in the next method. if step_context.result: await step_context.context.send_activity("You are now logged in.") - return await step_context.prompt(ConfirmPrompt.__name__, PromptOptions( - prompt=MessageFactory.text("Would you like to view your token?") - )) + return await step_context.prompt( + ConfirmPrompt.__name__, + PromptOptions( + prompt=MessageFactory.text("Would you like to view your token?") + ), + ) - await step_context.context.send_activity("Login was not successful please try again.") + await step_context.context.send_activity( + "Login was not successful please try again." + ) return await step_context.end_dialog() - async def display_token_phase1(self, step_context: WaterfallStepContext) -> DialogTurnResult: + async def display_token_phase1( + self, step_context: WaterfallStepContext + ) -> DialogTurnResult: await step_context.context.send_activity("Thank you.") if step_context.result: @@ -76,8 +83,12 @@ async def display_token_phase1(self, step_context: WaterfallStepContext) -> Dial return await step_context.end_dialog() - async def display_token_phase2(self, step_context: WaterfallStepContext) -> DialogTurnResult: + async def display_token_phase2( + self, step_context: WaterfallStepContext + ) -> DialogTurnResult: if step_context.result: - await step_context.context.send_activity(f"Here is your token {step_context.result['token']}") + await step_context.context.send_activity( + f"Here is your token {step_context.result['token']}" + ) - return await step_context.end_dialog() \ No newline at end of file + return await step_context.end_dialog() diff --git a/samples/19.custom-dialogs/app.py b/samples/19.custom-dialogs/app.py index 880dd8a85..1c3579210 100644 --- a/samples/19.custom-dialogs/app.py +++ b/samples/19.custom-dialogs/app.py @@ -4,7 +4,6 @@ import asyncio import sys from datetime import datetime -from types import MethodType from flask import Flask, request, Response from botbuilder.core import ( @@ -33,7 +32,7 @@ # Catch-all for errors. -async def on_error(self, context: TurnContext, error: Exception): +async def on_error(context: TurnContext, error: Exception): # This check writes out errors to console log .vs. app insights. # NOTE: In production environment, you should consider logging this to Azure # application insights. @@ -41,9 +40,11 @@ async def on_error(self, context: TurnContext, error: Exception): # Send a message to the user await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") + await context.send_activity( + "To continue to run this bot, please fix the bot source code." + ) # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': + if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", @@ -51,12 +52,13 @@ async def on_error(self, context: TurnContext, error: Exception): timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", - value_type="https://www.botframework.com/schemas/error" + value_type="https://www.botframework.com/schemas/error", ) # Send a trace activity, which will be displayed in Bot Framework Emulator await context.send_activity(trace_activity) -ADAPTER.on_turn_error = MethodType(on_error, ADAPTER) + +ADAPTER.on_turn_error = on_error # Create MemoryStorage and state MEMORY = MemoryStorage() diff --git a/samples/19.custom-dialogs/bots/dialog_bot.py b/samples/19.custom-dialogs/bots/dialog_bot.py index b9648661c..2edc0dbe4 100644 --- a/samples/19.custom-dialogs/bots/dialog_bot.py +++ b/samples/19.custom-dialogs/bots/dialog_bot.py @@ -8,7 +8,12 @@ class DialogBot(ActivityHandler): - def __init__(self, conversation_state: ConversationState, user_state: UserState, dialog: Dialog): + def __init__( + self, + conversation_state: ConversationState, + user_state: UserState, + dialog: Dialog, + ): self.conversation_state = conversation_state self.user_state = user_state self.dialog = dialog diff --git a/samples/19.custom-dialogs/dialogs/root_dialog.py b/samples/19.custom-dialogs/dialogs/root_dialog.py index e7ab55ec8..5d371ce6a 100644 --- a/samples/19.custom-dialogs/dialogs/root_dialog.py +++ b/samples/19.custom-dialogs/dialogs/root_dialog.py @@ -2,25 +2,25 @@ # Licensed under the MIT License. from typing import Dict +from recognizers_text import Culture from botbuilder.dialogs import ( ComponentDialog, WaterfallDialog, WaterfallStepContext, DialogTurnResult, - NumberPrompt, PromptValidatorContext) + NumberPrompt, + PromptValidatorContext, +) from botbuilder.dialogs.prompts import TextPrompt from botbuilder.core import MessageFactory, UserState -from recognizers_text import Culture from dialogs import SlotFillingDialog from dialogs.slot_details import SlotDetails class RootDialog(ComponentDialog): - def __init__( - self, user_state: UserState - ): + def __init__(self, user_state: UserState): super(RootDialog, self).__init__(RootDialog.__name__) self.user_state_accessor = user_state.create_property("result") @@ -29,15 +29,11 @@ def __init__( # In this example we will want two text prompts to run, one for the first name and one for the last fullname_slots = [ SlotDetails( - name="first", - dialog_id="text", - prompt="Please enter your first name." + name="first", dialog_id="text", prompt="Please enter your first name." ), SlotDetails( - name="last", - dialog_id="text", - prompt="Please enter your last name." - ) + name="last", dialog_id="text", prompt="Please enter your last name." + ), ] # This defines an address dialog that collects street, city and zip properties. @@ -45,42 +41,26 @@ def __init__( SlotDetails( name="street", dialog_id="text", - prompt="Please enter the street address." + prompt="Please enter the street address.", ), - SlotDetails( - name="city", - dialog_id="text", - prompt="Please enter the city." - ), - SlotDetails( - name="zip", - dialog_id="text", - prompt="Please enter the zip." - ) + SlotDetails(name="city", dialog_id="text", prompt="Please enter the city."), + SlotDetails(name="zip", dialog_id="text", prompt="Please enter the zip."), ] # Dialogs can be nested and the slot filling dialog makes use of that. In this example some of the child # dialogs are slot filling dialogs themselves. slots = [ + SlotDetails(name="fullname", dialog_id="fullname",), SlotDetails( - name="fullname", - dialog_id="fullname", - ), - SlotDetails( - name="age", - dialog_id="number", - prompt="Please enter your age." + name="age", dialog_id="number", prompt="Please enter your age." ), SlotDetails( name="shoesize", dialog_id="shoesize", prompt="Please enter your shoe size.", - retry_prompt="You must enter a size between 0 and 16. Half sizes are acceptable." + retry_prompt="You must enter a size between 0 and 16. Half sizes are acceptable.", ), - SlotDetails( - name="address", - dialog_id="address" - ) + SlotDetails(name="address", dialog_id="address"), ] # Add the various dialogs that will be used to the DialogSet. @@ -88,27 +68,35 @@ def __init__( self.add_dialog(SlotFillingDialog("fullname", fullname_slots)) self.add_dialog(TextPrompt("text")) self.add_dialog(NumberPrompt("number", default_locale=Culture.English)) - self.add_dialog(NumberPrompt("shoesize", RootDialog.shoe_size_validator, default_locale=Culture.English)) + self.add_dialog( + NumberPrompt( + "shoesize", + RootDialog.shoe_size_validator, + default_locale=Culture.English, + ) + ) self.add_dialog(SlotFillingDialog("slot-dialog", slots)) # Defines a simple two step Waterfall to test the slot dialog. self.add_dialog( - WaterfallDialog( - "waterfall", [self.start_dialog, self.process_result] - ) + WaterfallDialog("waterfall", [self.start_dialog, self.process_result]) ) # The initial child Dialog to run. self.initial_dialog_id = "waterfall" - async def start_dialog(self, step_context: WaterfallStepContext) -> DialogTurnResult: + async def start_dialog( + self, step_context: WaterfallStepContext + ) -> DialogTurnResult: # Start the child dialog. This will run the top slot dialog than will complete when all the properties are # gathered. return await step_context.begin_dialog("slot-dialog") - async def process_result(self, step_context: WaterfallStepContext) -> DialogTurnResult: + async def process_result( + self, step_context: WaterfallStepContext + ) -> DialogTurnResult: # To demonstrate that the slot dialog collected all the properties we will echo them back to the user. - if type(step_context.result) is dict and len(step_context.result) > 0: + if isinstance(step_context.result, dict) and len(step_context.result) > 0: fullname: Dict[str, object] = step_context.result["fullname"] shoe_size: float = step_context.result["shoesize"] address: dict = step_context.result["address"] @@ -118,12 +106,20 @@ async def process_result(self, step_context: WaterfallStepContext) -> DialogTurn obj["data"] = {} obj["data"]["fullname"] = f"{fullname.get('first')} {fullname.get('last')}" obj["data"]["shoesize"] = f"{shoe_size}" - obj["data"]["address"] = f"{address['street']}, {address['city']}, {address['zip']}" + obj["data"][ + "address" + ] = f"{address['street']}, {address['city']}, {address['zip']}" # show user the values - await step_context.context.send_activity(MessageFactory.text(obj["data"]["fullname"])) - await step_context.context.send_activity(MessageFactory.text(obj["data"]["shoesize"])) - await step_context.context.send_activity(MessageFactory.text(obj["data"]["address"])) + await step_context.context.send_activity( + MessageFactory.text(obj["data"]["fullname"]) + ) + await step_context.context.send_activity( + MessageFactory.text(obj["data"]["shoesize"]) + ) + await step_context.context.send_activity( + MessageFactory.text(obj["data"]["address"]) + ) return await step_context.end_dialog() diff --git a/samples/19.custom-dialogs/dialogs/slot_details.py b/samples/19.custom-dialogs/dialogs/slot_details.py index 3478f8b55..172d81c67 100644 --- a/samples/19.custom-dialogs/dialogs/slot_details.py +++ b/samples/19.custom-dialogs/dialogs/slot_details.py @@ -6,16 +6,23 @@ class SlotDetails: - def __init__(self, - name: str, - dialog_id: str, - options: PromptOptions = None, - prompt: str = None, - retry_prompt: str = None - ): + def __init__( + self, + name: str, + dialog_id: str, + options: PromptOptions = None, + prompt: str = None, + retry_prompt: str = None, + ): self.name = name self.dialog_id = dialog_id - self.options = options if options else PromptOptions( - prompt=MessageFactory.text(prompt), - retry_prompt=None if retry_prompt is None else MessageFactory.text(retry_prompt) + self.options = ( + options + if options + else PromptOptions( + prompt=MessageFactory.text(prompt), + retry_prompt=None + if retry_prompt is None + else MessageFactory.text(retry_prompt), + ) ) diff --git a/samples/19.custom-dialogs/dialogs/slot_filling_dialog.py b/samples/19.custom-dialogs/dialogs/slot_filling_dialog.py index 7f7043055..6e354431a 100644 --- a/samples/19.custom-dialogs/dialogs/slot_filling_dialog.py +++ b/samples/19.custom-dialogs/dialogs/slot_filling_dialog.py @@ -6,21 +6,24 @@ from botbuilder.dialogs import ( DialogContext, DialogTurnResult, - Dialog, DialogInstance, DialogReason) + Dialog, + DialogInstance, + DialogReason, +) from botbuilder.schema import ActivityTypes from dialogs.slot_details import SlotDetails -""" -This is an example of implementing a custom Dialog class. This is similar to the Waterfall dialog in the -framework; however, it is based on a Dictionary rather than a sequential set of functions. The dialog is defined by a -list of 'slots', each slot represents a property we want to gather and the dialog we will be using to collect it. -Often the property is simply an atomic piece of data such as a number or a date. But sometimes the property is itself -a complex object, in which case we can use the slot dialog to collect that compound property. -""" - class SlotFillingDialog(Dialog): + """ + This is an example of implementing a custom Dialog class. This is similar to the Waterfall dialog in the + framework; however, it is based on a Dictionary rather than a sequential set of functions. The dialog is defined + by a list of 'slots', each slot represents a property we want to gather and the dialog we will be using to + collect it. Often the property is simply an atomic piece of data such as a number or a date. But sometimes the + property is itself a complex object, in which case we can use the slot dialog to collect that compound property. + """ + def __init__(self, dialog_id: str, slots: List[SlotDetails]): super(SlotFillingDialog, self).__init__(dialog_id) @@ -34,17 +37,21 @@ def __init__(self, dialog_id: str, slots: List[SlotDetails]): # The list of slots defines the properties to collect and the dialogs to use to collect them. self.slots = slots - async def begin_dialog(self, dialog_context: DialogContext, options: object = None): + async def begin_dialog( + self, dialog_context: "DialogContext", options: object = None + ): if dialog_context.context.activity.type != ActivityTypes.message: return await dialog_context.end_dialog({}) return await self._run_prompt(dialog_context) - async def continue_dialog(self, dialog_context: DialogContext, options: object = None): + async def continue_dialog(self, dialog_context: "DialogContext"): if dialog_context.context.activity.type != ActivityTypes.message: return Dialog.end_of_turn return await self._run_prompt(dialog_context) - async def resume_dialog(self, dialog_context: DialogContext, reason: DialogReason, result: object): + async def resume_dialog( + self, dialog_context: DialogContext, reason: DialogReason, result: object + ): slot_name = dialog_context.active_dialog.state[self.SLOT_NAME] values = self._get_persisted_values(dialog_context.active_dialog) values[slot_name] = result @@ -74,12 +81,16 @@ async def _run_prompt(self, dialog_context: DialogContext) -> DialogTurnResult: dialog_context.active_dialog.state[self.SLOT_NAME] = unfilled_slot.name # Run the child dialog - return await dialog_context.begin_dialog(unfilled_slot.dialog_id, unfilled_slot.options) - else: - # No more slots to fill so end the dialog. - return await dialog_context.end_dialog(state) + return await dialog_context.begin_dialog( + unfilled_slot.dialog_id, unfilled_slot.options + ) + + # No more slots to fill so end the dialog. + return await dialog_context.end_dialog(state) - def _get_persisted_values(self, dialog_instance: DialogInstance) -> Dict[str, object]: + def _get_persisted_values( + self, dialog_instance: DialogInstance + ) -> Dict[str, object]: obj = dialog_instance.state.get(self.PERSISTED_VALUES) if not obj: diff --git a/samples/21.corebot-app-insights/app.py b/samples/21.corebot-app-insights/app.py index 5011c21f9..91d2f29af 100644 --- a/samples/21.corebot-app-insights/app.py +++ b/samples/21.corebot-app-insights/app.py @@ -52,9 +52,11 @@ async def on_error(context: TurnContext, error: Exception): # Send a message to the user await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") + await context.send_activity( + "To continue to run this bot, please fix the bot source code." + ) # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': + if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", @@ -62,7 +64,7 @@ async def on_error(context: TurnContext, error: Exception): timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", - value_type="https://www.botframework.com/schemas/error" + value_type="https://www.botframework.com/schemas/error", ) # Send a trace activity, which will be displayed in Bot Framework Emulator await context.send_activity(trace_activity) @@ -70,6 +72,7 @@ async def on_error(context: TurnContext, error: Exception): # Clear out state await CONVERSATION_STATE.delete(context) + # Set the error handler on the Adapter. # In this case, we want an unbound method, so MethodType is not needed. ADAPTER.on_turn_error = on_error diff --git a/samples/21.corebot-app-insights/bots/dialog_bot.py b/samples/21.corebot-app-insights/bots/dialog_bot.py index 3b55ba7a7..8c9322bc9 100644 --- a/samples/21.corebot-app-insights/bots/dialog_bot.py +++ b/samples/21.corebot-app-insights/bots/dialog_bot.py @@ -36,9 +36,6 @@ def __init__( self.conversation_state = conversation_state self.user_state = user_state self.dialog = dialog - self.dialogState = self.conversation_state.create_property( - "DialogState" - ) # pylint:disable=invalid-name self.telemetry_client = telemetry_client async def on_turn(self, turn_context: TurnContext): @@ -49,7 +46,6 @@ async def on_turn(self, turn_context: TurnContext): await self.user_state.save_changes(turn_context, False) async def on_message_activity(self, turn_context: TurnContext): - # pylint:disable=invalid-name await DialogHelper.run_dialog( self.dialog, turn_context, diff --git a/samples/21.corebot-app-insights/config.py b/samples/21.corebot-app-insights/config.py index 339154fc0..b3c87e304 100644 --- a/samples/21.corebot-app-insights/config.py +++ b/samples/21.corebot-app-insights/config.py @@ -16,4 +16,6 @@ class DefaultConfig: LUIS_API_KEY = os.environ.get("LuisAPIKey", "") # LUIS endpoint host name, ie "westus.api.cognitive.microsoft.com" LUIS_API_HOST_NAME = os.environ.get("LuisAPIHostName", "") - APPINSIGHTS_INSTRUMENTATION_KEY = os.environ.get("AppInsightsInstrumentationKey", "") + APPINSIGHTS_INSTRUMENTATION_KEY = os.environ.get( + "AppInsightsInstrumentationKey", "" + ) diff --git a/samples/21.corebot-app-insights/dialogs/booking_dialog.py b/samples/21.corebot-app-insights/dialogs/booking_dialog.py index 139d146fc..ab9b341b8 100644 --- a/samples/21.corebot-app-insights/dialogs/booking_dialog.py +++ b/samples/21.corebot-app-insights/dialogs/booking_dialog.py @@ -2,10 +2,11 @@ # Licensed under the MIT License. """Flight booking dialog.""" +from datatypes_date_time.timex import Timex + from botbuilder.dialogs import WaterfallDialog, WaterfallStepContext, DialogTurnResult from botbuilder.dialogs.prompts import ConfirmPrompt, TextPrompt, PromptOptions from botbuilder.core import MessageFactory, BotTelemetryClient, NullTelemetryClient -from datatypes_date_time.timex import Timex from .cancel_and_help_dialog import CancelAndHelpDialog from .date_resolver_dialog import DateResolverDialog @@ -59,8 +60,8 @@ async def destination_step( prompt=MessageFactory.text("To what city would you like to travel?") ), ) # pylint: disable=line-too-long,bad-continuation - else: - return await step_context.next(booking_details.destination) + + return await step_context.next(booking_details.destination) async def origin_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: """Prompt for origin city.""" @@ -75,8 +76,8 @@ async def origin_step(self, step_context: WaterfallStepContext) -> DialogTurnRes prompt=MessageFactory.text("From what city will you be travelling?") ), ) # pylint: disable=line-too-long,bad-continuation - else: - return await step_context.next(booking_details.origin) + + return await step_context.next(booking_details.origin) async def travel_date_step( self, step_context: WaterfallStepContext @@ -94,8 +95,8 @@ async def travel_date_step( return await step_context.begin_dialog( DateResolverDialog.__name__, booking_details.travel_date ) # pylint: disable=line-too-long - else: - return await step_context.next(booking_details.travel_date) + + return await step_context.next(booking_details.travel_date) async def confirm_step( self, step_context: WaterfallStepContext @@ -122,8 +123,8 @@ async def final_step(self, step_context: WaterfallStepContext) -> DialogTurnResu booking_details.travel_date = step_context.result return await step_context.end_dialog(booking_details) - else: - return await step_context.end_dialog() + + return await step_context.end_dialog() def is_ambiguous(self, timex: str) -> bool: """Ensure time is correct.""" diff --git a/samples/21.corebot-app-insights/dialogs/cancel_and_help_dialog.py b/samples/21.corebot-app-insights/dialogs/cancel_and_help_dialog.py index 2a73c669a..4dab4dbe4 100644 --- a/samples/21.corebot-app-insights/dialogs/cancel_and_help_dialog.py +++ b/samples/21.corebot-app-insights/dialogs/cancel_and_help_dialog.py @@ -44,11 +44,11 @@ async def interrupt(self, inner_dc: DialogContext) -> DialogTurnResult: if inner_dc.context.activity.type == ActivityTypes.message: text = inner_dc.context.activity.text.lower() - if text == "help" or text == "?": + if text in ("help", "?"): await inner_dc.context.send_activity("Show Help...") return DialogTurnResult(DialogTurnStatus.Waiting) - if text == "cancel" or text == "quit": + if text in ("cancel", "quit"): await inner_dc.context.send_activity("Cancelling") return await inner_dc.cancel_all_dialogs() diff --git a/samples/21.corebot-app-insights/dialogs/date_resolver_dialog.py b/samples/21.corebot-app-insights/dialogs/date_resolver_dialog.py index f64a27955..baa5224ac 100644 --- a/samples/21.corebot-app-insights/dialogs/date_resolver_dialog.py +++ b/samples/21.corebot-app-insights/dialogs/date_resolver_dialog.py @@ -1,6 +1,9 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. """Handle date/time resolution for booking dialog.""" + +from datatypes_date_time.timex import Timex + from botbuilder.core import MessageFactory, BotTelemetryClient, NullTelemetryClient from botbuilder.dialogs import WaterfallDialog, DialogTurnResult, WaterfallStepContext from botbuilder.dialogs.prompts import ( @@ -9,7 +12,6 @@ PromptOptions, DateTimeResolution, ) -from datatypes_date_time.timex import Timex from .cancel_and_help_dialog import CancelAndHelpDialog @@ -62,15 +64,15 @@ async def initial_step( retry_prompt=MessageFactory.text(reprompt_msg), ), ) - else: - # We have a Date we just need to check it is unambiguous. - if "definite" in Timex(timex).types: - # This is essentially a "reprompt" of the data we were given up front. - return await step_context.prompt( - DateTimePrompt.__name__, PromptOptions(prompt=reprompt_msg) - ) - else: - return await step_context.next(DateTimeResolution(timex=timex)) + + # We have a Date we just need to check it is unambiguous. + if "definite" in Timex(timex).types: + # This is essentially a "reprompt" of the data we were given up front. + return await step_context.prompt( + DateTimePrompt.__name__, PromptOptions(prompt=reprompt_msg) + ) + + return await step_context.next(DateTimeResolution(timex=timex)) async def final_step(self, step_context: WaterfallStepContext): """Cleanup - set final return value and end dialog.""" diff --git a/samples/21.corebot-app-insights/dialogs/main_dialog.py b/samples/21.corebot-app-insights/dialogs/main_dialog.py index e4807ce8a..6e70deadd 100644 --- a/samples/21.corebot-app-insights/dialogs/main_dialog.py +++ b/samples/21.corebot-app-insights/dialogs/main_dialog.py @@ -63,13 +63,13 @@ async def intro_step(self, step_context: WaterfallStepContext) -> DialogTurnResu ) return await step_context.next(None) - else: - return await step_context.prompt( - TextPrompt.__name__, - PromptOptions( - prompt=MessageFactory.text("What can I help you with today?") - ), - ) # pylint: disable=bad-continuation + + return await step_context.prompt( + TextPrompt.__name__, + PromptOptions( + prompt=MessageFactory.text("What can I help you with today?") + ), + ) async def act_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: """Use language understanding to gather details about booking.""" diff --git a/samples/21.corebot-app-insights/helpers/luis_helper.py b/samples/21.corebot-app-insights/helpers/luis_helper.py index e244940c4..81e28a032 100644 --- a/samples/21.corebot-app-insights/helpers/luis_helper.py +++ b/samples/21.corebot-app-insights/helpers/luis_helper.py @@ -63,8 +63,8 @@ async def execute_luis_query( ) if date_entities: booking_details.travel_date = ( - None - ) # Set when we get a timex format + None # Set when we get a timex format + ) except Exception as exception: print(exception) diff --git a/samples/43.complex-dialog/app.py b/samples/43.complex-dialog/app.py index 9610c3e3c..f18a309d1 100644 --- a/samples/43.complex-dialog/app.py +++ b/samples/43.complex-dialog/app.py @@ -40,9 +40,11 @@ async def on_error(context: TurnContext, error: Exception): # Send a message to the user await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") + await context.send_activity( + "To continue to run this bot, please fix the bot source code." + ) # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': + if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", @@ -50,14 +52,15 @@ async def on_error(context: TurnContext, error: Exception): timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", - value_type="https://www.botframework.com/schemas/error" + value_type="https://www.botframework.com/schemas/error", ) # Send a trace activity, which will be displayed in Bot Framework Emulator await context.send_activity(trace_activity) - + # Clear out state await CONVERSATION_STATE.delete(context) + # Set the error handler on the Adapter. # In this case, we want an unbound function, so MethodType is not needed. ADAPTER.on_turn_error = on_error diff --git a/samples/43.complex-dialog/bots/dialog_and_welcome_bot.py b/samples/43.complex-dialog/bots/dialog_and_welcome_bot.py index 2c2d91d92..68c3c9a30 100644 --- a/samples/43.complex-dialog/bots/dialog_and_welcome_bot.py +++ b/samples/43.complex-dialog/bots/dialog_and_welcome_bot.py @@ -31,7 +31,9 @@ async def on_members_added_activity( for member in members_added: # Greet anyone that was not the target (recipient) of this message. if member.id != turn_context.activity.recipient.id: - await turn_context.send_activity(MessageFactory.text( - f"Welcome to Complex Dialog Bot {member.name}. This bot provides a complex conversation, with " - f"multiple dialogs. Type anything to get started. ") + await turn_context.send_activity( + MessageFactory.text( + f"Welcome to Complex Dialog Bot {member.name}. This bot provides a complex conversation, with " + f"multiple dialogs. Type anything to get started. " + ) ) diff --git a/samples/43.complex-dialog/data_models/user_profile.py b/samples/43.complex-dialog/data_models/user_profile.py index 4ceb9a639..0267721d4 100644 --- a/samples/43.complex-dialog/data_models/user_profile.py +++ b/samples/43.complex-dialog/data_models/user_profile.py @@ -5,7 +5,9 @@ class UserProfile: - def __init__(self, name: str = None, age: int = 0, companies_to_review: List[str] = None): + def __init__( + self, name: str = None, age: int = 0, companies_to_review: List[str] = None + ): self.name: str = name self.age: int = age self.companies_to_review: List[str] = companies_to_review diff --git a/samples/43.complex-dialog/dialogs/main_dialog.py b/samples/43.complex-dialog/dialogs/main_dialog.py index 9fd04ce05..8b3fcd82d 100644 --- a/samples/43.complex-dialog/dialogs/main_dialog.py +++ b/samples/43.complex-dialog/dialogs/main_dialog.py @@ -14,32 +14,31 @@ class MainDialog(ComponentDialog): - def __init__( - self, user_state: UserState - ): + def __init__(self, user_state: UserState): super(MainDialog, self).__init__(MainDialog.__name__) self.user_state = user_state self.add_dialog(TopLevelDialog(TopLevelDialog.__name__)) self.add_dialog( - WaterfallDialog( - "WFDialog", [ - self.initial_step, - self.final_step - ] - ) + WaterfallDialog("WFDialog", [self.initial_step, self.final_step]) ) self.initial_dialog_id = "WFDialog" - async def initial_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: + async def initial_step( + self, step_context: WaterfallStepContext + ) -> DialogTurnResult: return await step_context.begin_dialog(TopLevelDialog.__name__) async def final_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: user_info: UserProfile = step_context.result - companies = "no companies" if len(user_info.companies_to_review) == 0 else " and ".join(user_info.companies_to_review) + companies = ( + "no companies" + if len(user_info.companies_to_review) == 0 + else " and ".join(user_info.companies_to_review) + ) status = f"You are signed up to review {companies}." await step_context.context.send_activity(MessageFactory.text(status)) @@ -49,4 +48,3 @@ async def final_step(self, step_context: WaterfallStepContext) -> DialogTurnResu await accessor.set(step_context.context, user_info) return await step_context.end_dialog() - diff --git a/samples/43.complex-dialog/dialogs/review_selection_dialog.py b/samples/43.complex-dialog/dialogs/review_selection_dialog.py index 1e6f0c747..2119068bb 100644 --- a/samples/43.complex-dialog/dialogs/review_selection_dialog.py +++ b/samples/43.complex-dialog/dialogs/review_selection_dialog.py @@ -3,7 +3,12 @@ from typing import List -from botbuilder.dialogs import WaterfallDialog, WaterfallStepContext, DialogTurnResult, ComponentDialog +from botbuilder.dialogs import ( + WaterfallDialog, + WaterfallStepContext, + DialogTurnResult, + ComponentDialog, +) from botbuilder.dialogs.prompts import ChoicePrompt, PromptOptions from botbuilder.dialogs.choices import Choice, FoundChoice from botbuilder.core import MessageFactory @@ -11,40 +16,49 @@ class ReviewSelectionDialog(ComponentDialog): def __init__(self, dialog_id: str = None): - super(ReviewSelectionDialog, self).__init__(dialog_id or ReviewSelectionDialog.__name__) + super(ReviewSelectionDialog, self).__init__( + dialog_id or ReviewSelectionDialog.__name__ + ) self.COMPANIES_SELECTED = "value-companiesSelected" self.DONE_OPTION = "done" - self.company_options = ["Adatum Corporation", - "Contoso Suites", - "Graphic Design Institute", - "Wide World Importers"] + self.company_options = [ + "Adatum Corporation", + "Contoso Suites", + "Graphic Design Institute", + "Wide World Importers", + ] self.add_dialog(ChoicePrompt(ChoicePrompt.__name__)) self.add_dialog( WaterfallDialog( - WaterfallDialog.__name__, [ - self.selection_step, - self.loop_step - ] + WaterfallDialog.__name__, [self.selection_step, self.loop_step] ) ) self.initial_dialog_id = WaterfallDialog.__name__ - async def selection_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: + async def selection_step( + self, step_context: WaterfallStepContext + ) -> DialogTurnResult: # step_context.options will contains the value passed in begin_dialog or replace_dialog. # if this value wasn't provided then start with an emtpy selection list. This list will # eventually be returned to the parent via end_dialog. - selected: [str] = step_context.options if step_context.options is not None else [] + selected: [ + str + ] = step_context.options if step_context.options is not None else [] step_context.values[self.COMPANIES_SELECTED] = selected if len(selected) == 0: - message = f"Please choose a company to review, or `{self.DONE_OPTION}` to finish." + message = ( + f"Please choose a company to review, or `{self.DONE_OPTION}` to finish." + ) else: - message = f"You have selected **{selected[0]}**. You can review an additional company, "\ - f"or choose `{self.DONE_OPTION}` to finish. " + message = ( + f"You have selected **{selected[0]}**. You can review an additional company, " + f"or choose `{self.DONE_OPTION}` to finish. " + ) # create a list of options to choose, with already selected items removed. options = self.company_options.copy() @@ -56,14 +70,14 @@ async def selection_step(self, step_context: WaterfallStepContext) -> DialogTurn prompt_options = PromptOptions( prompt=MessageFactory.text(message), retry_prompt=MessageFactory.text("Please choose an option from the list."), - choices=self._to_choices(options) + choices=self._to_choices(options), ) return await step_context.prompt(ChoicePrompt.__name__, prompt_options) def _to_choices(self, choices: [str]) -> List[Choice]: choice_list: List[Choice] = [] - for c in choices: - choice_list.append(Choice(value=c)) + for choice in choices: + choice_list.append(Choice(value=choice)) return choice_list async def loop_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: @@ -80,4 +94,6 @@ async def loop_step(self, step_context: WaterfallStepContext) -> DialogTurnResul return await step_context.end_dialog(selected) # Otherwise, repeat this dialog, passing in the selections from this iteration. - return await step_context.replace_dialog(ReviewSelectionDialog.__name__, selected) + return await step_context.replace_dialog( + ReviewSelectionDialog.__name__, selected + ) diff --git a/samples/43.complex-dialog/dialogs/top_level_dialog.py b/samples/43.complex-dialog/dialogs/top_level_dialog.py index 96992e080..4342e668f 100644 --- a/samples/43.complex-dialog/dialogs/top_level_dialog.py +++ b/samples/43.complex-dialog/dialogs/top_level_dialog.py @@ -6,13 +6,9 @@ WaterfallDialog, DialogTurnResult, WaterfallStepContext, - ComponentDialog -) -from botbuilder.dialogs.prompts import ( - PromptOptions, - TextPrompt, - NumberPrompt + ComponentDialog, ) +from botbuilder.dialogs.prompts import PromptOptions, TextPrompt, NumberPrompt from data_models import UserProfile from dialogs.review_selection_dialog import ReviewSelectionDialog @@ -20,9 +16,7 @@ class TopLevelDialog(ComponentDialog): def __init__(self, dialog_id: str = None): - super(TopLevelDialog, self).__init__( - dialog_id or TopLevelDialog.__name__ - ) + super(TopLevelDialog, self).__init__(dialog_id or TopLevelDialog.__name__) # Key name to store this dialogs state info in the StepContext self.USER_INFO = "value-userInfo" @@ -34,12 +28,13 @@ def __init__(self, dialog_id: str = None): self.add_dialog( WaterfallDialog( - "WFDialog", [ + "WFDialog", + [ self.name_step, self.age_step, self.start_selection_step, - self.acknowledgement_step - ] + self.acknowledgement_step, + ], ) ) @@ -66,23 +61,27 @@ async def age_step(self, step_context: WaterfallStepContext) -> DialogTurnResult ) return await step_context.prompt(NumberPrompt.__name__, prompt_options) - async def start_selection_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: + async def start_selection_step( + self, step_context: WaterfallStepContext + ) -> DialogTurnResult: # Set the user's age to what they entered in response to the age prompt. user_profile: UserProfile = step_context.values[self.USER_INFO] user_profile.age = step_context.result if user_profile.age < 25: # If they are too young, skip the review selection dialog, and pass an empty list to the next step. - await step_context.context.send_activity(MessageFactory.text( - "You must be 25 or older to participate.") + await step_context.context.send_activity( + MessageFactory.text("You must be 25 or older to participate.") ) return await step_context.next([]) - else: - # Otherwise, start the review selection dialog. - return await step_context.begin_dialog(ReviewSelectionDialog.__name__) - async def acknowledgement_step(self, step_context: WaterfallStepContext) -> DialogTurnResult: + # Otherwise, start the review selection dialog. + return await step_context.begin_dialog(ReviewSelectionDialog.__name__) + + async def acknowledgement_step( + self, step_context: WaterfallStepContext + ) -> DialogTurnResult: # Set the user's company selection to what they entered in the review-selection dialog. user_profile: UserProfile = step_context.values[self.USER_INFO] user_profile.companies_to_review = step_context.result diff --git a/samples/44.prompt-users-for-input/app.py b/samples/44.prompt-users-for-input/app.py index 79b861b59..34633b1fe 100644 --- a/samples/44.prompt-users-for-input/app.py +++ b/samples/44.prompt-users-for-input/app.py @@ -38,9 +38,11 @@ async def on_error(context: TurnContext, error: Exception): # Send a message to the user await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") + await context.send_activity( + "To continue to run this bot, please fix the bot source code." + ) # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': + if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", @@ -48,14 +50,15 @@ async def on_error(context: TurnContext, error: Exception): timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", - value_type="https://www.botframework.com/schemas/error" + value_type="https://www.botframework.com/schemas/error", ) # Send a trace activity, which will be displayed in Bot Framework Emulator await context.send_activity(trace_activity) - + # Clear out state await CONVERSATION_STATE.delete(context) + # Set the error handler on the Adapter. # In this case, we want an unbound method, so MethodType is not needed. ADAPTER.on_turn_error = on_error diff --git a/samples/44.prompt-users-for-input/bots/custom_prompt_bot.py b/samples/44.prompt-users-for-input/bots/custom_prompt_bot.py index 67cecfc54..693eee92a 100644 --- a/samples/44.prompt-users-for-input/bots/custom_prompt_bot.py +++ b/samples/44.prompt-users-for-input/bots/custom_prompt_bot.py @@ -3,15 +3,24 @@ from datetime import datetime -from botbuilder.core import ActivityHandler, ConversationState, TurnContext, UserState, MessageFactory from recognizers_number import recognize_number, Culture from recognizers_date_time import recognize_datetime +from botbuilder.core import ( + ActivityHandler, + ConversationState, + TurnContext, + UserState, + MessageFactory, +) + from data_models import ConversationFlow, Question, UserProfile class ValidationResult: - def __init__(self, is_valid: bool = False, value: object = None, message: str = None): + def __init__( + self, is_valid: bool = False, value: object = None, message: str = None + ): self.is_valid = is_valid self.value = value self.message = message @@ -45,57 +54,84 @@ async def on_message_activity(self, turn_context: TurnContext): await self.conversation_state.save_changes(turn_context) await self.user_state.save_changes(turn_context) - async def _fill_out_user_profile(self, flow: ConversationFlow, profile: UserProfile, turn_context: TurnContext): + async def _fill_out_user_profile( + self, flow: ConversationFlow, profile: UserProfile, turn_context: TurnContext + ): user_input = turn_context.activity.text.strip() # ask for name if flow.last_question_asked == Question.NONE: - await turn_context.send_activity(MessageFactory.text("Let's get started. What is your name?")) + await turn_context.send_activity( + MessageFactory.text("Let's get started. What is your name?") + ) flow.last_question_asked = Question.NAME # validate name then ask for age elif flow.last_question_asked == Question.NAME: validate_result = self._validate_name(user_input) if not validate_result.is_valid: - await turn_context.send_activity(MessageFactory.text(validate_result.message)) + await turn_context.send_activity( + MessageFactory.text(validate_result.message) + ) else: profile.name = validate_result.value - await turn_context.send_activity(MessageFactory.text(f"Hi {profile.name}")) - await turn_context.send_activity(MessageFactory.text("How old are you?")) + await turn_context.send_activity( + MessageFactory.text(f"Hi {profile.name}") + ) + await turn_context.send_activity( + MessageFactory.text("How old are you?") + ) flow.last_question_asked = Question.AGE # validate age then ask for date elif flow.last_question_asked == Question.AGE: validate_result = self._validate_age(user_input) if not validate_result.is_valid: - await turn_context.send_activity(MessageFactory.text(validate_result.message)) + await turn_context.send_activity( + MessageFactory.text(validate_result.message) + ) else: profile.age = validate_result.value - await turn_context.send_activity(MessageFactory.text(f"I have your age as {profile.age}.")) - await turn_context.send_activity(MessageFactory.text("When is your flight?")) + await turn_context.send_activity( + MessageFactory.text(f"I have your age as {profile.age}.") + ) + await turn_context.send_activity( + MessageFactory.text("When is your flight?") + ) flow.last_question_asked = Question.DATE # validate date and wrap it up elif flow.last_question_asked == Question.DATE: validate_result = self._validate_date(user_input) if not validate_result.is_valid: - await turn_context.send_activity(MessageFactory.text(validate_result.message)) + await turn_context.send_activity( + MessageFactory.text(validate_result.message) + ) else: profile.date = validate_result.value - await turn_context.send_activity(MessageFactory.text( - f"Your cab ride to the airport is scheduled for {profile.date}.") + await turn_context.send_activity( + MessageFactory.text( + f"Your cab ride to the airport is scheduled for {profile.date}." + ) + ) + await turn_context.send_activity( + MessageFactory.text( + f"Thanks for completing the booking {profile.name}." + ) ) - await turn_context.send_activity(MessageFactory.text( - f"Thanks for completing the booking {profile.name}.") + await turn_context.send_activity( + MessageFactory.text("Type anything to run the bot again.") ) - await turn_context.send_activity(MessageFactory.text("Type anything to run the bot again.")) flow.last_question_asked = Question.NONE def _validate_name(self, user_input: str) -> ValidationResult: if not user_input: - return ValidationResult(is_valid=False, message="Please enter a name that contains at least one character.") - else: - return ValidationResult(is_valid=True, value=user_input) + return ValidationResult( + is_valid=False, + message="Please enter a name that contains at least one character.", + ) + + return ValidationResult(is_valid=True, value=user_input) def _validate_age(self, user_input: str) -> ValidationResult: # Attempt to convert the Recognizer result to an integer. This works for "a dozen", "twelve", "12", and so on. @@ -107,7 +143,9 @@ def _validate_age(self, user_input: str) -> ValidationResult: if 18 <= age <= 120: return ValidationResult(is_valid=True, value=age) - return ValidationResult(is_valid=False, message="Please enter an age between 18 and 120.") + return ValidationResult( + is_valid=False, message="Please enter an age between 18 and 120." + ) def _validate_date(self, user_input: str) -> ValidationResult: try: @@ -125,16 +163,27 @@ def _validate_date(self, user_input: str) -> ValidationResult: candidate = datetime.strptime(value, "%Y-%m-%d") elif resolution["type"] == "time": candidate = datetime.strptime(value, "%H:%M:%S") - candidate = candidate.replace(year=now.year, month=now.month, day=now.day) + candidate = candidate.replace( + year=now.year, month=now.month, day=now.day + ) else: candidate = datetime.strptime(value, "%Y-%m-%d %H:%M:%S") # user response must be more than an hour out diff = candidate - now if diff.total_seconds() >= 3600: - return ValidationResult(is_valid=True, value=candidate.strftime("%m/%d/%y @ %H:%M")) - - return ValidationResult(is_valid=False, message="I'm sorry, please enter a date at least an hour out.") + return ValidationResult( + is_valid=True, + value=candidate.strftime("%m/%d/%y @ %H:%M"), + ) + + return ValidationResult( + is_valid=False, + message="I'm sorry, please enter a date at least an hour out.", + ) except ValueError: - return ValidationResult(is_valid=False, message="I'm sorry, I could not interpret that as an appropriate " - "date. Please enter a date at least an hour out.") + return ValidationResult( + is_valid=False, + message="I'm sorry, I could not interpret that as an appropriate " + "date. Please enter a date at least an hour out.", + ) diff --git a/samples/44.prompt-users-for-input/data_models/conversation_flow.py b/samples/44.prompt-users-for-input/data_models/conversation_flow.py index f40732419..f848db64f 100644 --- a/samples/44.prompt-users-for-input/data_models/conversation_flow.py +++ b/samples/44.prompt-users-for-input/data_models/conversation_flow.py @@ -13,7 +13,6 @@ class Question(Enum): class ConversationFlow: def __init__( - self, - last_question_asked: Question = Question.NONE, + self, last_question_asked: Question = Question.NONE, ): self.last_question_asked = last_question_asked diff --git a/samples/47.inspection/app.py b/samples/47.inspection/app.py index 4e4bef778..c699450c5 100644 --- a/samples/47.inspection/app.py +++ b/samples/47.inspection/app.py @@ -4,20 +4,20 @@ import asyncio import sys from datetime import datetime -from types import MethodType -from botbuilder.core.inspection import InspectionMiddleware, InspectionState -from botframework.connector.auth import MicrosoftAppCredentials from flask import Flask, request, Response + from botbuilder.core import ( BotFrameworkAdapter, BotFrameworkAdapterSettings, ConversationState, MemoryStorage, TurnContext, - UserState, + UserState ) +from botbuilder.core.inspection import InspectionMiddleware, InspectionState from botbuilder.schema import Activity, ActivityTypes +from botframework.connector.auth import MicrosoftAppCredentials from bots import EchoBot @@ -41,9 +41,11 @@ async def on_error(context: TurnContext, error: Exception): # Send a message to the user await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") + await context.send_activity( + "To continue to run this bot, please fix the bot source code." + ) # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': + if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", @@ -51,14 +53,15 @@ async def on_error(context: TurnContext, error: Exception): timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", - value_type="https://www.botframework.com/schemas/error" + value_type="https://www.botframework.com/schemas/error", ) # Send a trace activity, which will be displayed in Bot Framework Emulator await context.send_activity(trace_activity) - + # Clear out state await CONVERSATION_STATE.delete(context) + # Set the error handler on the Adapter. # In this case, we want an unbound method, so MethodType is not needed. ADAPTER.on_turn_error = on_error @@ -74,9 +77,8 @@ async def on_error(context: TurnContext, error: Exception): user_state=USER_STATE, conversation_state=CONVERSATION_STATE, credentials=MicrosoftAppCredentials( - app_id=APP.config["APP_ID"], - password=APP.config["APP_PASSWORD"] - ) + app_id=APP.config["APP_ID"], password=APP.config["APP_PASSWORD"] + ), ) ADAPTER.use(INSPECTION_MIDDLEWARE) diff --git a/samples/47.inspection/bots/echo_bot.py b/samples/47.inspection/bots/echo_bot.py index fe4d8d099..21a99aa9d 100644 --- a/samples/47.inspection/bots/echo_bot.py +++ b/samples/47.inspection/bots/echo_bot.py @@ -1,7 +1,13 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -from botbuilder.core import ActivityHandler, ConversationState, TurnContext, UserState, MessageFactory +from botbuilder.core import ( + ActivityHandler, + ConversationState, + TurnContext, + UserState, + MessageFactory, +) from botbuilder.schema import ChannelAccount from data_models import CustomState @@ -21,7 +27,9 @@ def __init__(self, conversation_state: ConversationState, user_state: UserState) self.conversation_state = conversation_state self.user_state = user_state - self.conversation_state_accessor = self.conversation_state.create_property("CustomState") + self.conversation_state_accessor = self.conversation_state.create_property( + "CustomState" + ) self.user_state_accessor = self.user_state.create_property("CustomState") async def on_turn(self, turn_context: TurnContext): @@ -30,7 +38,9 @@ async def on_turn(self, turn_context: TurnContext): await self.conversation_state.save_changes(turn_context) await self.user_state.save_changes(turn_context) - async def on_members_added_activity(self, members_added: [ChannelAccount], turn_context: TurnContext): + async def on_members_added_activity( + self, members_added: [ChannelAccount], turn_context: TurnContext + ): for member in members_added: if member.id != turn_context.activity.recipient.id: await turn_context.send_activity("Hello and welcome!") @@ -38,13 +48,17 @@ async def on_members_added_activity(self, members_added: [ChannelAccount], turn_ async def on_message_activity(self, turn_context: TurnContext): # Get the state properties from the turn context. user_data = await self.user_state_accessor.get(turn_context, CustomState) - conversation_data = await self.conversation_state_accessor.get(turn_context, CustomState) + conversation_data = await self.conversation_state_accessor.get( + turn_context, CustomState + ) - await turn_context.send_activity(MessageFactory.text( - f"Echo: {turn_context.activity.text}, " - f"conversation state: {conversation_data.value}, " - f"user state: {user_data.value}")) + await turn_context.send_activity( + MessageFactory.text( + f"Echo: {turn_context.activity.text}, " + f"conversation state: {conversation_data.value}, " + f"user state: {user_data.value}" + ) + ) user_data.value = user_data.value + 1 conversation_data.value = conversation_data.value + 1 -