Python Forum
Conditionals, while loops, continue, break (PyBite 102)
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Conditionals, while loops, continue, break (PyBite 102)
#1
Hello Pythonistas!

I’m practicing my while loops whilst using conditionals and the .lower() class method. The material I am working with provides a script with an empty function and a separate test script. I feel like I have completed the requirements but when using pytest, it passes only one test and fails four others. This is my first time using pytest and I don’t fully understand the output. I’ve made some adjustments based on the pytest output but my script still fails.

I think I’ve completed the task so I don’t understand why it is failing the pytest.

Here is the original task:

Quote:https://codechalleng.es/bites/102/

In this Bite we'll get you to take user input using the input builtin and see if it matches items within a list.

In the while loop ask the user to enter a color and capture that input.

Check to see whether they've entered 'quit'. If so, print bye and exit (break) the loop, effectively ending the function.

If not, check to see whether the color (input) is in the VALID_COLORS color list. If it is, then print the color in lower case. If not, print Not a valid color and continue the loop.

As you want to ask the user over and over again till they quit, you can use an infinite while loop. We already provided that in the template code, just code inside that loop.

Here is my (what I think to be the fully completed) script:

VALID_COLORS = ['blue', 'yellow', 'red']


def print_colors():
    """
    In the while loop ask the user to enter a color, lowercase it and store it in a variable. Next check: 
       - if 'quit' was entered for color, print 'bye' and break. 
       - if the color is not in VALID_COLORS, print 'Not a valid color' and continue.
       - otherwise print the color in lower case.
    """
    while True:
        chosen_color = input("What color do you choose?")
        low_chosen_color = chosen_color.lower()
        if low_chosen_color == "quit":
            print("bye")
            break
        elif low_chosen_color not in VALID_COLORS:
            print("Not a valid color")
            print("bye")
            continue
        elif low_chosen_color in VALID_COLORS:
            print(f"{low_chosen_color}")
            print("bye")
        pass
Here are the contents of the provided test script:

from unittest.mock import patch
from colors2 import print_colors

NOT_VALID = 'Not a valid color'


def call_print_colors():
    # some people prefer sys.exit instead of break
    try:
        print_colors()
    except SystemExit:
        pass


@patch("builtins.input", side_effect=['quit'])
def test_straight_quit(input_mock, capsys):
    # user only enter quit, program prints bye and breaks loop
    call_print_colors()
    actual = capsys.readouterr()[0].strip()
    expected = 'bye'
    assert actual == expected


@patch("builtins.input", side_effect=['blue', 'quit'])
def test_one_valid_color_then_quit(input_mock, capsys):
    # user enters blue = valid color so print it
    # then user enters quit so break out of loop = end program
    call_print_colors()
    actual = capsys.readouterr()[0].strip()
    expected = 'blue\nbye'
    assert actual == expected


@patch("builtins.input", side_effect=['green', 'quit'])
def test_one_invalid_color_then_quit(input_mock, capsys):
    # user enters green which is not in VALID_COLORS so continue the loop,
    # user then enters quit so loop breaks (end function / program)
    call_print_colors()
    actual = capsys.readouterr()[0].strip()
    expected = f'{NOT_VALID}\nbye'
    assert actual == expected


@patch("builtins.input", side_effect=['white', 'red', 'quit'])
def test_invalid_then_valid_color_then_quit(nput_mock, capsys):
    # white is not a valid color so continue the loop,
    # then user enters red which is valid so print it, then quit
    call_print_colors()
    actual = capsys.readouterr()[0].strip()
    expected = f'{NOT_VALID}\nred\nbye'
    assert actual == expected


@patch("builtins.input", side_effect=['yellow', 'orange', 'quit'])
def test_valid_then_invalid_color_then_quit(input_mock, capsys):
    # yellow is a valid color so print it, user then enters orange
    # which is not a valid color so continue loop, lastly user
    # enters quit so exit loop = reaching end function / program
    call_print_colors()
    actual = capsys.readouterr()[0].strip()
    expected = f'yellow\n{NOT_VALID}\nbye'
    assert actual == expected
Here is the actual output showing multiple failures:

› bpython -m pytest test_colors.py
================================= test session starts ==================================
platform linux -- Python 3.8.2, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: /home/<user>/dev/projects/python/2018-and-2020/bitesofpy/Intro-freebies/Bite 102 - Infinite loop, input, continue and break
collected 5 items                                                                      

test_colors.py .FFFF                                                             [100%]

======================================= FAILURES =======================================
____________________________ test_one_valid_color_then_quit ____________________________

