8000 Added on_turn_error functionality to bot_adapter with updates to all … · zigri2612/botbuilder-python@d3b2634 · GitHub < 8000 link rel="icon" class="js-site-favicon" type="image/svg+xml" href="https://github.githubassets.com/favicons/favicon.svg" data-base-href="https://github.githubassets.com/favicons/favicon">
[go: up one dir, main page]

Skip to content

Commit d3b2634

Browse files
committed
Added on_turn_error functionality to bot_adapter with updates to all related samples, ported bot assert and added some missing annotations.
1 parent c41dd5a commit d3b2634

File tree

8 files changed

+140
-9
lines changed

8 files changed

+140
-9
lines changed

libraries/botbuilder-core/botbuilder/core/bot_adapter.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,18 @@
22
# Licensed under the MIT License.
33

44
from abc import ABC, abstractmethod
5-
from typing import List, Callable
5+
from typing import List, Callable, Awaitable
66
from botbuilder.schema import Activity, ConversationReference
77

8+
from .bot_assert import BotAssert
89
from .turn_context import TurnContext
910
from .middleware_set import MiddlewareSet
1011

1112

1213
class BotAdapter(ABC):
13-
def __init__(self):
14+
def __init__(self, on_turn_error: Callable = None):
1415
self._middleware = MiddlewareSet()
16+
self.on_turn_error = on_turn_error
1517

1618
@abstractmethod
1719
async def send_activities(self, context: TurnContext, activities: List[Activity]):
@@ -48,12 +50,25 @@ def use(self, middleware):
4850
"""
4951
self._middleware.use(middleware)
5052

51-
async def run_middleware(self, context: TurnContext, callback: Callable=None):
53+
async def run_middleware(self, context: TurnContext, callback: Callable[[TurnContext], Awaitable]= None):
5254
"""
5355
Called by the parent class to run the adapters middleware set and calls the passed in `callback()` handler at
5456
the end of the chain.
5557
:param context:
5658
:param callback:
5759
:return:
5860
"""
59-
return await self._middleware.receive_activity_with_status(context, callback)
61+
BotAssert.context_not_none(context)
62+
63+
if context.activity is not None:
64+
try:
65+
return await self._middleware.receive_activity_with_status(context, callback)
66+
except Exception as error:
67+
if self.on_turn_error is not None:
68+
await self.on_turn_error(context, error)
69+
else:
70+
raise error
71+
else:
72+
# callback to caller on proactive case
73+
if callback is not None:
74+
await callback(context)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from typing import List
2+
3+
from botbuilder.schema import Activity, ConversationReference
4+
from .middleware_set import Middleware
5+
from .turn_context import TurnContext
6+
7+
class BotAssert():
8+
9+
@staticmethod
10+
def activity_not_none(activity: Activity) -> None:
11+
"""
12+
Checks that an activity object is not None
13+
:param activity: The activity object
14+
"""
15+
if (activity is None):
16+
raise TypeError(activity.__class__.__name__)
17+
18+
@staticmethod
19+
def context_not_none(turn_context: TurnContext) -> None:
20+
"""
21+
Checks that a context object is not None
22+
:param turn_context: The context object
23+
"""
24+
if (turn_context is None):
25+
raise TypeError(turn_context.__class__.__name__)
26+
27+
@staticmethod
28+
def conversation_reference_not_none(reference: ConversationReference) -> None:
29+
"""
30+
Checks that a conversation reference object is not None
31+
:param reference: The conversation reference object
32+
"""
33+
if (reference is None):
34+
raise TypeError(reference.__class__.__name__)
35+
36+
@staticmethod
37+
def activity_list_not_none(activities: List[Activity]) -> None:
38+
"""
39+
Checks that an activity list is not None
40+
:param activities: The activity list
41+
"""
42+
if (activities is None):
43+
raise TypeError(activities.__class__.__name__)
44+
45+
@staticmethod
46+
def middleware_not_none(middleware: Middleware) -> None:
47+
"""
48+
Checks that a middleware object is not None
49+
:param middleware: The middleware object
50+
"""
51+
if (middleware is None):
52+
raise TypeError(middleware.__class__.__name__)
53+
54+
@staticmethod
55+
def middleware_list_not_none(middleware: List[Middleware]) -> None:
56+
"""
57+
Checks that a middeware list is not None
58+
:param activities: The middleware list
59+
"""
60+
if (middleware is None):
61+
raise TypeError(middleware.__class__.__name__)
62+
63+

libraries/botbuilder-core/botbuilder/core/bot_framework_adapter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Licensed under the MIT License.
33

44
import asyncio
5-
from typing import List, Callable
5+
from typing import List, Callable, Awaitable
66
from botbuilder.schema import (Activity, ChannelAccount,
77
ConversationAccount,
88
ConversationParameters, ConversationReference,
@@ -46,7 +46,7 @@ async def continue_conversation(self, reference: ConversationReference, logic):
4646
context = self.create_context(request)
4747
return await self.run_middleware(context, logic)
4848

49-
async def create_conversation(self, reference: ConversationReference, logic):
49+
async def create_conversation(self, reference: ConversationReference, logic: Callable[[TurnContext], Awaitable]=None):
5050
"""
5151
Starts a new conversation with a user. This is typically used to Direct Message (DM) a member
5252
of a group.

