Repository: microsoft/botbuilder-python

Issue:
[PORT] add typing activity to activityhandler
> Port this change from botbuilder-dotnet/master branch:
https://github.com/microsoft/botbuilder-dotnet/pull/3384




# Changed projects
* Microsoft.Bot.Builder
* Microsoft.Bot.Builder.Tests






Discussion:

Resolving patch:
diff --git a/libraries/botbuilder-core/botbuilder/core/activity_handler.py b/libraries/botbuilder-core/botbuilder/core/activity_handler.py
--- a/libraries/botbuilder-core/botbuilder/core/activity_handler.py
+++ b/libraries/botbuilder-core/botbuilder/core/activity_handler.py
@@ -80,6 +80,8 @@ async def on_turn(self, turn_context: TurnContext):
                 )
         elif turn_context.activity.type == ActivityTypes.end_of_conversation:
             await self.on_end_of_conversation_activity(turn_context)
+        elif turn_context.activity.type == ActivityTypes.typing:
+            await self.on_typing_activity(turn_context)
         else:
             await self.on_unrecognized_activity_type(turn_context)
 
@@ -346,6 +348,19 @@ async def on_end_of_conversation_activity(  # pylint: disable=unused-argument
         """
         return
 
+    async def on_typing_activity(  # pylint: disable=unused-argument
+        self, turn_context: TurnContext
+    ):
+        """
+        Override this in a derived class to provide logic specific to
+        ActivityTypes.typing activities, such as the conversational logic.
+
+        :param turn_context: The context object for this turn
+        :type turn_context: :class:`botbuilder.core.TurnContext`
+        :returns: A task that represents the work queued to execute
+        """
+        return
+
     async def on_unrecognized_activity_type(  # pylint: disable=unused-argument
         self, turn_context: TurnContext
     ):


Test patch:
diff --git a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py
--- a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py
+++ b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py
@@ -57,6 +57,14 @@ async def on_event(self, turn_context: TurnContext):
         self.record.append("on_event")
         return await super().on_event(turn_context)
 
+    async def on_end_of_conversation_activity(self, turn_context: TurnContext):
+        self.record.append("on_end_of_conversation_activity")
+        return await super().on_end_of_conversation_activity(turn_context)
+
+    async def on_typing_activity(self, turn_context: TurnContext):
+        self.record.append("on_typing_activity")
+        return await super().on_typing_activity(turn_context)
+
     async def on_unrecognized_activity_type(self, turn_context: TurnContext):
         self.record.append("on_unrecognized_activity_type")
         return await super().on_unrecognized_activity_type(turn_context)
@@ -724,3 +732,27 @@ async def test_on_teams_task_module_submit(self):
         assert len(bot.record) == 2
         assert bot.record[0] == "on_invoke_activity"
         assert bot.record[1] == "on_teams_task_module_submit"
+
+    async def test_on_end_of_conversation_activity(self):
+        activity = Activity(type=ActivityTypes.end_of_conversation)
+
+        turn_context = TurnContext(SimpleAdapter(), activity)
+
+        # Act
+        bot = TestingTeamsActivityHandler()
+        await bot.on_turn(turn_context)
+
+        assert len(bot.record) == 1
+        assert bot.record[0] == "on_end_of_conversation_activity"
+
+    async def test_typing_activity(self):
+        activity = Activity(type=ActivityTypes.typing)
+
+        turn_context = TurnContext(SimpleAdapter(), activity)
+
+        # Act
+        bot = TestingTeamsActivityHandler()
+        await bot.on_turn(turn_context)
+
+        assert len(bot.record) == 1
+        assert bot.record[0] == "on_typing_activity"
diff --git a/libraries/botbuilder-core/tests/test_activity_handler.py b/libraries/botbuilder-core/tests/test_activity_handler.py
--- a/libraries/botbuilder-core/tests/test_activity_handler.py
+++ b/libraries/botbuilder-core/tests/test_activity_handler.py
@@ -59,6 +59,14 @@ async def on_event(self, turn_context: TurnContext):
         self.record.append("on_event")
         return await super().on_event(turn_context)
 
+    async def on_end_of_conversation_activity(self, turn_context: TurnContext):
+        self.record.append("on_end_of_conversation_activity")
+        return await super().on_end_of_conversation_activity(turn_context)
+
+    async def on_typing_activity(self, turn_context: TurnContext):
+        self.record.append("on_typing_activity")
+        return await super().on_typing_activity(turn_context)
+
     async def on_unrecognized_activity_type(self, turn_context: TurnContext):
         self.record.append("on_unrecognized_activity_type")
         return await super().on_unrecognized_activity_type(turn_context)
@@ -172,3 +180,29 @@ async def test_invoke_should_not_match(self):
         assert len(bot.record) == 1
         assert bot.record[0] == "on_invoke_activity"
         assert adapter.activity.value.status == int(HTTPStatus.NOT_IMPLEMENTED)
+
+    async def test_on_end_of_conversation_activity(self):
+        activity = Activity(type=ActivityTypes.end_of_conversation)
+
+        adapter = TestInvokeAdapter()
+        turn_context = TurnContext(adapter, activity)
+
+        # Act
+        bot = TestingActivityHandler()
+        await bot.on_turn(turn_context)
+
+        assert len(bot.record) == 1
+        assert bot.record[0] == "on_end_of_conversation_activity"
+
+    async def test_typing_activity(self):
+        activity = Activity(type=ActivityTypes.typing)
+
+        adapter = TestInvokeAdapter()
+        turn_context = TurnContext(adapter, activity)
+
+        # Act
+        bot = TestingActivityHandler()
+        await bot.on_turn(turn_context)
+
+        assert len(bot.record) == 1
+        assert bot.record[0] == "on_typing_activity"