separate and equal functions

All the functions in the functions project were written in tests/test_functions.py. I want to move them to the functions module in the src folder so that I can keep the tests and solutions separate.


preview

I have these tests by the end of the chapter

functions/tests/test_functions.py
 1import src.functions
 2
 3
 4def assert_equal(input_1, input_2):
 5    assert input_1 == input_2
 6
 7
 8def assert_is_none(something):
 9    assert something is None
10
11
12def test_making_a_function_w_pass():
13    assert_is_none(src.functions.w_pass())
functions/tests/test_functions.py
16def test_making_a_function_w_return():
17    assert_is_none(src.functions.w_return())
18
19
20def test_making_a_function_w_return_none():
21    assert_is_none(src.functions.w_return_none())
22
23
24def test_what_happens_after_functions_return():
25    assert_is_none(
26        src.functions.return_leaves_the_function()
27    )
functions/tests/test_functions.py
30def test_constant_function():
31    assert_equal(
32        src.functions.constant(), 'the same thing'
33    )
34
35
36def test_identity_function():
37    assert_is_none(src.functions.identity(None))
38    assert_equal(
39        src.functions.identity(object), object
40    )
functions/tests/test_functions.py
43def test_why_use_a_function():
44    def add_x(number):
45        return 3 + number
46
47    assert_equal(add_x(0), 3)
48    assert_equal(add_x(1), 4)
49    assert_equal(add_x(2), 5)
50    assert_equal(add_x(3), 6)
51    assert_equal(add_x(4), 7)
52    assert_equal(add_x(5), 8)
53    assert_equal(add_x(6), 9)
54    assert_equal(add_x(7), 10)
55    assert_equal(add_x(8), 11)
56    assert_equal(add_x(9), 12)
functions/tests/test_functions.py
59def test_positional_arguments():
60    positional_arguments = (
61        src.functions.positional_arguments
62    )
63    first, last = 'first', 'last'
64
65    assert_equal(
66        positional_arguments(first, last),
67        (first, last)
68    )
69    assert_equal(
70        positional_arguments(last, first),
71        (last, first)
72    )
73
74    assert_equal(
75        positional_arguments(0, 1), (0, 1)
76    )
77
78    a_tuple = (0, 1, 2, 'n')
79    a_list = [0, 1, 2, 'n']
80    assert_equal(
81        positional_arguments(a_tuple, a_list),
82        (a_tuple, a_list)
83    )
84
85    a_set = {0, 1, 2, 'n'}
86    a_dictionary = {'key': 'value'}
87    assert_equal(
88        src.functions.keyword_arguments(
89            a_set, a_dictionary,
90        ),
91        (a_set, a_dictionary)
92    )
functions/tests/test_functions.py
 95def test_keyword_arguments():
 96    keyword_arguments = (
 97        src.functions.keyword_arguments
 98    )
 99    first, last = 'first', 'last'