input_mock = <MagicMock name='input' id='140425085005776'>
capsys = <_pytest.capture.CaptureFixture object at 0x7fb7434e63d0>

    @patch("builtins.input", side_effect=['blue', 'quit'])
    def test_one_valid_color_then_quit(input_mock, capsys):
        # user enters blue = valid color so print it
        # then user enters quit so break out of loop = end program
        call_print_colors()
        actual = capsys.readouterr()[0].strip()
        expected = 'blue\nbye'
>       assert actual == expected
E       AssertionError: assert 'blue\nbye\nbye' == 'blue\nbye'
E           blue
E         + bye
E           bye

test_colors.py:31: AssertionError
___________________________ test_one_invalid_color_then_quit ___________________________

input_mock = <MagicMock name='input' id='140425084954416'>
capsys = <_pytest.capture.CaptureFixture object at 0x7fb7434e65b0>

    @patch("builtins.input", side_effect=['green', 'quit'])
    def test_one_invalid_color_then_quit(input_mock, capsys):
        # user enters green which is not in VALID_COLORS so continue the loop,
        # user then enters quit so loop breaks (end function / program)
        call_print_colors()
        actual = capsys.readouterr()[0].strip()
        expected = f'{NOT_VALID}\nbye'
>       assert actual == expected
E       AssertionError: assert 'Not a valid color\nbye\nbye' == 'Not a valid color\nbye'
E           Not a valid color
E         + bye
E           bye

test_colors.py:41: AssertionError
_______________________ test_invalid_then_valid_color_then_quit ________________________

nput_mock = <MagicMock name='input' id='140425084684704'>
capsys = <_pytest.capture.CaptureFixture object at 0x7fb743504d60>

    @patch("builtins.input", side_effect=['white', 'red', 'quit'])
    def test_invalid_then_valid_color_then_quit(nput_mock, capsys):
        # white is not a valid color so continue the loop,
        # then user enters red which is valid so print it, then quit
        call_print_colors()
        actual = capsys.readouterr()[0].strip()
        expected = f'{NOT_VALID}\nred\nbye'
>       assert actual == expected
E       AssertionError: assert 'Not a valid ...red\nbye\nbye' == 'Not a valid color\nred\nbye'
E           Not a valid color
E         + bye
E           red
E         + bye
E           bye

test_colors.py:51: AssertionError
_______________________ test_valid_then_invalid_color_then_quit ________________________

input_mock = <MagicMock name='input' id='140425084672032'>
capsys = <_pytest.capture.CaptureFixture object at 0x7fb7434a14c0>

    @patch("builtins.input", side_effect=['yellow', 'orange', 'quit'])
    def test_valid_then_invalid_color_then_quit(input_mock, capsys):
        # yellow is a valid color so print it, user then enters orange
        # which is not a valid color so continue loop, lastly user
        # enters quit so exit loop = reaching end function / program
        call_print_colors()
        actual = capsys.readouterr()[0].strip()
        expected = f'yellow\n{NOT_VALID}\nbye'
>       assert actual == expected
E       AssertionError: assert 'yellow\nbye\...lor\nbye\nbye' == 'yellow\nNot ...id color\nbye'
E           yellow
E         + bye
E           Not a valid color
E         + bye
E           bye

test_colors.py:62: AssertionError
=============================== short test summary info ================================
FAILED test_colors.py::test_one_valid_color_then_quit - AssertionError: assert 'blue\...
FAILED test_colors.py::test_one_invalid_color_then_quit - AssertionError: assert 'Not...
FAILED test_colors.py::test_invalid_then_valid_color_then_quit - AssertionError: asse...
FAILED test_colors.py::test_valid_then_invalid_color_then_quit - AssertionError: asse...
============================= 4 failed, 1 passed in 0.09s ==============================


EDIT: I’m back!

If I add the break operator at the end of each conditional, then pytest informs me that 3 tests pass however 2 tests are still failing.

Here is my latest script:

VALID_COLORS = ['blue', 'yellow', 'red']


def print_colors():
   """
   In the while loop ask the user to enter a color, lowercase it and store it in a variable. Next check:
      - if 'quit' was entered for color, print 'bye' and break.
      - if the color is not in VALID_COLORS, print 'Not a valid color' and continue.
      - otherwise print the color in lower case.
   """
   while True:
       chosen_color = input("What color do you choose?")
       low_chosen_color = chosen_color.lower()
       if low_chosen_color == "quit":
           print("bye")
           break
       elif low_chosen_color not in VALID_COLORS:
           print("Not a valid color")
           print("bye")
           break
       elif low_chosen_color in VALID_COLORS:
           print(f"{low_chosen_color}")
           print("bye")
           break
       pass
Here is the new output:

$ bpython -m pytest test_colors.py
================================= test session starts ==================================
platform linux -- Python 3.8.2, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: /home/<user>/dev/projects/python/2018-and-2020/bitesofpy/Intro-freebies/Bite 102 - Infinite loop, input, continue and break
collected 5 items                                                                      

