how to make a calculator 6

I want to use the things I know to make the tests for the calculator program better


preview

These are the tests I have by the end of the chapter


open the project

  • I change directory to the calculator folder

    cd calculator
    

    the terminal shows I am in the calculator folder

    .../pumping_python/calculator
    
  • I use pytest-watcher to run the tests

    uv run pytest-watcher . --now
    

    the terminal shows

    rootdir: .../pumping_python/calculator
    configfile: pyproject.toml
    collected 7 items
    
    tests/test_calculator.py .......                              [100%]
    
    ======================== 7 passed in X.YZs =========================
    
  • I hold ctrl on the keyboard, then click on tests/test_calculator.py to open it in the editor


how to make sure the calculator tests use new numbers for every test

I used the setUp method in list comprehensions to make sure that I have a new list and iterable for every test. I want to do the same thing with the calculator, to make sure that each test uses 2 new different random numbers, not the same random numbers for every test


RED: make it fail


I add the setUp method to the TestCalculator class

10class TestCalculator(unittest.TestCase):
11
12    def setUp(self):
13        random_first_number = a_random_number()
14        random_second_number = a_random_number()
15
16    def test_addition(self):

the terminal shows AttributeError

AttributeError: 'TestCalculator' object has no attribute 'random_first_number'

random_first_number and random_second_number can no longer be reached because they belong to the setUp method, I have to make sure they are class attributes


GREEN: make it pass


  • I add self. to random_first_number

    12      def setUp(self):
    13          self.random_first_number = a_random_number()
    14          random_second_number = a_random_number()
    

    the terminal shows AttributeError

    AttributeError: 'TestCalculator' object has no attribute 'random_second_number'. Did you mean: 'random_first_number'?
    
  • I add self. to random_second_number

    10class TestCalculator(unittest.TestCase):
    11
    12    def setUp(self):
    13        self.random_first_number = a_random_number()
    14        self.random_second_number = a_random_number()
    15
    16    def test_addition(self):
    

    the test passes.

The setUp method runs before every test, giving random_first_number and random_second_number new random values for each test.


test_calculator_w_a_for_loop

I tested the calculator functions with None, strings and lists, I want to test them with the other basic Python data types: booleans, tuples, sets and dictionaries.

Since I know how to use a for loop and list comprehensions, I can do this with one test for all of them instead of a different test with 4 or more assertions for each data type


RED: make it fail


I add a new test with a for loop and an assertion to test_calculator.py

164    def test_calculator_raises_type_error_when_given_more_than_two_inputs(self):
165        not_two_numbers = [0, 1, 2]
166
167        with self.assertRaises(TypeError):
168            src.calculator.add(*not_two_numbers)
169        with self.assertRaises(TypeError):
170            src.calculator.divide(*not_two_numbers)
171        with self.assertRaises(TypeError):
172            src.calculator.multiply(*not_two_numbers)
173        with self.assertRaises(TypeError):
174            src.calculator.subtract(*not_two_numbers)
175
176    def test_calculator_w_a_for_loop(self):
177        error_message = 'brmph?! Numbers only. Try again...'
178
179        for data_type in (
180            None,
181            True, False,
182            str(),
183            tuple(),
184            list(),
185            set(),
186            dict(),
187        ):
188            self.assertEqual(
189                src.calculator.add(
190                    data_type, a_random_number()
191                ),
192                'BOOM!!!'
193            )
194
195
196# Exceptions seen

the terminal shows AssertionError

AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'s