100
101    assert_equal(
102        keyword_arguments(
103            first_input=first, last_input=last,
104        ),
105        (first, last)
106    )
107    assert_equal(
108        keyword_arguments(
109            last_input=last, first_input=first,
110        ),
111        (first, last)
112    )
113
114    assert_equal(
115        keyword_arguments(
116            last_input=0, first_input=1,
117        ),
118        (1, 0)
119    )
120
121    a_tuple = (0, 1, 2, 'n')
122    a_list = [0, 1, 2, 'n']
123    assert_equal(
124        keyword_arguments(
125            first_input=a_tuple,
126            last_input=a_list,
127        ),
128        (a_tuple, a_list)
129    )
130
131    a_set = {0, 1, 2, 'n'}
132    a_dictionary = {'key': 'value'}
133    assert_equal(
134        src.functions.positional_arguments(
135            last_input=a_dictionary,
136            first_input=a_set,
137        ),
138        (a_set, a_dictionary)
139    )
functions/tests/test_functions.py
142def test_args_and_kwargs():
143    first, last = 'first', 'last'
144
145    assert_equal(
146        src.functions.args_and_kwargs(
147            first, last_input=last
148        ),
149        (first, last)
150    )
functions/tests/test_functions.py
153def test_optional_arguments():
154    optional_arguments = (
155        src.functions.optional_arguments
156    )
157
158    first_name, last_name = 'jane', 'doe'
159    assert_equal(
160        optional_arguments(
161            first_name,
162        ),
163        (first_name, last_name)
164    )
165
166    first_name, blow = 'joe', 'blow'
167    assert_equal(
168        optional_arguments(
169            first_name, blow
170        ),
171        (first_name, blow)
172    )
173
174    first_name = 'john'
175    assert_equal(
176        optional_arguments(
177            first_input=first_name,
178        ),
179        (first_name, last_name)
180    )
181
182    last_name = 'smith'
183    assert_equal(
184        optional_arguments(
185            last_input=last_name,
186            first_input=first_name,
187        ),
188        (first_name, last_name)
189    )
functions/tests/test_functions.py
192def test_unknown_number_of_arguments():
193    unknown_number_of_arguments = (
194        src.functions.unknown_number_of_arguments
195    )
196
197    a_tuple = (0, 1)
198    a_dictionary = {'a': 2, 'b': 3}
199    assert_equal(
200        unknown_number_of_arguments(
201            *a_tuple, **a_dictionary
202        ),
203        (a_tuple, a_dictionary)
204    )
205
206    a_dictionary = {'a': 2, 'b': 3, 'c': 4}
207    assert_equal(
208        unknown_number_of_arguments(
209            *a_tuple, **a_dictionary,
210        ),
211        (a_tuple, a_dictionary)
212    )
213
214    a_tuple = (0, 1, 2)
215    a_dictionary = {'a': 3, 'b': 4, 'c': 5}
216    assert_equal(
217        unknown_number_of_arguments(
218            *a_tuple, **a_dictionary
219        ),
220        (a_tuple, a_dictionary)
221    )
222
223    a_tuple = (0, 1, 2, 'n')
224    assert_equal(
225        unknown_number_of_arguments(*a_tuple),
226        (a_tuple, {})
227    )
228
229    a_dictionary = {'a': 1, 'b': 2, 'c': 3, 'd': 'n'}
230    assert_equal(
231        unknown_number_of_arguments(**a_dictionary),
232        ((), a_dictionary)
233    )
234
235    assert_equal(
236        unknown_number_of_arguments(), ((), {})
237    )
238
239
240# Exceptions seen
241# AssertionError
242# NameError
243# TypeError
244# SyntaxError
245# AttributeError

open the project

  • I open a terminal

  • I change directory to the project

    terminal
    cd functions
    

    the terminal shows I am in the functions folder

    .../pumping_python/functions
    
  • I open test_functions.py from the tests folder

  • I use pytest-watcher to run the tests automatically

    terminal
    uv run pytest-watcher . --now --patterns "**/*.py"
    

    the terminal shows

    test_functions.py ............                      [100%]
    
    =================== 12 passed in X.YZs ===================
    

move w_pass to src

RED: make it fail


I change the call in the assertion of test_making_a_function_w_pass to use the result of a call to the w_pass function of the functions module in the src folder instead of a call to the w_pass function in tests/test_functions.py

 9def test_making_a_function_w_pass():
10    def w_pass():
11        pass
12
13    # assert_is_none(w_pass())
14    assert_is_none(src.functions.w_pass())
15
16
17def test_making_a_function_w_return():

the terminal is my friend, and shows NameError

NameError: name 'src' is not defined

because src is not defined in tests/test_functions.py.