test_colors.py ...FF                                                             [100%]

======================================= FAILURES =======================================
_______________________ test_invalid_then_valid_color_then_quit ________________________

nput_mock = <MagicMock name='input' id='140073684807632'>
capsys = <_pytest.capture.CaptureFixture object at 0x7f65723891c0>

    @patch("builtins.input", side_effect=['white', 'red', 'quit'])
    def test_invalid_then_valid_color_then_quit(nput_mock, capsys):
        # white is not a valid color so continue the loop,
        # then user enters red which is valid so print it, then quit
        call_print_colors()
        actual = capsys.readouterr()[0].strip()
        expected = f'{NOT_VALID}\nred\nbye'
>       assert actual == expected
E       AssertionError: assert 'Not a valid color\nbye' == 'Not a valid color\nred\nbye'
E           Not a valid color
E         - red
E           bye

test_colors.py:51: AssertionError
_______________________ test_valid_then_invalid_color_then_quit ________________________

input_mock = <MagicMock name='input' id='140073684760272'>
capsys = <_pytest.capture.CaptureFixture object at 0x7f657238f310>

    @patch("builtins.input", side_effect=['yellow', 'orange', 'quit'])
    def test_valid_then_invalid_color_then_quit(input_mock, capsys):
        # yellow is a valid color so print it, user then enters orange
        # which is not a valid color so continue loop, lastly user
        # enters quit so exit loop = reaching end function / program
        call_print_colors()
        actual = capsys.readouterr()[0].strip()
        expected = f'yellow\n{NOT_VALID}\nbye'
>       assert actual == expected
E       AssertionError: assert 'yellow\nbye' == 'yellow\nNot ...id color\nbye'
E           yellow
E         - Not a valid color
E           bye

test_colors.py:62: AssertionError
=============================== short test summary info ================================
FAILED test_colors.py::test_invalid_then_valid_color_then_quit - AssertionError: asse...
FAILED test_colors.py::test_valid_then_invalid_color_then_quit - AssertionError: asse...
============================= 2 failed, 3 passed in 0.08s ==============================
Reply
#2
The problem suggests that you should be looping over input until you get a "quit".

But all of your cases end in break, which will exit the loop. So you exit before seeing quit. That seems wrong. You'll never be able to process two colors.

I would expect the only one that you'd want to break with would be the quit branch.
Reply
#3
Ding, ding, ding! I pulled it off, thanks to @bowlofred's advice.

I replaced the second and third instances of the break operator with continue. I also removed the second and third instances of print("bye"). When I ran the test script, it passes all 5 checks. Cool

For what it is worth, here is my final script in full:

VALID_COLORS = ['blue', 'yellow', 'red']


def print_colors():
    """
    In the while loop ask the user to enter a color, lowercase it and store it in a variable. Next check: 
       - if 'quit' was entered for color, print 'bye' and break. 
       - if the color is not in VALID_COLORS, print 'Not a valid color' and continue.
       - otherwise print the color in lower case.
    """
    while True:
        chosen_color = input("What color do you choose?")
        low_chosen_color = chosen_color.lower()
        if low_chosen_color == "quit":
            print("bye")
            break
        elif low_chosen_color not in VALID_COLORS:
            print("Not a valid color")
            continue
        elif low_chosen_color in VALID_COLORS:
            print(f"{low_chosen_color}")
            continue
        pass
Thanks @bowlofred for your help. Big Grin

I meant to reply sooner. Sorry for the delay.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  for loops break when I call the list I'm looping through Radical 4 824 Sep-18-2023, 07:52 AM
Last Post: buran
Question Doubt about conditionals in Python. Carmazum 6 1,536 Apr-01-2023, 12:01 AM
Last Post: Carmazum
  conditionals based on data frame mbrown009 1 873 Aug-12-2022, 08:18 AM
Last Post: Larz60+
  Efficiency with regard to nested conditionals or and statements Mark17 13 3,082 May-06-2022, 05:16 PM
Last Post: Mark17
  Nested conditionals vs conditionals connected by operators dboxall123 8 2,984 Feb-18-2022, 09:34 PM
Last Post: dboxall123
  Break out of nested loops muzikman 11 3,240 Sep-18-2021, 12:59 PM
Last Post: muzikman
  Nested Conditionals shen123 3 2,584 Jul-28-2021, 08:24 AM
Last Post: Yoriz
  How to break out of nested loops pace 11 5,263 Mar-03-2021, 06:25 PM
Last Post: pace
  Invalid syntax using conditionals if - else jperezqu 1 2,295 Jan-13-2021, 07:32 PM
Last Post: bowlofred
  Sorting list of names using a lambda (PyBite #5) Drone4four 2 2,683 Oct-16-2020, 07:30 PM
Last Post: ndc85430

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020