Repository: microsoft/botbuilder-python

Issue:
test_inspection_middleware fails on Python 3.6.8
Test: test_should_replicate_activity_data_to_listening_emulator_following_open_and_attach_with_at_mention

This test passes on 3.7.6 and 3.8.1


Discussion:

Resolving patch:
diff --git a/libraries/botbuilder-core/botbuilder/core/re_escape.py b/libraries/botbuilder-core/botbuilder/core/re_escape.py
new file mode 100644
--- /dev/null
+++ b/libraries/botbuilder-core/botbuilder/core/re_escape.py
@@ -0,0 +1,25 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+# SPECIAL_CHARS
+# closing ')', '}' and ']'
+# '-' (a range in character set)
+# '&', '~', (extended character set operations)
+# '#' (comment) and WHITESPACE (ignored) in verbose mode
+SPECIAL_CHARS_MAP = {i: "\\" + chr(i) for i in b"()[]{}?*+-|^$\\.&~# \t\n\r\v\f"}
+
+
+def escape(pattern):
+    """
+    Escape special characters in a string.
+
+    This is a copy of the re.escape function in Python 3.8.  This was done
+    because the 3.6.x version didn't escape in the same way and handling
+    bot names with regex characters in it would fail in TurnContext.remove_mention_text
+    without escaping the text.
+    """
+    if isinstance(pattern, str):
+        return pattern.translate(SPECIAL_CHARS_MAP)
+
+    pattern = str(pattern, "latin1")
+    return pattern.translate(SPECIAL_CHARS_MAP).encode("latin1")
diff --git a/libraries/botbuilder-core/botbuilder/core/turn_context.py b/libraries/botbuilder-core/botbuilder/core/turn_context.py
--- a/libraries/botbuilder-core/botbuilder/core/turn_context.py
+++ b/libraries/botbuilder-core/botbuilder/core/turn_context.py
@@ -13,6 +13,7 @@
     Mention,
     ResourceResponse,
 )
+from .re_escape import escape
 
 
 class TurnContext:
@@ -362,7 +363,7 @@ def remove_mention_text(activity: Activity, identifier: str) -> str:
             if mention.additional_properties["mentioned"]["id"] == identifier:
                 mention_name_match = re.match(
                     r"<at(.*)>(.*?)<\/at>",
-                    re.escape(mention.additional_properties["text"]),
+                    escape(mention.additional_properties["text"]),
                     re.IGNORECASE,
                 )
                 if mention_name_match:


Test patch:
diff --git a/libraries/botbuilder-core/tests/test_turn_context.py b/libraries/botbuilder-core/tests/test_turn_context.py
--- a/libraries/botbuilder-core/tests/test_turn_context.py
+++ b/libraries/botbuilder-core/tests/test_turn_context.py
@@ -322,8 +322,8 @@ def test_should_remove_at_mention_from_activity(self):
 
         text = TurnContext.remove_recipient_mention(activity)
 
-        assert text, " test activity"
-        assert activity.text, " test activity"
+        assert text == " test activity"
+        assert activity.text == " test activity"
 
     def test_should_remove_at_mention_with_regex_characters(self):
         activity = Activity(
@@ -343,8 +343,8 @@ def test_should_remove_at_mention_with_regex_characters(self):
 
         text = TurnContext.remove_recipient_mention(activity)
 
-        assert text, " test activity"
-        assert activity.text, " test activity"
+        assert text == " test activity"
+        assert activity.text == " test activity"
 
     async def test_should_send_a_trace_activity(self):
         context = TurnContext(SimpleAdapter(), ACTIVITY)