GREEN: make it pass


  • I add an import statement at the top of tests/test_functions.py

    1import src.functions
    2
    3
    4def test_making_a_function_w_pass():
    

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.functions' has no attribute 'w_pass'
    

    because there is nothing in the functions module in the src folder with the name w_pass.

  • I add AttributeError to the list of Exceptions seen, in tests/test_functions.py

  • I open __init__.py from the functions folder in the src folder.

  • I remove all the text then add a copy of the w_pass function to src/functions/__init__.py

    1def w_pass():
    2    pass
    

    the test passes.


REFACTOR: make it better


I can write solutions in a different module from the tests.


move w_return

RED: make it fail



GREEN: make it pass


I add a copy of the w_return function to src/functions/__init__.py

1def w_pass():
2    pass
3
4
5def w_return():
6    return

the test passes.


REFACTOR: make it better



move w_return_none

RED: make it fail



GREEN: make it pass


I add a copy of the w_return_none function to src/functions/__init__.py

 5def w_return():
 6    return
 7
 8
 9def w_return_none():
10    return None

the test passes.


REFACTOR: make it better



move return_leaves_the_function

RED: make it fail



GREEN: make it pass


I add a copy of return_leaves_the_function to src/functions/__init__.py

 9def w_return_none():
10    return None
11
12
13def return_leaves_the_function():
14    return None
15    return 'only one way for this line to run'

the test passes.


REFACTOR: make it better



move constant function

RED: make it fail



GREEN: make it pass


I add a copy of the constant function to src/functions/__init__.py

13def return_leaves_the_function():
14    return None
15    return 'only one way for this line to run'
16
17
18def constant():
19    return 'the same thing'

the test passes.


REFACTOR: make it better



move identity function

RED: make it fail



GREEN: make it pass


I add a copy of the identity function to src/functions/__init__.py

18def constant():
19    return 'the same thing'
20
21
22def identity(the_input):
23    return the_input

the test passes.


REFACTOR: make it better



move positional_arguments

RED: make it fail



GREEN: make it pass



REFACTOR: make it better



move keyword_arguments

RED: make it fail



GREEN: make it pass



REFACTOR: make it better



move args_and_kwargs

RED: make it fail



GREEN: make it pass


I add a copy of the args_and_kwargs function to src/functions/__init__.py

30def keyword_arguments(first_input, last_input):
31    return first_input, last_input
32
33
34def args_and_kwargs(first_input, last_input):
35    return first_input, last_input

the test passes.


REFACTOR: make it better


  • I remove the commented line and the args_and_kwargs function from test_args_and_kwargs in tests/test_functions.py

    the test is still green because the call that was made to the args_and_kwargs function that was in tests/test_functions.py is now to the args_and_kwargs function in __init__.py in the functions folder in the src folder.

    Python follows this path when src.functions.args_and_kwargs is called

    src.functions.args_and_kwargs
    src/
    └── functions/
        └── __init__.py
            └── def args_and_kwargs(first_input, last_input):
                └── return first_input, last_input
    
  • I add a git commit message in the other terminal

    terminal
    git commit -am \
    'move args_and_kwargs to src'
    

move optional_arguments

RED: make it fail



GREEN: make it pass



REFACTOR: make it better



move unknown_number_of_arguments function

RED: make it fail



GREEN: make it pass



REFACTOR: make it better



test_functions

I can write the functions that make the tests pass (except for test_why_use_a_function which I left alone) without looking at tests/test_functions.py since the solutions are now separate from the tests.