GREEN: make it pass


  • I change the expectation to match

    188            self.assertEqual(
    189                src.calculator.add(
    190                    data_type, a_random_number()
    191                ),
    192                error_message
    193            )
    

    the terminal shows AssertionError

    AssertionError: ABC.DEFGHIJKLMNOPQR != 'brmph?! Numbers only. Try again...'
    

    One of the data types from the test gets to the add function so it returns a number and not a message. How can I tell which data type caused the failure?

  • the unittest.TestCase class has a way to tell which item is causing my failure when I am using a for loop, I add it to the test

    176    def test_calculator_w_a_for_loop(self):
    177        error_message = 'brmph?! Numbers only. Try again...'
    178
    179        for data_type in (
    180            None,
    181            True, False,
    182            str(),
    183            tuple(),
    184            list(),
    185            set(),
    186            dict(),
    187        ):
    188            with self.subTest(data_type=data_type):
    189                self.assertEqual(
    190                    src.calculator.add(
    191                        data_type, a_random_number()
    192                    ),
    193                    error_message
    194                )
    195
    196# Exceptions seen
    

    the terminal shows AssertionError for two of the data types I am testing

    tests/test_calculator.py:189: AssertionError
    ============= short test summary info ==============
    SUBFAILED(data_type=True) ...   - AssertionError: UVW.XYZABCDEFGHIJKL != 'brmph?! Numbers only. Try again...'
    SUBFAILED(data_type=False) ...  - AssertionError: MNO.PQRSTUVWXYZABCD != 'brmph?! Numbers only. Try again...'
    =========== 2 failed, 7 passed in X.YZs ============
    

    the unittest.TestCase.subTest method runs the code under it as a sub test, showing the values I give in data_type=data_type so that I can see which one caused the error. In this case the failures were caused by True and False. Is a boolean a number?

  • I open calculator.py from the src folder in the editor

  • then add a condition for booleans to the add function in calculator.py

    38@numbers_only
    39def add(first_input, second_input):
    40    if (
    41        isinstance(first_input, str)
    42        or
    43        isinstance(second_input, str)
    44    ):
    45        return 'brmph?! Numbers only. Try again...'
    46    if (
    47        isinstance(first_input, bool)
    48        or
    49        isinstance(second_input, bool)
    50    ):
    51        return 'brmph?! Numbers only. Try again...'
    52    return first_input + second_input
    

    the test passes


how to test if something is an instance of more than one type

The two if statements in the add function look the same

if (
    isinstance(first_input, data_type)
    or
    isinstance(second_input, data_type)
):
    return 'brmph?! Numbers only. Try again...'

the only difference are the data types

isinstance(something, str)
isinstance(something, bool)

