From 80043f835e87c6ce5301f82567bb12302efe23e5 Mon Sep 17 00:00:00 2001 From: Matt Klaber Date: Fri, 26 Aug 2022 19:11:13 +0100 Subject: [PATCH 1/9] feat: `ShouldAsk` for `Echo` and `Acknowledge` * Create an abstract class from which `Echo` and `Acknowledge` inherit * Add `should_ask` optional parameters * Only display a message if `should_ask` is `None` or `True` --- columbo/_interaction.py | 98 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 12 deletions(-) diff --git a/columbo/_interaction.py b/columbo/_interaction.py index 91797be6..ca57c904 100644 --- a/columbo/_interaction.py +++ b/columbo/_interaction.py @@ -19,7 +19,7 @@ Validator, ) -Interaction = Union["Echo", "Acknowledge", "Question"] +Interaction = Union["Displayable", "Question"] # Used by copy() implementations. Since some arguments can be None, None can't be used as the value to indicate that the @@ -39,60 +39,133 @@ def _or_default(value, default: T) -> T: return default if isinstance(value, _Sentinel) else value -class Echo: - """Display a message to the user.""" +class Displayable(ABC): + """ + Base class for a message to the user that is displayed. + """ - def __init__(self, message: StaticOrDynamicValue[str]) -> None: + def __init__( + self, + message: StaticOrDynamicValue[str], + should_ask: Optional[ShouldAsk] = None + ) -> None: """ Initialize an instance. :param message: The message to be displayed to the user. If the value is callable, the argument passed in will be the answers that have been provided this far. + :param should_ask: If `None`, the message is displayed to the user. Otherwise, the callable will be passed the + answers that have been provided this far and should return `True` if the message should be displayed. """ self._message = message + self._should_ask = should_ask + + @abstractmethod + def display(self, answers: Answers) -> None: + pass + + def should_ask(self, answers: Answers) -> bool: + """ + Should the user be displayed this message. + + :param answers: The answers that have been provided this far. + :return: `True` if this message should be displayed + """ + if self._should_ask is None: + return True + if callable(self._should_ask): + return self._should_ask(answers) + raise ValueError(f"Invalid value for should_ask: {self._should_ask}") + + +class Echo(Displayable): + """Display a message to the user.""" + + def __init__( + self, + message: StaticOrDynamicValue[str], + should_ask: Optional[ShouldAsk] = None + ) -> None: + """ + Initialize an instance. + + :param message: The message to be displayed to the user. If the value is callable, the argument passed in will + be the answers that have been provided this far. + :param should_ask: If `None`, the message is displayed to the user. Otherwise, the callable will be passed the + answers that have been provided this far and should return `True` if the message should be displayed. + """ + super().__init__( + message, + should_ask + ) def display(self, answers: Answers) -> None: user_io.echo(to_value(self._message, answers, str)) def copy( - self, *, message: Possible[StaticOrDynamicValue[str]] = _NOT_GIVEN + self, + *, + message: Possible[StaticOrDynamicValue[str]] = _NOT_GIVEN, + should_ask: Possible[Optional[ShouldAsk]] = _NOT_GIVEN, ) -> "Echo": """ Create a new instance like this one, potentially with different values. :param message: The message to be displayed to the user. If the value is callable, the argument passed in will be the answers that have been provided this far. + :param should_ask: If `None`, the message is displayed. Otherwise, the callable will be passed the answers that + have been provided this far and should return `True` if the message should be displayed. :return: A newly constructed instance with the given values in place of the values of this instance. """ - return Echo(_or_default(message, self._message)) + return Echo( + _or_default(message, self._message), + should_ask=_or_default(should_ask, self._should_ask), + ) -class Acknowledge: + +class Acknowledge(Displayable): """Display a message to the user and require the user to press ENTER to continue.""" - def __init__(self, message: StaticOrDynamicValue[str]) -> None: + def __init__( self, + message: StaticOrDynamicValue[str], + should_ask: Optional[ShouldAsk] = None + ) -> None: """ Initialize an instance. :param message: The message to be displayed to the user. If the value is callable, the argument passed in will be the answers that have been provided this far. + :param should_ask: If `None`, the message is displayed to the user. Otherwise, the callable will be passed the + answers that have been provided this far and should return `True` if the message should be displayed. """ - self._message = message + super().__init__( + message, + should_ask + ) def display(self, answers: Answers) -> None: user_io.acknowledge(to_value(self._message, answers, str)) def copy( - self, *, message: Possible[StaticOrDynamicValue[str]] = _NOT_GIVEN + self, + *, + message: Possible[StaticOrDynamicValue[str]] = _NOT_GIVEN, + should_ask: Possible[Optional[ShouldAsk]] = _NOT_GIVEN, ) -> "Acknowledge": """ Create a new instance like this one, potentially with different values. :param message: The message to be displayed to the user. If the value is callable, the argument passed in will be the answers that have been provided this far. + :param should_ask: If `None`, the message is displayed. Otherwise, the callable will be passed the answers that + have been provided this far and should return `True` if the message should be displayed. :return: A newly constructed instance with the given values in place of the values of this instance. """ - return Acknowledge(_or_default(message, self._message)) + return Acknowledge( + _or_default(message, self._message), + should_ask=_or_default(should_ask, self._should_ask), + ) class Question(ABC): @@ -556,7 +629,8 @@ def get_answers( for interaction in interactions: if isinstance(interaction, (Echo, Acknowledge)): - interaction.display(result) + if interaction.should_ask(result): + interaction.display(result) elif isinstance(interaction, (Confirm, Choice, BasicQuestion)): if interaction.should_ask(result): result[interaction.name] = interaction.ask(result, no_user_input) From 691d7be9535213cd9c508b42d3c4d427108bc480 Mon Sep 17 00:00:00 2001 From: Matt Klaber Date: Sun, 28 Aug 2022 10:14:32 +0100 Subject: [PATCH 2/9] chore: Linting change --- columbo/_interaction.py | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/columbo/_interaction.py b/columbo/_interaction.py index ca57c904..a0fa4cd7 100644 --- a/columbo/_interaction.py +++ b/columbo/_interaction.py @@ -45,10 +45,8 @@ class Displayable(ABC): """ def __init__( - self, - message: StaticOrDynamicValue[str], - should_ask: Optional[ShouldAsk] = None - ) -> None: + self, message: StaticOrDynamicValue[str], should_ask: Optional[ShouldAsk] = None + ) -> None: """ Initialize an instance. @@ -82,10 +80,8 @@ class Echo(Displayable): """Display a message to the user.""" def __init__( - self, - message: StaticOrDynamicValue[str], - should_ask: Optional[ShouldAsk] = None - ) -> None: + self, message: StaticOrDynamicValue[str], should_ask: Optional[ShouldAsk] = None + ) -> None: """ Initialize an instance. @@ -94,10 +90,7 @@ def __init__( :param should_ask: If `None`, the message is displayed to the user. Otherwise, the callable will be passed the answers that have been provided this far and should return `True` if the message should be displayed. """ - super().__init__( - message, - should_ask - ) + super().__init__(message, should_ask) def display(self, answers: Answers) -> None: user_io.echo(to_value(self._message, answers, str)) @@ -123,14 +116,12 @@ def copy( ) - class Acknowledge(Displayable): """Display a message to the user and require the user to press ENTER to continue.""" - def __init__( self, - message: StaticOrDynamicValue[str], - should_ask: Optional[ShouldAsk] = None - ) -> None: + def __init__( + self, message: StaticOrDynamicValue[str], should_ask: Optional[ShouldAsk] = None + ) -> None: """ Initialize an instance. @@ -139,10 +130,7 @@ def __init__( self, :param should_ask: If `None`, the message is displayed to the user. Otherwise, the callable will be passed the answers that have been provided this far and should return `True` if the message should be displayed. """ - super().__init__( - message, - should_ask - ) + super().__init__(message, should_ask) def display(self, answers: Answers) -> None: user_io.acknowledge(to_value(self._message, answers, str)) From e0bbb4b819edc64d803ed861af67fd2b73db2dbb Mon Sep 17 00:00:00 2001 From: Matt Klaber Date: Sun, 28 Aug 2022 10:15:02 +0100 Subject: [PATCH 3/9] test: Test `Displayable` and new `should_ask` --- tests/interaction_test.py | 46 ++++++++++++++++++++++++++++++++++----- tests/sample_data.py | 16 ++++++++++++++ 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/tests/interaction_test.py b/tests/interaction_test.py index 3c2ca214..d885dd4b 100644 --- a/tests/interaction_test.py +++ b/tests/interaction_test.py @@ -24,6 +24,7 @@ SOME_OPTIONS, SOME_OTHER_BOOL, SOME_STRING, + SampleDisplayable, SampleQuestion, some_dynamic_bool, some_dynamic_default, @@ -450,6 +451,25 @@ def test_should_ask__invalid_type__exception(): ) +@pytest.mark.parametrize( + "description,should_ask,expected_result", + [("not set", None, True), ("dynamic", some_dynamic_bool, SOME_OTHER_BOOL)], +) +def test_displayable_should_ask__expected_result( + should_ask, expected_result, description +): + result = SampleDisplayable(SOME_STRING, should_ask=should_ask).should_ask( + SOME_ANSWERS + ) + + assert result == expected_result, description + + +def test_displayable_should_ask__invalid_type__exception(): + with pytest.raises(ValueError): + SampleDisplayable(SOME_STRING, should_ask=object()).should_ask(SOME_ANSWERS) + + def test_get_answers__unknown_interaction_provided(): """ An unsupported interaction type should raise a ValueError @@ -461,18 +481,30 @@ def test_get_answers__unknown_interaction_provided(): @pytest.mark.parametrize( - ["basic_question_should_ask", "expected_basic_question_ask_call_count"], - [(True, 1), (False, 0)], + [ + "basic_question_should_ask", + "expected_basic_question_ask_call_count", + "echo_should_ask", + "expected_echo_display_call_count", + ], + [(True, 1, False, 0), (False, 0, True, 1)], ) def test_get_answers__proper_funcs_called( - mocker, basic_question_should_ask, expected_basic_question_ask_call_count + mocker, + basic_question_should_ask, + expected_basic_question_ask_call_count, + echo_should_ask, + expected_echo_display_call_count, ): """ Given a list of interactions of different types, validate the proper funcs should be invoked on each - The parametrization asserts that Question interactions are only 'asked' when they should be asked + The parametrization asserts that Question interactions are only 'asked' when they should be asked and + that Displayable interactions are only 'displayed' when they should be displayed. """ - echo_interaction_mock = mocker.Mock(spec=Echo) + echo_interaction_mock = mocker.Mock( + spec=Echo, should_ask=mocker.Mock(return_value=echo_should_ask) + ) basic_question_interaction_mock = mocker.Mock( spec=BasicQuestion, should_ask=mocker.Mock(return_value=basic_question_should_ask), @@ -486,7 +518,9 @@ def test_get_answers__proper_funcs_called( # functions belonging to interactions should be invoked # in the case of a question, it either should or shouldn't be asked - echo_interaction_mock.display.assert_called_once() + # in the case of echo, it either should or shouldn't be displayed + echo_interaction_mock.should_ask.assert_called_once() + assert echo_interaction_mock.display.call_count == expected_echo_display_call_count basic_question_interaction_mock.should_ask.assert_called_once() assert ( basic_question_interaction_mock.ask.call_count diff --git a/tests/sample_data.py b/tests/sample_data.py index 7003c814..93bbb3e3 100644 --- a/tests/sample_data.py +++ b/tests/sample_data.py @@ -4,6 +4,7 @@ BasicQuestion, Choice, Confirm, + Displayable, Question, canonical_arg_name, ) @@ -53,6 +54,21 @@ def ask(self, answers, no_user_input=False): raise Exception("Don't call") +class SampleDisplayable(Displayable): + """Displayable for testing base class functionality""" + + def __init__(self, message, should_ask=None): + super().__init__(message, should_ask) + self._display_called = False + + def display(self, answers): + self._display_called = True + + @property + def display_called(self) -> bool: + return self._display_called + + # combination of questions that reuse the same name DUPLICATE_QUESTION_NAME_PARAMS = [ [ From 992517140e6e4b86d5e98cbf97de3f768ca35458 Mon Sep 17 00:00:00 2001 From: Matt Klaber Date: Sun, 28 Aug 2022 10:16:37 +0100 Subject: [PATCH 4/9] docs: Document should_ask in display interactions --- CHANGELOG.md | 3 ++- docs/examples/branching_story.py | 14 ++++++++++---- docs/examples/optional_questions.py | 4 ++++ .../optional_questions_with_value_if_not_asked.py | 4 ++++ docs/index.md | 1 + docs/usage-guide/interactions.md | 8 +++++++- .../optional-questions-and-branching.md | 14 +++++++++----- 7 files changed, 37 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e24c8019..32490ba6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.12.0] - 2022-08-27 ### Added - Python version `3.10` tested during CI - Python version `3.10` added to package classifiers +- `should_ask` kwarg for `Echo` and `Acknowledge` interactions ([#356](https://github.com/wayfair-incubator/columbo/issues/356)) ### Removed diff --git a/docs/examples/branching_story.py b/docs/examples/branching_story.py index 0c351240..c7e550e4 100644 --- a/docs/examples/branching_story.py +++ b/docs/examples/branching_story.py @@ -33,18 +33,24 @@ def outcome(answers: columbo.Answers) -> str: options=["left", "right"], default="left", ), + columbo.Echo( + "You step into a short hallway and the door closes behind you, refusing to open again. " + "As you walk down the hallway, there is a small side table with a key on it.", + should_ask=went_left, + ), columbo.Confirm( "has_key", - "You step into a short hallway and the door closes behind you, refusing to open again. " - "As you walk down the hallway, there is a small side table with a key on it.\n" "Do you pick up the key before going through the door at the other end?", should_ask=went_left, default=True, ), + columbo.Echo( + "You step into smaller room and the door closes behind, refusing to open again. " + "The room has a single door on the opposite side of the room and a work bench with a hammer on it.", + should_ask=went_right, + ), columbo.Confirm( "has_hammer", - "You step into smaller room and the door closes behind, refusing to open again. " - "The room has a single door on the opposite side of the room and a work bench with a hammer on it.\n" "Do you pick up the hammer before going through the door at the other side?", should_ask=went_right, default=True, diff --git a/docs/examples/optional_questions.py b/docs/examples/optional_questions.py index 903dc8b4..9455aeb3 100644 --- a/docs/examples/optional_questions.py +++ b/docs/examples/optional_questions.py @@ -7,6 +7,10 @@ def user_has_dog(answers: columbo.Answers) -> bool: interactions = [ columbo.Confirm("has_dog", "Do you have a dog?", default=True), + columbo.Echo( + "Because you have have a dog, we want to ask you some more questions.", + should_ask=user_has_dog, + ), columbo.BasicQuestion( "dog_name", "What is the name of the dog?", diff --git a/docs/examples/optional_questions_with_value_if_not_asked.py b/docs/examples/optional_questions_with_value_if_not_asked.py index aa89b40f..d65d206f 100644 --- a/docs/examples/optional_questions_with_value_if_not_asked.py +++ b/docs/examples/optional_questions_with_value_if_not_asked.py @@ -7,6 +7,10 @@ def user_has_dog(answers: columbo.Answers) -> bool: interactions = [ columbo.Confirm("has_dog", "Do you have a dog?", default=True), + columbo.Echo( + "Because you have have a dog, we want to ask you some more questions.", + should_ask=user_has_dog, + ), columbo.BasicQuestion( "dog_name", "What is the name of the dog?", diff --git a/docs/index.md b/docs/index.md index 5ecfc136..a703a200 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,6 +18,7 @@ * As part of the text of a question * As part of the text of a default value * To decide if a question should be skipped + * To decide if a message should be displayed * Accept answers from the command line in addition to prompting the user. ## Example diff --git a/docs/usage-guide/interactions.md b/docs/usage-guide/interactions.md index 291c43b0..0bccf731 100644 --- a/docs/usage-guide/interactions.md +++ b/docs/usage-guide/interactions.md @@ -15,7 +15,13 @@ ### Echo & Acknowledge -`Echo` and `Acknowledge` both accept `message` as their only argument. This is the message to be displayed to the user. +`Echo` and `Acknowledge` both accept the following arguments. + +* `message`: The message to be displayed to the user. +* `should_ask`: Optional. When given, the argument should be a function that accepts an `Answers` dictionary and returns + `True` or `False`. Returning `True` indicates that the message should be displayed. Returning `False` will skip the + message and not present it to the user. See [Optional Questions & Branching][optional-questions] for more details. + ### All Questions diff --git a/docs/usage-guide/optional-questions-and-branching.md b/docs/usage-guide/optional-questions-and-branching.md index da641f1f..e32fb591 100644 --- a/docs/usage-guide/optional-questions-and-branching.md +++ b/docs/usage-guide/optional-questions-and-branching.md @@ -1,8 +1,11 @@ -## Only Asking Some Questions +## Only Prompting Some Interactions -There are situations where a question should be asked some times, but not all the time. For example, a program that collects -information about a user's pets should not ask the user for the dog's name and breed if the user said they do not have a -dog. The `should_ask` argument that is present on each question provides a way to achieve this functionality. +There are situations where a question should be asked some times, but not all the time. Or, a message should be displayed some times. +For example, a program that collects information about a user's +pets should not ask the user for the dog's name and breed if the +user said they do not have a dog. If the user has a dog, the program +may want to display a special message. The `should_ask` argument that +is present on each interaction provides a way to achieve this functionality. Similarly, `should_ask` can be used to provide branching paths to the user. An example of these branching paths is a [Choose Your Own Adventure][choose-your-own-adventure] story. The story provides the reader with choices during the @@ -16,7 +19,8 @@ adventure. These choices introduce diverging paths of interactions that may or m ### Optional Questions The following is a basic example that has two optional questions that are not asked based on the answer to the first -question. +question. It also has an optional "echo" that is only displayed +based on the answer to the first question. ```python {!examples/optional_questions.py!} From 1ba1e40701e5f056e1bf942c5e7365ebd34af638 Mon Sep 17 00:00:00 2001 From: Matt Klaber Date: Sun, 28 Aug 2022 10:23:31 +0100 Subject: [PATCH 5/9] chore: Add `#pragma: no cover` to abstract methods --- columbo/_interaction.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/columbo/_interaction.py b/columbo/_interaction.py index a0fa4cd7..80d4fb02 100644 --- a/columbo/_interaction.py +++ b/columbo/_interaction.py @@ -59,7 +59,7 @@ def __init__( self._should_ask = should_ask @abstractmethod - def display(self, answers: Answers) -> None: + def display(self, answers: Answers) -> None: # pragma: no cover pass def should_ask(self, answers: Answers) -> bool: @@ -201,7 +201,9 @@ def cli_help(self) -> Optional[str]: return self._cli_help @abstractmethod - def ask(self, answers: Answers, no_user_input: bool = False) -> Answer: + def ask( + self, answers: Answers, no_user_input: bool = False + ) -> Answer: # pragma: no cover """ Prompt the user with this question. From 25c1c9ee8efb5aec34d1284ff406860b6fa3a697 Mon Sep 17 00:00:00 2001 From: Matt Klaber Date: Sun, 28 Aug 2022 15:11:12 +0100 Subject: [PATCH 6/9] chore: Unversion changelog and minor edits --- CHANGELOG.md | 2 +- CONTRIBUTING.md | 6 +++--- columbo/__init__.py | 1 + columbo/_interaction.py | 20 ++++++++++---------- docs/index.md | 7 +++---- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32490ba6..e9cbf16a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.12.0] - 2022-08-27 +## [Unreleased] ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fe7b803a..8b6c54c9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,8 +6,8 @@ Please note we have a [code of conduct](CODE_OF_CONDUCT.md), please follow it in ## Pull Request Process -1. Ensure the CI pipeline and all checks are passing. -2. Update documentation with details of changes. -3. Add an entry to the [change log](CHANGELOG.md). +1. Ensure the CI pipeline and all checks are passing +2. Update documentation with details of changes +3. Add an entry to the [change log](CHANGELOG.md) using `[Unreleased]` as the version header 4. You may merge the Pull Request in once it has approvals of two other developers. If you do not have permission to do that, you may request the second reviewer to merge it for you. diff --git a/columbo/__init__.py b/columbo/__init__.py index e587e87c..32e1387c 100644 --- a/columbo/__init__.py +++ b/columbo/__init__.py @@ -10,6 +10,7 @@ BasicQuestion, Choice, Confirm, + Displayable, Echo, Interaction, Question, diff --git a/columbo/_interaction.py b/columbo/_interaction.py index 80d4fb02..2df2f607 100644 --- a/columbo/_interaction.py +++ b/columbo/_interaction.py @@ -39,6 +39,14 @@ def _or_default(value, default: T) -> T: return default if isinstance(value, _Sentinel) else value +def _should_ask_or_display(should_ask: Optional[ShouldAsk], answers: Answers) -> bool: + if should_ask is None: + return True + if callable(should_ask): + return should_ask(answers) + raise ValueError(f"Invalid value for should_ask: {should_ask}") + + class Displayable(ABC): """ Base class for a message to the user that is displayed. @@ -69,11 +77,7 @@ def should_ask(self, answers: Answers) -> bool: :param answers: The answers that have been provided this far. :return: `True` if this message should be displayed """ - if self._should_ask is None: - return True - if callable(self._should_ask): - return self._should_ask(answers) - raise ValueError(f"Invalid value for should_ask: {self._should_ask}") + return _should_ask_or_display(self._should_ask, answers) class Echo(Displayable): @@ -221,11 +225,7 @@ def should_ask(self, answers: Answers) -> bool: :param answers: The answers that have been provided this far. :return: `True` if this questions should be asked """ - if self._should_ask is None: - return True - if callable(self._should_ask): - return self._should_ask(answers) - raise ValueError(f"Invalid value for should_ask: {self._should_ask}") + return _should_ask_or_display(self._should_ask, answers) class Confirm(Question): diff --git a/docs/index.md b/docs/index.md index a703a200..4d1a08fd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -13,13 +13,12 @@ * Yes or No * Multiple choice * Open-ended -* Validate the response provided by the user. +* Validate the response provided by the user * Use answers from earlier questions: * As part of the text of a question * As part of the text of a default value - * To decide if a question should be skipped - * To decide if a message should be displayed -* Accept answers from the command line in addition to prompting the user. + * To decide if a question should be skipped or a message should be displayed +* Accept answers from the command line in addition to prompting the user ## Example From 7502934551ec6ee3e914f840c79023816483910f Mon Sep 17 00:00:00 2001 From: Matt Klaber Date: Mon, 29 Aug 2022 14:15:55 +0100 Subject: [PATCH 7/9] chore: Revert contributing clarification --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8b6c54c9..fe7b803a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,8 +6,8 @@ Please note we have a [code of conduct](CODE_OF_CONDUCT.md), please follow it in ## Pull Request Process -1. Ensure the CI pipeline and all checks are passing -2. Update documentation with details of changes -3. Add an entry to the [change log](CHANGELOG.md) using `[Unreleased]` as the version header +1. Ensure the CI pipeline and all checks are passing. +2. Update documentation with details of changes. +3. Add an entry to the [change log](CHANGELOG.md). 4. You may merge the Pull Request in once it has approvals of two other developers. If you do not have permission to do that, you may request the second reviewer to merge it for you. From ffb4a25ec2d26024ae05facfe212e2776abfa33a Mon Sep 17 00:00:00 2001 From: Matt Klaber Date: Mon, 29 Aug 2022 14:18:44 +0100 Subject: [PATCH 8/9] docs: Improve optional echo doc --- docs/usage-guide/optional-questions-and-branching.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/usage-guide/optional-questions-and-branching.md b/docs/usage-guide/optional-questions-and-branching.md index e32fb591..2689ca47 100644 --- a/docs/usage-guide/optional-questions-and-branching.md +++ b/docs/usage-guide/optional-questions-and-branching.md @@ -19,8 +19,7 @@ adventure. These choices introduce diverging paths of interactions that may or m ### Optional Questions The following is a basic example that has two optional questions that are not asked based on the answer to the first -question. It also has an optional "echo" that is only displayed -based on the answer to the first question. +question. It also has an optional message that is only displayed based on the answer to the first question. ```python {!examples/optional_questions.py!} From 4ede22cc569116874b5ab18aed50da63f2f75c8c Mon Sep 17 00:00:00 2001 From: Matt Klaber <939816+mklaber@users.noreply.github.com> Date: Fri, 2 Sep 2022 17:12:34 +0100 Subject: [PATCH 9/9] chore: Update CHANGELOG.md Co-authored-by: Patrick Lannigan --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9cbf16a..b2abb982 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Python version `3.10` tested during CI - Python version `3.10` added to package classifiers -- `should_ask` kwarg for `Echo` and `Acknowledge` interactions ([#356](https://github.com/wayfair-incubator/columbo/issues/356)) +- `should_ask` keyword argument for `Echo` and `Acknowledge` interactions ([#356](https://github.com/wayfair-incubator/columbo/issues/356)) ### Removed