Repository: microsoft/botbuilder-python

Issue:
date_resolver_dialog - test of "definite"
## Version SDK v4.5.0b3
in botbuilder-python/samples/13.core-bot/dialogs/date_resolver_dialog.py

## Describe the bug
Line : _if "definite" in Timex(timex).types:_
The goal of this line is to treat ambiguous date such as timex date = XXXX-05-17
so the test must be "not in" instead of "in" ("definite" = type for an unambiguous date)

[bug]



Discussion:
Hmm, it looks like the behavior in the Python version of CoreBot is different from the behavior of what happens in C# and JS versions.

I'll need to investigate further on why the discrepancy occurs though
___
For the line that you pointed out in question, for it the bot actually ventures down the if statement checking for for definite inside date resolver dialog if you:
* start the dialog with an ambiguous date
* answer with the "to" and "from" locations in the next prompts asking for flight cities
* it should then detect that the initial date was given in the first utterance, and that that utterance is ambiguous, and send that "reprompt" given in date resolver dialog

### Example of Behavior in JS/C#
![image](https://user-images.githubusercontent.com/35248895/62894201-254e0d80-bd01-11e9-9843-5c531aafd027.png)

### Example of Behavior in Python
![image](https://user-images.githubusercontent.com/35248895/62894299-52022500-bd01-11e9-933f-543861a55777.png)
Notice above it doesn't seem to detect that a date was initially given, nor does it reprompt, _even when changing the if statement you pointed out to use `not in`_
I tried changing where the `not` was placed "just in case" it made a difference, but it doesn't.
![image](https://user-images.githubusercontent.com/35248895/62894498-a3aaaf80-bd01-11e9-8625-9ee499695ec0.png)

Running in debugger mode, I myself can't seem to get it to hit that if statement--seems to end that dialog before it would even reach it maybe?

Investigating further...
Ah ok, looks like it never hits LN 59 `if "definite" not in Timex(timex).types` in `date_resolver_dialog.py`, because the `step_context.options` is `None`, and therefore always will hit LN 52 `if timex is None` prompt  and never gets to LN 59.

I'll dig to see why this is, so we can finally hit LN 59 and ensure the changes produce the behavior expected
Ok, dug down and figured out why the sample bot is breaking on entities.

`MainDialog` calls `LuisHelper.execute_luis_query` to get `intent` and `result`

* If you take a look at `luis_helper.py`, you can see that the `execute_luis_query` method does indeed return `intent` & `result`. 
* Separately, we have the raw LUIS result that came from calling LUIS endpoint to predict intent, saved in `recognizer_result`. 
* The issue is **we never save any of the parsed entity values specifically for datetime from `recognizer_result` to `result` that gets returned, so therefore all the datetime travel_date value in `result` that `MainDialog` has is`None`**

Fixing the above issue first, then can actually hit the `if "definite" not in Timex(timex).type` statement originally reported.

Resolving patch:
diff --git a/samples/13.core-bot/dialogs/date_resolver_dialog.py b/samples/13.core-bot/dialogs/date_resolver_dialog.py
--- a/samples/13.core-bot/dialogs/date_resolver_dialog.py
+++ b/samples/13.core-bot/dialogs/date_resolver_dialog.py
@@ -56,7 +56,7 @@ async def initial_step(
                 PromptOptions(prompt=prompt_msg, retry_prompt=reprompt_msg),
             )
         # We have a Date we just need to check it is unambiguous.
-        if "definite" in Timex(timex).types:
+        if "definite" not 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)
diff --git a/samples/13.core-bot/dialogs/main_dialog.py b/samples/13.core-bot/dialogs/main_dialog.py
--- a/samples/13.core-bot/dialogs/main_dialog.py
+++ b/samples/13.core-bot/dialogs/main_dialog.py
@@ -1,17 +1,13 @@
 # Copyright (c) Microsoft Corporation. All rights reserved.
 # Licensed under the MIT License.
 
-from datetime import datetime
-from typing import Dict
 from botbuilder.dialogs import (
     ComponentDialog,
-    DialogSet,
-    DialogTurnStatus,
     WaterfallDialog,
     WaterfallStepContext,
     DialogTurnResult,
 )
-from botbuilder.dialogs.prompts import TextPrompt, ConfirmPrompt, PromptOptions
+from botbuilder.dialogs.prompts import TextPrompt, PromptOptions
 from botbuilder.core import MessageFactory, TurnContext
 from botbuilder.schema import InputHints
 
@@ -76,9 +72,8 @@ async def act_step(self, step_context: WaterfallStepContext) -> DialogTurnResult
             self._luis_recognizer, step_context.context
         )
 
-        # top_intent = cognitive_models_helper.top_intent(luis_result['intents'])
-
         if intent == Intent.BOOK_FLIGHT.value and luis_result:
+            # Show a warning for Origin and Destination if we can't resolve them.
             await MainDialog._show_warning_for_unsupported_cities(
                 step_context.context, luis_result
             )
diff --git a/samples/13.core-bot/helpers/luis_helper.py b/samples/13.core-bot/helpers/luis_helper.py
--- a/samples/13.core-bot/helpers/luis_helper.py
+++ b/samples/13.core-bot/helpers/luis_helper.py
@@ -2,7 +2,7 @@
 # Licensed under the MIT License.
 from enum import Enum
 from typing import Dict
-from botbuilder.ai.luis import LuisRecognizer, LuisApplication
+from botbuilder.ai.luis import LuisRecognizer
 from botbuilder.core import IntentScore, TopIntent, TurnContext
 
 from booking_details import BookingDetails
@@ -32,6 +32,9 @@ class LuisHelper:
     async def execute_luis_query(
         luis_recognizer: LuisRecognizer, turn_context: TurnContext
     ) -> (Intent, object):
+        """
+        Returns an object with preformatted LUIS results for the bot's dialogs to consume.
+        """
         result = None
         intent = None
 
@@ -78,13 +81,20 @@ async def execute_luis_query(
                             from_entities[0]["text"].capitalize()
                         )
 
-                # TODO: This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the Time part.
+                # 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("$instance", {}).get(
-                    "datetime", []
-                )
-                if len(date_entities) > 0:
-                    result.travel_date = None  # TODO: Set when we get a timex format
+                date_entities = recognizer_result.entities.get("datetime", [])
+                if date_entities:
+                    timex = date_entities[0]["timex"]
+
+                    if timex:
+                        datetime = timex[0].split("T")[0]
+
+                        result.travel_date = datetime
+
+                else:
+                    result.travel_date = None
+
         except Exception as e:
             print(e)
 


Test patch: