Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate examples used in documentation #115

Merged
merged 14 commits into from
Mar 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,15 @@ jobs:
with:
package-import-name: "columbo"

validate-doc-examples:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2

- name: Validate docs
run: ./docker/validate_docs.sh

fhightower marked this conversation as resolved.
Show resolved Hide resolved
build-docs:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
Expand Down
5 changes: 5 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ services:
<<: *devbox
command: docker/run_tests.sh --format-code

# test the documentation examples to make sure they can be run with Python
validateDocExamples:
<<: *devbox
command: docker/validate_docs.sh

fhightower marked this conversation as resolved.
Show resolved Hide resolved
bump:
<<: *devbox
<<: *mount-app-and-user-git-config
Expand Down
4 changes: 2 additions & 2 deletions docker/run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ echo "Running MyPy..."
mypy columbo tests

echo "Running black..."
black ${BLACK_ACTION} columbo tests
black ${BLACK_ACTION} columbo tests docs/examples/

echo "Running iSort..."
isort ${ISORT_ACTION} columbo tests
isort ${ISORT_ACTION} columbo tests docs/examples/
fhightower marked this conversation as resolved.
Show resolved Hide resolved

echo "Running flake8..."
flake8 columbo tests
Expand Down
16 changes: 16 additions & 0 deletions docker/validate_docs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# this script will exit if one of the example files does not execute properly with python

# this is set so that the script fails if one example fails to be executed properly
set -e

# install columbo
pip install . -q;

for filename in docs/examples/*.py; do
# provide default answers if example python file asks for input
yes "" | python ${filename};
done

# this will only get printed if all examples finish succesfully
printf "\n\n\nAll of the documentation examples can be run!";
fhightower marked this conversation as resolved.
Show resolved Hide resolved
19 changes: 17 additions & 2 deletions docs/development-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ coverage rather than decreasing it.

We use [pytest][pytest-docs] as our testing framework.

#### Stages
### Stages
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something seemed odd with the level of the headings in this document (on this line and this one). I've made a best-guess at what they should be.


To customize / override a specific testing stage, please read the documentation specific to that tool:

Expand All @@ -73,7 +73,22 @@ To customize / override a specific testing stage, please read the documentation
4. [Flake8][flake8-docs]
5. [Bandit][bandit-docs]

### `setup.py`
## Validate Examples Used in Documentation

In the `docs/examples/` directory of this repo, there are example Python scripts which we use in our documentation.
You can validate that the examples run properly using:

```bash
docker-compose run --rm validateDocExamples
```

If the script fails (exits with a non-zero status), it will output information about the file that we need to fix.

Note that this script will output some content in the shell every time it runs.
Just because the script outputs content to the shell does *not* mean it has failed;
as long as the script finishes successfully (exits with a zero status), there are no problems we need to address.

## `setup.py`

Setuptools is used to packaging the library.

Expand Down
5 changes: 5 additions & 0 deletions docs/examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Examples

These are the examples used in the [documentation][documentation].

[documentation]: https://wayfair-incubator.github.io/columbo/
11 changes: 7 additions & 4 deletions examples/branching_story.py → docs/examples/branching_story.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import columbo


fhightower marked this conversation as resolved.
Show resolved Hide resolved
def went_left(answers: columbo.Answers) -> bool:
return answers["which_door"] == "left"


def went_right(answers: columbo.Answers) -> bool:
return answers["which_door"] == "right"


def outcome(answers: columbo.Answers) -> str:
if answers.get("has_key", False):
return "You try the the key on the lock. With a little jiggling, it finally opens. You open the gate and leave."
Expand All @@ -15,7 +18,7 @@ def outcome(answers: columbo.Answers) -> str:
"Unable to open the gate yourself, you yell for help. A farmer in the nearby field hears you. "
"He reaches into his pocket and pulls out a key to unlock the gate and open it. "
"As you walk through the archway he says, "
"\"What I don't understand is how you got in there. This is the only key.\""
'"What I don\'t understand is how you got in there. This is the only key."'
)


Expand All @@ -28,23 +31,23 @@ def outcome(answers: columbo.Answers) -> str:
"which_door",
"Which door do you walk through?",
options=["left", "right"],
default="left"
default="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
default=True,
),
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
default=True,
),
columbo.Echo(
"You enter a small courtyard with high walls. There is an archway that would allow you to go free, "
Expand Down
33 changes: 33 additions & 0 deletions docs/examples/index_command_line_answers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import columbo

interactions = [
columbo.Echo("Welcome to the Columbo example"),
columbo.Acknowledge("Press enter to start"),
columbo.BasicQuestion(
"user",
"What is your name?",
default="Patrick",
),
columbo.BasicQuestion(
"user_email",
lambda answers: f"""What email address should be used to contact {answers["user"]}?""",
default="[email protected]",
),
columbo.Choice(
"mood",
"How are you feeling today?",
options=["happy", "sad", "sleepy", "confused"],
default="happy",
),
columbo.Confirm("likes_dogs", "Do you like dogs?", default=True),
]

answers = columbo.parse_args(
interactions,
args=[
"--user-email",
"[email protected]",
"--likes-dogs",
],
)
print(answers)
26 changes: 26 additions & 0 deletions docs/examples/index_user_prompts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import columbo

interactions = [
columbo.Echo("Welcome to the Columbo example"),
columbo.Acknowledge("Press enter to start"),
columbo.BasicQuestion(
"user",
"What is your name?",
default="Patrick",
),
columbo.BasicQuestion(
"user_email",
lambda answers: f"""What email address should be used to contact {answers["user"]}?""",
default="[email protected]",
),
columbo.Choice(
"mood",
"How are you feeling today?",
options=["happy", "sad", "sleepy", "confused"],
default="happy",
),
columbo.Confirm("likes_dogs", "Do you like dogs?", default=True),
]

answers = columbo.get_answers(interactions)
print(answers)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import columbo


def does_user_have_a_dog(answers: columbo.Answers) -> bool:
def user_has_dog(answers: columbo.Answers) -> bool:
return answers["has_dog"]


Expand All @@ -10,15 +10,15 @@ def does_user_have_a_dog(answers: columbo.Answers) -> bool:
columbo.BasicQuestion(
"dog_name",
"What is the name of the dog?",
should_ask=does_user_have_a_dog,
default="Kaylee"
should_ask=user_has_dog,
default="Kaylee",
),
columbo.BasicQuestion(
"dog_breed",
"What is the breed of the dog?",
should_ask=does_user_have_a_dog,
default="Basset Hound"
)
should_ask=user_has_dog,
default="Basset Hound",
),
]

user_answers = columbo.get_answers(interactions)
Expand Down
25 changes: 25 additions & 0 deletions docs/examples/validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import re
from typing import List

import columbo


def is_email_address(value: str, _: columbo.Answers) -> columbo.ValidationResponse:
if not re.match(r"^\w+@\w+", value):
error_message = f"{value} is not a valid email address"
return columbo.ValidationFailure(error=error_message)

return columbo.ValidationSuccess()


interactions: List[columbo.Interaction] = [
columbo.BasicQuestion(
"user_email_address",
"What email address should be used to contact you?",
default="[email protected]",
validator=is_email_address,
)
]

user_answers = columbo.get_answers(interactions)
print(user_answers)
61 changes: 2 additions & 59 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,34 +79,7 @@ printed next.
This is the example that appears on the [main page][docs-main] of the documentation.

```python linenums="1"
import columbo

interactions = [
columbo.Echo("Welcome to the Columbo example"),
columbo.Acknowledge(
"Press enter to start"
),
columbo.BasicQuestion(
"user",
"What is your name?",
default="Patrick",
),
columbo.BasicQuestion(
"user_email",
lambda answers: f"""What email address should be used to contact {answers["user"]}?""",
default="[email protected]"
),
columbo.Choice(
"mood",
"How are you feeling today?",
options=["happy", "sad", "sleepy", "confused"],
default="happy",
),
columbo.Confirm("likes_dogs", "Do you like dogs?", default=True),
]

answers = columbo.get_answers(interactions)
print(answers)
{!examples/index_user_prompts.py!}
```

* Line 1: Import the `columbo` module.
Expand Down Expand Up @@ -152,37 +125,7 @@ print(answers)
<summary>The full example</summary>

```python linenums="1" hl_lines="27-30"
import columbo

interactions = [
columbo.Echo("Welcome to the Columbo example"),
columbo.Acknowledge(
"Press enter to start"
),
columbo.BasicQuestion(
"user",
"What is your name?",
default="Patrick",
),
columbo.BasicQuestion(
"user_email",
lambda answers: f"""What email address should be used to contact {answers["user"]}?""",
default="[email protected]"
),
columbo.Choice(
"mood",
"How are you feeling today?",
options=["happy", "sad", "sleepy", "confused"],
default="happy",
),
columbo.Confirm("likes_dogs", "Do you like dogs?", default=True),
]

answers = columbo.parse_args(interactions, args=[
"--user-email", "[email protected]",
"--likes-dogs",
])
print(answers)
{!examples/index_command_line_answers.py!}
```
</details>

Expand Down
Loading