RED: make it fail


  • I go back to the terminal where the tests are running

  • I close tests/test_functions.py

  • I delete all the text in src/functions/__init__.py and the terminal shows 11 failures.

    FAILED ...::test_making_a_function_w_pass -
        AttributeError: module 'src.functions'
                        has no attribute 'w_pass'
    FAILED ...::test_making_a_function_w_return -
        AttributeError: module 'src.functions'
                        has no attribute 'w_return'
    FAILED ...::test_making_a_function_w_return_none -
        AttributeError: module 'src.functions'
                        has no attribute 'w_return_none'
    FAILED ...::test_what_happens_after_functions_return -
        AttributeError: module 'src.functions'
                        has no attribute 'return_lea...
    FAILED ...::test_constant_function -
        AttributeError: module 'src.functions'
                        has no attribute 'constant'
    FAILED ...::test_identity_function -
        AttributeError: module 'src.functions'
                        has no attribute 'identity'
    FAILED ...::test_positional_arguments -
        AttributeError: module 'src.functions'
                        has no attribute 'positional_arguments'
    FAILED ...::test_keyword_arguments -
        AttributeError: module 'src.functions'
                        has no attribute 'keyword_arguments'
    FAILED ...::test_args_and_kwargs -
        AttributeError: module 'src.functions'
                        has no attribute 'args_and_kwargs'
    FAILED ...::test_optional_arguments -
        AttributeError: module 'src.functions'
                        has no attribute 'optional_arguments'
    FAILED ...::test_unknown_number_of_arguments -
        AttributeError: module 'src.functions'
                        has no attribute 'unknown_nu...
    ============= 11 failed, 1 passed in A.BCs ==============
    

    Can you make the tests pass without looking at how I solve it below? You can come back to compare solutions when you are done or if you get stuck.


GREEN: make it pass


  • I start with the last AttributeError and add a function definition for unknown_number_of_arguments to src/functions/__init__.py

    1def unknown_number_of_arguments():
    2    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: unknown_number_of_arguments() got an
               unexpected keyword argument 'a'
    
  • I add a to the parentheses

    1# def unknown_number_of_arguments():
    2def unknown_number_of_arguments(a):
    3    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: unknown_number_of_arguments() got
               multiple values for argument 'a'
    

    which means it got called with a as a keyword argument and since I have it as the first position, Python reads it as two values for the same argument.

  • I try another argument in the parentheses before a

    1# def unknown_number_of_arguments():
    2# def unknown_number_of_arguments(a):
    3def unknown_number_of_arguments(z, a):
    4    return None
    

    the terminal still shows TypeError

  • I use a starred expression to make the function take any number of positional_arguments

    1# def unknown_number_of_arguments():
    2# def unknown_number_of_arguments(a):
    3# def unknown_number_of_arguments(z, a):
    4def unknown_number_of_arguments(
    5        *positional, a
    6    ):
    7    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: unknown_number_of_arguments() got
               an unexpected keyword argument 'b'
    

    because the call uses a name (b) that is not in the parentheses of its definition.

  • I add b to the parentheses

    1# def unknown_number_of_arguments():
    2# def unknown_number_of_arguments(a):
    3# def unknown_number_of_arguments(z, a):
    4def unknown_number_of_arguments(
    5        # *positional, a
    6        *positional, a, b
    7    ):
    8    return None
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert None == ((0, 1), {'a': 2, 'b': 3})
    
  • I copy (ctrl/command+c) the tuple from the right side in the terminal then paste it (ctrl/command+v) to replace the return statement

    1# def unknown_number_of_arguments():
    2# def unknown_number_of_arguments(a):
    3# def unknown_number_of_arguments(z, a):
    4def unknown_number_of_arguments(
    5        # *positional, a
    6        *positional, a, b
    7    ):
    8    # return None
    9    return ((0, 1), {'a': 2, 'b': 3})
    

    the terminal is my friend, and shows TypeError

    TypeError: unknown_number_of_arguments() got
               an unexpected keyword argument 'c'
    

    because the call uses a name (c) that is not in the parentheses of its definition.

  • I add c to the parentheses

     1# def unknown_number_of_arguments():
     2# def unknown_number_of_arguments(a):
     3# def unknown_number_of_arguments(z, a):
     4def unknown_number_of_arguments(
     5        # *positional, a
     6        # *positional, a, b
     7        *positional, a, b, c
     8    ):
     9    # return None
    10    return ((0, 1), {'a': 2, 'b': 3})
    

    the terminal shows TypeError

    TypeError: unknown_number_of_arguments() missing
               1 required keyword-only argument: 'c'.
    

    because something called the function without a value for c

  • I make c an optional argument

     1# def unknown_number_of_arguments():
     2# def unknown_number_of_arguments(a):
     3# def unknown_number_of_arguments(z, a):
     4def unknown_number_of_arguments(
     5        # *positional, a
     6        # *positional, a, b
     7        # *positional, a, b, c
     8        *positional, a, b, c=None,
     9    ):
    10    # return None
    11    return ((0, 1), {'a': 2, 'b': 3})
    

    the terminal shows AssertionError

    AssertionError: assert ((0, 1), {'a': 2, 'b': 3})
                        == ((0, 1), {'a'...': 3, 'c': 4})
    
  • I change the return statement to see the difference between the input and the expected output

     1# def unknown_number_of_arguments():
     2# def unknown_number_of_arguments(a):
     3# def unknown_number_of_arguments(z, a):
     4def unknown_number_of_arguments(
     5        # *positional, a
     6        # *positional, a, b
     7        # *positional, a, b, c
     8        *positional, a, b, c=None,
     9    ):
    10    # return None
    11    # return ((0, 1), {'a': 2, 'b': 3})
    12    return positional, a, b, c
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert ((0, 1), 2, 3, None)
                        == ((0, 1), {'a': 2, 'b': 3})
    
  • I change the return statement back

     1# def unknown_number_of_arguments():
     2# def unknown_number_of_arguments(a):
     3# def unknown_number_of_arguments(z, a):
     4def unknown_number_of_arguments(
     5        # *positional, a
     6        # *positional, a, b
     7        # *positional, a, b, c
     8        *positional, a, b, c=None,
     9    ):
    10    # return None
    11    return ((0, 1), {'a': 2, 'b': 3})
    12    # return positional, a, b, c
    

    the terminal is my friend, and shows AssertionError

    AssertionError: assert ((0, 1), {'a': 2, 'b': 3})
                        == ((0, 1), {'a'...': 3, 'c': 4})
    

    the dictionaries are different.

  • I use a double starred expression in the parentheses to make the function take any number of keyword_arguments

     1# def unknown_number_of_arguments():
     2# def unknown_number_of_arguments(a):
     3# def unknown_number_of_arguments(z, a):
     4def unknown_number_of_arguments(
     5        # *positional, a
     6        # *positional, a, b
     7        # *positional, a, b, c
     8        # *positional, a, b, c=None,
     9        *positional, **keyword,
    10    ):
    11    # return None
    12    return ((0, 1), {'a': 2, 'b': 3})
    13    # return positional, a, b, c
    

    the terminal still shows AssertionError

    AssertionError: assert ((0, 1), {'a': 2, 'b': 3})
                        == ((0, 1), {'a'...': 3, 'c': 4})
    
  • I return the inputs

     1# def unknown_number_of_arguments():
     2# def unknown_number_of_arguments(a):
     3# def unknown_number_of_arguments(z, a):
     4def unknown_number_of_arguments(
     5        # *positional, a
     6        # *positional, a, b
     7        # *positional, a, b, c
     8        # *positional, a, b, c=None,
     9        *positional, **keyword,
    10    ):
    11    # return None
    12    # return ((0, 1), {'a': 2, 'b': 3})
    13    # return positional, a, b, c
    14    return positional, keyword
    

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.functions'
                    has no attribute 'optional_arguments'
    
  • I add a function definition for optional_arguments

    the terminal is my friend, and shows TypeError

    TypeError: optional_arguments() takes
               0 positional arguments but 1 was given
    
  • I add a name to allow the function take input

    the terminal is my friend, and shows AssertionError

    AssertionError: assert None == ('jane', 'doe')
    
  • I copy (ctrl/command+c) the value from the terminal and paste it (ctrl/command+v) to replace the return statement

    the terminal is my friend, and shows TypeError

    TypeError: optional_arguments() takes
               1 positional argument but 2 were given
    
  • I add another name to the parentheses

    the terminal shows TypeError

    TypeError: optional_arguments() missing
               1 required positional argument: 'argument_b'
    
  • I make the argument optional

    the terminal is my friend, and shows AssertionError

    AssertionError: assert ('jane', 'doe')
                        == ('joe', 'blow')
    
  • I change the return statement of optional_arguments to see the difference between the input and the expected output

    the terminal is my friend, and shows AssertionError

    AssertionError: assert ('jane', None)
                        == ('jane', 'doe')
    

    the function returned a tuple with the first argument and the default value of argument_b.

  • I change the default value to 'doe'

    the terminal is my friend, and shows TypeError

    TypeError: optional_arguments() got
               an unexpected keyword argument 'first_input'
    

    because the call uses a name (first_input) that is not in the parentheses of its definition.

  • I add the name in parentheses

    the terminal is my friend, and shows SyntaxError

    SyntaxError: parameter without a default
         follows parameter with a default
    

    because parameters without default values must come before parameters with default values.

  • I change the order of the arguments

    the terminal is my friend, and shows TypeError

    TypeError: optional_arguments() missing
               1 required positional argument: 'first_input'
    
  • I make first_input the first argument to see if the problem is the position it is in

    the terminal is my friend, and shows TypeError

    TypeError: optional_arguments() missing
               1 required positional argument: 'argument'
    
  • I make argument optional

    the terminal is my friend, and shows AssertionError

    AssertionError: assert (None, 'doe')
                        == ('jane', 'doe')
    

    the function returned a tuple with the default value of argument

  • I add first_input to the return statement

    the terminal is my friend, and shows AssertionError

    AssertionError: assert ('jane', None, 'doe')
                        == ('jane', 'doe')
    

    it looks like I do not need the argument parameter.

  • I remove argument from the parentheses and return statement

    the terminal is my friend, and shows TypeError

    TypeError: optional_arguments() got
               an unexpected keyword argument 'last_input'.
               Did you mean 'first_input'?
    

    because the call uses a name (last_input) that is not in the parentheses of its definition.

  • I add the name in the parentheses

    the terminal is my friend, and shows SyntaxError

    SyntaxError: parameter without a default
         follows parameter with a default
    

    because parameters without default values must come before parameters with default values.

  • I give the argument a default value

    the terminal is my friend, and shows AssertionError

    AssertionError: assert ('john', 'doe')
                        == ('john', 'smith')
    

    the last names are different.

  • I add last_input to the return statement

    the terminal is my friend, and shows AssertionError

    AssertionError: assert ('jane', 'doe', None)
                        == ('jane', 'doe')
    

    I only need two inputs.

  • I remove argument_b from the parentheses and return statement, then change the default value of last_input to 'doe'

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.functions'
                    has no attribute 'args_and_kwargs'
    
  • I add a function definition for args_and_kwargs

    the terminal is my friend, and shows TypeError

    TypeError: args_and_kwargs() got
               an unexpected keyword argument 'last_input'
    
  • I add last_input in parentheses

    the terminal is my friend, and shows TypeError

    TypeError: args_and_kwargs() got
               multiple values for argument 'last_input'
    

    which means it got called with last_input as a positional and keyword argument. Since I have it as the first position, Python reads it as two values for the same argument.

  • I add another name before last_input

    the terminal is my friend, and shows AssertionError

    AssertionError: assert None == ('first', 'last')
    
  • I return the inputs

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.functions'
                    has no attribute 'keyword_arguments'
    
  • I add a function definition for keyword_arguments

    the terminal is my friend, and shows TypeError

    TypeError: keyword_arguments() got
               an unexpected keyword argument 'first_input'
    

    because the call uses a name (first_input) that is not in the parentheses of its definition.

  • I add first_input to the parentheses

    the terminal is my friend, and shows TypeError

    TypeError: keyword_arguments() got
               an unexpected keyword argument 'last_input'.
               Did you mean 'first_input'?
    
  • I add last_input to the parentheses

    the terminal is my friend, and shows AssertionError

    AssertionError: assert None == ('first', 'last')
    
  • I copy and paste the tuple from the terminal as the return statement

    the terminal is my friend, and shows AssertionError

    AssertionError: assert ('first', 'last') == (1, 0)
    
  • I change the return statement to see the difference between the inputs and the output

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.functions'
                    has no attribute 'positional_arguments'.
                    Did you mean: 'optional_arguments'?
    
  • I add a function definition for positional_arguments

    the terminal is my friend, and shows TypeError

    TypeError: positional_arguments() got
               an unexpected keyword argument 'last_input'
    

    because the call uses a name (last_input) that is …

  • I add the name to the parentheses in the definition

    the terminal is my friend, and shows TypeError

    TypeError: positional_arguments() got
               an unexpected keyword argument 'first_input'.
               Did you mean 'last_input'?
    

    because …

  • I add first_input to the parentheses

    the terminal is my friend, and shows AssertionError

    AssertionError: assert None
        == ({3, 1, 2, 'n'}, {'key': 'value'})
    
  • I copy (ctrl/command+c) and paste (ctrl/command+v) the value from the terminal to change the return statement

    the terminal is my friend, and shows AssertionError

    AssertionError:
        assert ({1, 2, 3, 'n...ey': 'value'})
            == ('first', 'last')
    
  • I change the return statement to see the difference between the inputs and the output

    the terminal is my friend, and shows AssertionError

    AssertionError:
        assert ({'key': 'val...3, 1, 'n', 2})
            == ({3, 1, 'n', ...ey': 'value'})
    
  • I change the order of the inputs in the return statement

    the terminal is my friend, and shows AssertionError

    AssertionError: assert ('last', 'first')
                        == ('first', 'last')
    

    the order is reversed.

  • I change the order of inputs in the parentheses

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.functions'
                    has no attribute 'identity'
    
  • I add a function definition for identity

    the terminal is my friend, and shows TypeError

    TypeError: identity() takes
               0 positional arguments but 1 was given
    
  • I add a name to the function definition to make it take input

    the terminal is my friend, and shows AssertionError

    AssertionError: assert None == object
    
  • I change the return statement to give the test what it wants

    the terminal is my friend, and shows AssertionError

    AssertionError: assert <class 'object'> == None
    
  • I return the input

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.functions'
                    has no attribute 'constant'
    
  • I add a function definition for constant

    the terminal is my friend, and shows AssertionError

    AssertionError: assert None == 'the same thing'
    
  • I copy and paste the value from the terminal as the return statement

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.functions'
                    has no attribute 'return_leaves_the_function'
    
  • I add a function definition for return_leaves_the_function

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.functions'
                    has no attribute 'w_return_none'
    
  • I add a function definition for w_return_none

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.functions'
                    has no attribute 'w_return'
    
  • I add a function definition for w_return

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.functions'
                    has no attribute 'w_pass'
    
  • I add a function definition for w_pass

    all tests are passing!


REFACTOR: make it better


  • I remove the commented lines

     1def unknown_number_of_arguments(
     2        *positional, **keyword,
     3    ):
     4    return positional, keyword
     5
     6
     7def optional_arguments(
     8        first_input, last_input='doe',
     9    ):
    10    return first_input, last_input
    
  • I add a git commit message in the other terminal

    terminal
    git commit -am 'test functions'
    

close the project

  • I close src/functions/__init__.py

  • I click in the terminal where the tests are running

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

  • I change directory to the parent of functions

    terminal
    cd ..
    

    the terminal shows

    .../pumping_python
    

    I am back in the pumping_python directory.


review

I can write solutions in a different module from the tests.


code from the chapter

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


what is next?

would you like to separate the tests from the solution in the telephone project?


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.