libraries/botbuilder-core/botbuilder/core/middleware_set.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from asyncio import iscoroutinefunction
55
from abc import ABC, abstractmethod
6+
from typing import Awaitable, Callable
67

78
from .turn_context import TurnContext
89

@@ -48,14 +49,14 @@ def use(self, *middleware: Middleware):
4849
async def receive_activity(self, context: TurnContext):
4950
await self.receive_activity_internal(context, None)
5051

51-
async def on_process_request(self, context, logic):
52+
async def on_process_request(self, context: TurnContext, logic: Callable[[TurnContext], Awaitable]):
5253
await self.receive_activity_internal(context, None)
5354
await logic()
5455

55-
async def receive_activity_with_status(self, context: TurnContext, callback):
56+
async def receive_activity_with_status(self, context: TurnContext, callback: Callable[[TurnContext], Awaitable]):
5657
return await self.receive_activity_internal(context, callback)
5758

58-
async def receive_activity_internal(self, context, callback, next_middleware_index=0):
59+
async def receive_activity_internal(self, context: TurnContext, callback: Callable[[TurnContext], Awaitable], next_middleware_index: int = 0):
5960
if next_middleware_index == len(self._middleware):
6061
if callback:
6162
return await callback(context)

samples/Core-Bot/main.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@
2525
SETTINGS = BotFrameworkAdapterSettings(cfg['Settings']['AppId'], cfg['Settings']['AppPassword'])
2626
ADAPTER = BotFrameworkAdapter(SETTINGS)
2727

28+
# Catch-all for errors.
29+
async def on_error(context: TurnContext, error: Exception):
30+
# This check writes out errors to console log
31+
# NOTE: In production environment, you should consider logging this to Azure
32+
# application insights.
33+
print(f'\n [on_turn_error]: { error }')
34+
# Send a message to the user
35+
await context.send_activity('Oops. Something went wrong!')
36+
# Clear out state
37+
await conversation_state.delete(context)
38+
39+
ADAPTER.on_turn_error = on_error
40+
2841
# Create MemoryStorage, UserState and ConversationState
2942
memory = MemoryStorage()
3043

samples/Rich-Cards-Bot/main.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@
2424
SETTINGS = BotFrameworkAdapterSettings(cfg['Settings']['AppId'], cfg['Settings']['AppPassword'])
2525
ADAPTER = BotFrameworkAdapter(SETTINGS)
2626

27+
# Catch-all for errors.
28+
async def on_error(context: TurnContext, error: Exception):
29+
# This check writes out errors to console log
30+
# NOTE: In production environment, you should consider logging this to Azure
31+
# application insights.
32+
print(f'\n [on_turn_error]: { error }')
33+
# Send a message to the user
34+
await context.send_activity('Oops. Something went wrong!')
35+
# Clear out state
36+
await conversation_state.delete(context)
37+
38+
ADAPTER.on_turn_error = on_error
39+
2740
# Create MemoryStorage, UserState and ConversationState
2841
memory = MemoryStorage()
2942

samples/State-Management-Bot/main.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,19 @@
2323
SETTINGS = BotFrameworkAdapterSettings(cfg['Settings']['AppId'], cfg['Settings']['AppPassword'])
2424
ADAPTER = BotFrameworkAdapter(SETTINGS)
2525

26+
# Catch-all for errors.
27+
async def on_error(context: TurnContext, error: Exception):
28+
# This check writes out errors to console log
29+
# NOTE: In production environment, you should consider logging this to Azure
30+
# application insights.
31+
print(f'\n [on_turn_error]: { error }')
32+
# Send a message to the user
33+
await context.send_activity('Oops. Something went wrong!')
34+
# Clear out state
35+
await conversation_state.delete(context)
36+
37+
ADAPTER.on_turn_error = on_error
38+
2639
# Create MemoryStorage, UserState and ConversationState
2740
memory = MemoryStorage()
2841

samples/python-flask/13.core-bot/main.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@
2929
SETTINGS = BotFrameworkAdapterSettings(app.config['APP_ID'], app.config['APP_PASSWORD'])
3030
ADAPTER = BotFrameworkAdapter(SETTINGS)
3131

32+
# Catch-all for errors.
33+
async def on_error(context: TurnContext, error: Exception):
34+
# This check writes out errors to console log
35+
# NOTE: In production environment, you should consider logging this to Azure
36+
# application insights.
37+
print(f'\n [on_turn_error]: { error }')
38+
# Send a message to the user
39+
await context.send_activity('Oops. Something went wrong!')
40+
# Clear out state
41+
await conversation_state.delete(context)
42+
43+
ADAPTER.on_turn_error = on_error
44+
3245
# Create MemoryStorage, UserState and ConversationState
3346
memory = MemoryStorage()
3447

0 commit comments

Comments
 (0)
0