The isinstance function can take a tuple as the second input, which means I can if the first input is an instance of any of the objects in the tuple

  • I add a new if statement to the add function

    38@numbers_only
    39def add(first_input, second_input):
    40    # if (
    41    #     isinstance(first_input, str)
    42    #     or
    43    #     isinstance(second_input, str)
    44    # ):
    45    #     return 'brmph?! Numbers only. Try again...'
    46    # if (
    47    #     isinstance(first_input, bool)
    48    #     or
    49    #     isinstance(second_input, bool)
    50    # ):
    51    if (
    52        isinstance(first_input, (str, bool))
    53        or
    54        isinstance(second_input, (str, bool))
    55    ):
    56        return 'brmph?! Numbers only. Try again...'
    57    return first_input + second_input
    

    the test is still green

  • I remove the other if statements

    38@numbers_only
    39def add(first_input, second_input):
    40    if (
    41        isinstance(first_input, (str, bool))
    42        or
    43        isinstance(second_input, (str, bool))
    44    ):
    45        return 'brmph?! Numbers only. Try again...'
    46    return first_input + second_input
    

    still green


  • I add an assertion for the divide function to test_calculator_w_a_for_loop in test_calculator.py

    176    def test_calculator_w_a_for_loop(self):
    177        error_message = 'brmph?! Numbers only. Try again...'
    178
    179        for data_type in (
    180            None,
    181            True, False,
    182            str(),
    183            tuple(),
    184            list(),
    185            set(),
    186            dict(),
    187        ):
    188            with self.subTest(data_type=data_type):
    189                self.assertEqual(
    190                    src.calculator.add(
    191                        data_type, a_random_number()
    192                    ),
    193                    error_message
    194                )
    195                self.assertEqual(
    196                    src.calculator.divide(
    197                        data_type, a_random_number()
    198                    ),
    199                    'BOOM!!!'
    200                )
    

    the terminal shows AssertionError

    ===================== short test summary info ======================
    SUBFAILED(data_type=None) ... - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type=True) ... - AssertionError: -A.BCDEFGHIJKLMNOPQRS != 'BOOM!!!'
    SUBFAILED(data_type=False) ...- AssertionError: -T.U != 'BOOM!!!'
    SUBFAILED(data_type='') ...   - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type=()) ...   - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type=[]) ...   - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type=set()) ...- AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type={}) ...   - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    =================== 8 failed, 8 passed in V.WXs ====================
    
  • I change the expectation to use the error message

    195                self.assertEqual(
    196                    src.calculator.divide(
    197                        data_type, a_random_number()
    198                    ),
    199                    error_message
    200                )
    

    the terminal shows AssertionError

    SUBFAILED(data_type=True) ...  - AssertionError: Y.ZABCDEFGHIJKLMNOP != 'brmph?! Numbers only. Try again...'
    SUBFAILED(data_type=False) ... - AssertionError: Q.R != 'brmph?! Numbers only. Try again...'
    
  • I add an if statement to the divide function in calculator.py

    30@numbers_only
    31def divide(first_input, second_input):
    32    if (
    33        isinstance(first_input, bool)
    34        or
    35        isinstance(second_input, bool)
    36    ):
    37        return 'brmph?! Numbers only. Try again...'
    38    try:
    39        return first_input / second_input
    40    except ZeroDivisionError:
    41        return 'brmph?! I cannot divide by 0. Try again...'
    42
    43
    44@numbers_only
    45def add(first_input, second_input):
    

    the test passes


  • I add an assertion for the multiply function in test_calculator.py

    195                self.assertEqual(
    196                    src.calculator.divide(
    197                        data_type, a_random_number()
    198                    ),
    199                    error_message
    200                )
    201                self.assertEqual(
    202                    src.calculator.multiply(
    203                        data_type, a_random_number()
    204                    ),
    205                    'BOOM!!!'
    206                )
    207
    208
    209# Exceptions seen
    

    the terminal shows AssertionError

    SUBFAILED(data_type=None) ...  - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type=True) ...  - AssertionError: ST.UVWXYZABCDEFGHI != 'BOOM!!!'
    SUBFAILED(data_type=False) ... - AssertionError: J.K != 'BOOM!!!'
    SUBFAILED(data_type='') ...    - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type=()) ...    - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type=[]) ...    - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type=set()) ... - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type={}) ...    - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    

    they look the same as with the divide function

  • I change the expectation of the assertion for multiplication

    201                self.assertEqual(
    202                    src.calculator.multiply(
    203                        data_type, a_random_number()
    204                    ),
    205                    error_message
    206                )
    

    the terminal shows AssertionError

    SUBFAILED(data_type=True) ...  - AssertionError: -LMN.OPQRSTUVWXYZAB != 'brmph?! Numbers only. Try again...'
    SUBFAILED(data_type=False) ... - AssertionError: -C.D != 'brmph?! Numbers only. Try again...'
    
  • I add an if statement to the multiply function in calculator.py

    19@numbers_only
    20def multiply(first_input, second_input):
    21    if (
    22        isinstance(first_input, list)
    23        or
    24        isinstance(second_input, list)
    25    ):
    26        return 'brmph?! Numbers only. Try again...'
    27    if (
    28        isinstance(first_input, bool)
    29        or
    30        isinstance(second_input, bool)
    31    ):
    32        return 'brmph?! Numbers only. Try again...'
    33    return first_input * second_input
    34
    35
    36@numbers_only
    37def divide(first_input, second_input):
    

    the test passes

  • I add a new if statement to put the two statements together

    19@numbers_only
    20def multiply(first_input, second_input):
    21    # if (
    22    #     isinstance(first_input, list)
    23    #     or
    24    #     isinstance(second_input, list)
    25    # ):
    26    #     return 'brmph?! Numbers only. Try again...'
    27    # if (
    28    #     isinstance(first_input, bool)
    29    #     or
    30    #     isinstance(second_input, bool)
    31    # ):
    32    #     return 'brmph?! Numbers only. Try again...'
    33    if (
    34        isinstance(first_input, (list, bool))
    35        or
    36        isinstance(second_input, (list, bool))
    37    ):
    38        return 'brmph?! Numbers only. Try again...'
    39    return first_input * second_input
    

    the test is still green

  • I remove the other if statements

    19@numbers_only
    20def multiply(first_input, second_input):
    21    if (
    22        isinstance(first_input, (list, bool))
    23        or
    24        isinstance(second_input, (list, bool))
    25    ):
    26        return 'brmph?! Numbers only. Try again...'
    27    return first_input * second_input
    28
    29
    30@numbers_only
    31def divide(first_input, second_input):
    

    still green


  • I add an assertion for the subtract function in test_calculator.py

    201                self.assertEqual(
    202                    src.calculator.multiply(
    203                        data_type, a_random_number()
    204                    ),
    205                    error_message
    206                )
    207                self.assertEqual(
    208                    src.calculator.subtract(
    209                        data_type, a_random_number()
    210                    ),
    211                    'BOOM!!!'
    212                )
    213
    214
    215# Exceptions seen
    

    the terminal shows AssertionError

    SUBFAILED(data_type=None) ...  - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type=True) ...  - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type=False) ... - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type='') ...    - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type=()) ...    - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type=[]) ...    - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type=set()) ... - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    SUBFAILED(data_type={}) ...    - AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    
  • I change the expectation to use the error message

    207                self.assertEqual(
    208                    src.calculator.subtract(
    209                        data_type, a_random_number()
    210                    ),
    211                    error_message
    212                )
    213
    214
    215# Exceptions seen
    

    the terminal shows AssertionError

    SUBFAILED(data_type=True) ... - AssertionError: EFG.HIJKLMNOPQRSTU != 'brmph?! Numbers only. Try again...'
    SUBFAILED(data_type=False) ... - AssertionError: VWX.YZABCDEFGHIJK != 'brmph?! Numbers only. Try again...'
    
  • I add an if statement to the subtract function in calculator.py

    14@numbers_only
    15def subtract(first_input, second_input):
    16    if (
    17        isinstance(first_input, bool)
    18        or
    19        isinstance(second_input, bool)
    20    ):
    21        return 'brmph?! Numbers only. Try again...'
    22    return first_input - second_input
    23
    24
    25@numbers_only
    26def multiply(first_input, second_input):
    

    the test passes. it looks like booleans are numbers


  • All 4 calculator functions have the same if statement

    if (
        isinstance(first_input, bool)
        or
        isinstance(second_input, bool)
    )
    

    the difference between them is that the

    I add the if statement to the numbers_only decorator function to remove repetition

     1def numbers_only(function):
     2    def decorator(first_input, second_input):
     3        error_message = 'brmph?! Numbers only. Try again...'
     4        if first_input is None or second_input is None:
     5            return error_message
     6        if (
     7            isinstance(first_input, (str, list, bool))
     8            or
     9            isinstance(second_input, (str, list, bool))
    10        ):
    11            return error_message
    12
    13        try:
    14            return function(first_input, second_input)
    15        except TypeError:
    16            return error_message
    17    return decorator
    18
    19
    20@numbers_only
    21def subtract(first_input, second_input):
    

    the tests are still green

  • I remove the if statement from the subtract function

    21@numbers_only
    22def subtract(first_input, second_input):
    23    return first_input - second_input
    24
    25
    26@numbers_only
    27def multiply(first_input, second_input):
    

    still green

  • I remove the if statement from the multiply function

    26@numbers_only
    27def multiply(first_input, second_input):
    28    return first_input * second_input
    29
    30
    31@numbers_only
    32def divide(first_input, second_input):
    

    green

  • I remove the if statement from the divide function

    31@numbers_only
    32def divide(first_input, second_input):
    33    try:
    34        return first_input / second_input
    35    except ZeroDivisionError:
    36        return 'brmph?! I cannot divide by 0. Try again...'
    37
    38
    39@numbers_only
    40def add(first_input, second_input):
    

    still green

  • I remove the if statement from the add function

    39@numbers_only
    40def add(first_input, second_input):
    41    return first_input + second_input
    

    the tests are still green


  • I add a variable to the numbers_only decorator function

    1def numbers_only(function):
    2    def decorator(first_input, second_input):
    3        bad_data_types = (str, list, bool)
    4        error_message = 'brmph?! Numbers only. Try again...'
    5
    6        if first_input is None or second_input is None:
    
  • I use the variable to remove the repetition of (str, list, bool)

     6        if first_input is None or second_input is None:
     7            return error_message
     8        if (
     9            # isinstance(first_input, (str, list, bool))
    10            isinstance(first_input, bad_data_types)
    11            or
    12            # isinstance(second_input, (str, list, bool))
    13            isinstance(second_input, bad_data_types)
    14        ):
    15            return error_message
    

    still green

  • I remove the commented lines then use a for loop with the if statements

     1def numbers_only(function):
     2    def decorator(first_input, second_input):
     3        bad_data_types = (str, list, bool)
     4        error_message = 'brmph?! Numbers only. Try again...'
     5
     6        # if first_input is None or second_input is None:
     7        #     return error_message
     8        # if (
     9        #     isinstance(first_input, bad_data_types)
    10        #     or
    11        #     isinstance(second_input, bad_data_types)
    12        # ):
    13        #     return error_message
    14
    15        for value in (first_input, second_input):
    16            if value is None:
    17                return error_message
    18            if isinstance(value, bad_data_types):
    19                return error_message
    20
    21        try:
    22            return function(first_input, second_input)
    23        except TypeError:
    24            return error_message
    25    return decorator
    

    green

  • I remove the commented lines then put the two if statements together with logical disjunction

     1def numbers_only(function):
     2    def decorator(first_input, second_input):
     3        bad_data_types = (str, list, bool)
     4        error_message = 'brmph?! Numbers only. Try again...'
     5
     6        for value in (first_input, second_input):
     7            # if value is None:
     8            #     return error_message
     9            # if isinstance(value, bad_data_types):
    10            #     return error_message
    11
    12            if (
    13                value is None
    14                or
    15                isinstance(value, bad_data_types)
    16            ):
    17                return error_message
    18
    19        try:
    20            return function(first_input, second_input)
    21        except TypeError:
    22            return error_message
    23    return decorator
    

    still green

  • I remove the commented lines

     1def numbers_only(function):
     2    def decorator(first_input, second_input):
     3        bad_data_types = (str, list, bool)
     4        error_message = 'brmph?! Numbers only. Try again...'
     5
     6        for value in (first_input, second_input):
     7            if (
     8                value is None
     9                or
    10                isinstance(value, bad_data_types)
    11            ):
    12                return error_message
    13
    14        try:
    15            return function(first_input, second_input)
    16        except TypeError:
    17            return error_message
    18    return decorator
    19
    20
    21@numbers_only
    22def subtract(first_input, second_input):
    23    return first_input - second_input
    24
    25
    26@numbers_only
    27def multiply(first_input, second_input):
    28    return first_input * second_input
    29
    30
    31@numbers_only
    32def divide(first_input, second_input):
    33    try:
    34        return first_input / second_input
    35    except ZeroDivisionError:
    36        return 'brmph?! I cannot divide by 0. Try again...'
    37
    38
    39@numbers_only
    40def add(first_input, second_input):
    41    return first_input + second_input
    

    the tests are still green

  • I remove test_calculator_sends_message_when_input_is_not_a_number because it tests None, strings and lists, while test_calculator_w_a_for_loop tests None, booleans, strings, tuples, lists, sets and dictionaries

    43    def test_division(self):
    44        try:
    45            self.assertEqual(
    46                src.calculator.divide(
    47                    self.random_first_number,
    48                    self.random_second_number
    49                ),
    50                self.random_first_number/self.random_second_number
    51            )
    52        except ZeroDivisionError:
    53            self.assertEqual(
    54                src.calculator.divide(self.random_first_number, 0),
    55                'brmph?! I cannot divide by 0. Try again...'
    56            )
    57
    58    def test_calculator_w_list_items(self):
    
  • I change the name of test_calculator_w_a_for_loop to test_calculator_sends_message_when_input_is_not_a_number

    121    def test_calculator_sends_message_when_input_is_not_a_number(self):
    122        error_message = 'brmph?! Numbers only. Try again...'
    123
    124        for data_type in (
    125            None,
    126            True, False,
    127            str(),
    128            tuple(),
    129            list(),
    130            set(),
    131            dict(),
    132        ):
    133            with self.subTest(data_type=data_type):
    134                self.assertEqual(
    135                    src.calculator.add(
    136                        data_type, a_random_number()
    137                    ),
    138                    error_message
    139                )
    140                self.assertEqual(
    141                    src.calculator.divide(
    142                        data_type, a_random_number()
    143                    ),
    144                    error_message
    145                )
    146                self.assertEqual(
    147                    src.calculator.multiply(
    148                        data_type, a_random_number()
    149                    ),
    150                    error_message
    151                )
    152                self.assertEqual(
    153                    src.calculator.subtract(
    154                        data_type, a_random_number()
    155                    ),
    156                    error_message
    157                )
    158
    159
    160# Exceptions seen
    161# AssertionError
    162# NameError
    163# AttributeError
    164# TypeError
    

  • Using a for loop means I do not have to write a lot of tests. I can add more data to the iterable without having to add more tests

    121    def test_calculator_sends_message_when_input_is_not_a_number(self):
    122        error_message = 'brmph?! Numbers only. Try again...'
    123
    124        for data_type in (
    125            None,
    126            True, False,
    127            str(), 'text',
    128            tuple(), (0, 1, 2, 'n'),
    129            list(), [0, 1, 2, 'n'],
    130            set(), {0, 1, 2, 'n'},
    131            dict(), {'key': 'value'},
    132        ):
    133            with self.subTest(data_type=data_type):
    

    the test is still green

  • I can also write the test with a list comprehension, though it looks ugly

    121    def test_calculator_sends_message_when_input_is_not_a_number(self):
    122        error_message = 'brmph?! Numbers only. Try again...'
    123
    124        [
    125            self.assertEqual(
    126                src.calculator.add(data_type, a_random_number()),
    127                'BOOM!!!'
    128            ) for data_type in (
    129                None,
    130                True, False,
    131                str(), 'text',
    132                tuple(), (0, 1, 2, 'n'),
    133                list(), [0, 1, 2, 'n'],
    134                set(), {0, 1, 2, 'n'},
    135                dict(), {'key': 'value'},
    136            )
    137        ]
    138
    139        for data_type in (
    140            None,
    141            True, False,
    142            str(), 'text',
    143            tuple(), (0, 1, 2, 'n'),
    144            list(), [0, 1, 2, 'n'],
    145            set(), {0, 1, 2, 'n'},
    146            dict(), {'key': 'value'},
    147        ):
    

    the terminal shows AssertionError

    AssertionError: 'brmph?! Numbers only. Try again...' != 'BOOM!!!'
    
  • I change the expectation to the error message

     4        [
     5            self.assertEqual(
     6                src.calculator.add(data_type, a_random_number()),
     7                error_message
     8            ) for data_type in (
     9                None,
    10                True, False,
    11                str(), 'text',
    12                tuple(), (0, 1, 2, 'n'),
    13                list(), [0, 1, 2, 'n'],
    14                set(), {0, 1, 2, 'n'},
    15                dict(), {'key': 'value'},
    16            )
    17        ]
    

    the test passes. There are a few problems with doing it this way

I know a better way to test the calculator with inputs that are NOT numbers


close the project

  • I close test_calculator.py and calculator.py in the editors

  • I click in the terminal, then use q on the keyboard to leave the tests. The terminal goes back to the command line

  • I change directory to the parent of calculator

    cd ..
    

    the terminal shows

    .../pumping_python
    

    I am back in the pumping_python directory


review

I ran tests to show I can make a list from an iterable with

I can use functions and conditions with list comprehensions to make a list with one line. I think of it as

[
    process(item)
    for item in iterable
    if condition/not condition
]

I can also do this with dictionaries, it is called a dict comprehension and the syntax is any mix of these

{
    a_process(key): another_process(value)
    for key/value in iterable
    if condition/not condition
}

How many questions can you answer after going through this chapter?


code from the chapter

Do you want to see all the CODE I typed in this chapter?


what is next?

you know

Would you like to test if a boolean is an integer or a float?


rate pumping python

If this has been a 7 star experience for you, please CLICK HERE to leave a 5 star review of pumping python. It helps other people get into the book too