how to make a person with a class
The factory and say_hi functions use three of the same inputs
first_namelast_nameyear_of_birth
I want to give those values once, and get a representation for a person. I can do that with a class
what is a class?
I think of classes_ as attributes (variables) and methods (functions) that belong together.
Everything in Python is an object_, which is another word for a class_, it means that everything in Python has a class_ definition somewhere. Knowing how classes_ work and how to make them shows how everything in Python works or at least that they are attributes (variables) and methods (functions) that belong together.
preview
I have these tests by the end of the chapter
1import src.person
2
3
4def test_joe():
5 first_name = 'joe'
6 last_name = 'blow'
7 sex = 'M'
8 year_of_birth = 1996
9
10 reality = src.person.factory(
11 first_name=first_name,
12 last_name=last_name,
13 sex=sex,
14 year_of_birth=year_of_birth,
15 )
16 my_expectation = (
17 f'{first_name}, {last_name},'
18 f' {sex}, {year_of_birth}'
19 )
20 assert reality == my_expectation
21
22 reality = src.person.say_hi(
23 first_name=first_name,
24 last_name=last_name,
25 year_of_birth=year_of_birth,
26 )
27 my_expectation = (
28 f'Hi, my name is {first_name}'
29 f' {last_name} and I am'
30 f' {2026-year_of_birth}.'
31 )
32 assert reality == my_expectation
33
34
35def test_jane():
36 first_name = 'jane'
37 last_name = 'doe'
38 sex = 'F'
39 year_of_birth = 1991
40
41 reality = src.person.factory(
42 first_name=first_name,
43 last_name=last_name,
44 sex=sex,
45 year_of_birth=year_of_birth,
46 )
47 my_expectation = (
48 f'{first_name}, {last_name},'
49 f' {sex}, {year_of_birth}'
50 )
51 assert reality == my_expectation
52
53 reality = src.person.say_hi(
54 first_name=first_name,
55 last_name=last_name,
56 year_of_birth=year_of_birth,
57 )
58 my_expectation = (
59 f'Hi, my name is {first_name}'
60 f' {last_name} and I am'
61 f' {2026-year_of_birth}.'
62 )
63 assert reality == my_expectation
64
65
66def test_john():
67 first_name = 'john'
68 last_name = 'smith'
69 sex = 'M'
70 year_of_birth = 1580
71
72 reality = src.person.factory(
73 first_name=first_name,
74 last_name=last_name,
75 sex=sex,
76 year_of_birth=year_of_birth,
77 )
78 my_expectation = (
79 f'{first_name}, {last_name},'
80 f' {sex}, {year_of_birth}'
81 )
82 assert reality == my_expectation
83
84 reality = src.person.say_hi(
85 first_name=first_name,
86 last_name=last_name,
87 year_of_birth=year_of_birth,
88 )
89 my_expectation = (
90 f'Hi, my name is {first_name}'
91 f' {last_name} and I am'
92 f' {2026-year_of_birth}.'
93 )
94 assert reality == my_expectation
95
96
97def test_mary():
98 first_name = 'mary'
99 last_name = 'public'
100 sex = 'F'
101 year_of_birth = 2000
102
103 reality = src.person.factory(
104 first_name=first_name,
105 last_name=last_name,
106 sex=sex,
107 year_of_birth=year_of_birth,
108 )
109 my_expectation = (
110 f'{first_name}, {last_name},'
111 f' {sex}, {year_of_birth}'
112 )
113 assert reality == my_expectation
114
115 reality = src.person.say_hi(
116 first_name=first_name,
117 last_name=last_name,
118 year_of_birth=year_of_birth,
119 )
120 my_expectation = (
121 f'Hi, my name is {first_name}'
122 f' {last_name} and I am'
123 f' {2026-year_of_birth}.'
124 )
125 assert reality == my_expectation
126
127
128# Exceptions seen
129# AssertionError
130# NameError
131# TypeError
132# AttributeError
open the project
test person factory
RED: make it fail
I add an assertion to test_joe in test_person.py
17 def test_joe():
18 assert joe() == 'joe, blow, M, 1996'
19
20 reality = factory()
21 my_expectation = 'joe, blow, M, 1996'
22 assert reality == my_expectation
23
24
25 def test_jane():
the terminal is my friend, and shows NameError
NameError: name 'factory' is not defined
because I have not defined factory in test_person.py, yet.
GREEN: make it pass
I add a function definition for it
1def factory():
2 return 'joe, blow, M, 1996'
3
4
5def joe():
the test passes.
REFACTOR: make it better
I add an assertion with a call to the factory function in test_jane
21def test_joe(): 22 assert joe() == 'joe, blow, M, 1996' 23 24 reality = factory() 25 my_expectation = 'joe, blow, M, 1996' 26 assert reality == my_expectation 27 28 29def test_jane(): 30 assert jane() == 'jane, doe, F, 1991' 31 32 reality = factory() 33 my_expectation = 'jane, doe, F, 1991' 34 assert reality == my_expectation 35 36 37def test_john():the terminal is my friend, and shows AssertionError
AssertionError: assert 'joe, blow, M, 1996' == 'jane, doe, F, 1991'because the factory function always returns
joe, blow, M, 1996when it is called. It has to return a string based on the input it gets for me to be able to use it to make more than one person.I make the function take input for the first name
1# def factory(): 2def factory(first_name): 3 return 'joe, blow, M, 1996'the terminal is my friend, and shows TypeError
TypeError: factory() missing 1 required positional argument: 'first_name'because
I called the factory function with zero inputs.
The function definition (signature) of
factoryhas one required argument (first_name).I am violating the function signature when I call it in a way that it was not designed to be called, which raises TypeError.
I add
'jane'to the call to the factory function in test_jane30def test_jane(): 31 assert jane() == 'jane, doe, F, 1991' 32 33 # reality = factory() 34 reality = factory('jane') 35 my_expectation = 'jane, doe, F, 1991' 36 assert reality == my_expectation 37 38 39def test_john():the terminal is my friend, and shows AssertionError
AssertionError: assert 'joe, blow, M, 1996' == 'jane, doe, F, 1991'I change the return statement of the factory function to an f-string to use
first_namein the output1# def factory(): 2def factory(first_name): 3 # return 'joe, blow, M, 1996' 4 return f'{first_name}, blow, M, 1996' 5 6 7def joe():the terminal is my friend, and shows AssertionError
AssertionError: assert 'jane, blow, M, 1996' == 'jane, doe, F, 1991'the first names match. Progress!
I add
last_nameto the return statement1# def factory(): 2def factory(first_name): 3 # return 'joe, blow, M, 1996' 4 # return f'{first_name}, blow, M, 1996' 5 return ( 6 f'{first_name}, {last_name},' 7 ' M, 1996' 8 ) 9 10 11def joe():the terminal is my friend, and shows NameError
NameError: name 'last_name' is not definedI add the name to the parentheses to define it in the factory function
1# def factory(): 2# def factory(first_name): 3def factory(first_name, last_name): 4 # return 'joe, blow, M, 1996' 5 # return f'{first_name}, blow, M, 1996' 6 return ( 7 f'{first_name}, {last_name},' 8 ' M, 1996' 9 ) 10 11 12def joe():the terminal is my friend, and shows TypeError
TypeError: factory() missing 1 required positional argument: 'last_name'because
I called the factory function with one input (
jane).The function definition (signature) of
factoryhas two required arguments (first_nameandlast_name).I am violating the function signature when I call it in a way that it was not designed to be called, which raises TypeError.
I add
'doe'to the call to the factory function in test_jane36def test_jane(): 37 assert jane() == 'jane, doe, F, 1991' 38 39 # reality = factory() 40 # reality = factory('jane') 41 reality = factory('jane', 'doe') 42 my_expectation = 'jane, doe, F, 1991' 43 assert reality == my_expectation 44 45 46def test_john():the terminal is my friend, and shows AssertionError
AssertionError: assert 'jane, doe, M, 1996' == 'jane, doe, F, 1991'the first and last names match. More progress.
I use keyword arguments with a value for
sex(since I have more than two) to change the call to the factory function in test_jane36def test_jane(): 37 assert jane() == 'jane, doe, F, 1991' 38 39 # reality = factory() 40 # reality = factory('jane') 41 # reality = factory('jane', 'doe') 42 reality = factory( 43 first_name='jane', 44 last_name='doe', 45 sex='F', 46 ) 47 my_expectation = 'jane, doe, F, 1991' 48 assert reality == my_expectation 49 50 51def test_john():the terminal is my friend, and shows TypeError
TypeError: factory() got an unexpected keyword argument 'sex'because
I called the factory function with three keyword arguments input (
first_name,last_nameandsex).The function definition (signature) of
factoryhas two required arguments (first_nameandlast_name).I am violating the function signature when I call it in a way that it was not designed to be called, which raises TypeError.
I add
sexin the parentheses of thefactoryfunction definition1# def factory(): 2# def factory(first_name): 3# def factory(first_name, last_name): 4def factory(first_name, last_name, sex): 5 # return 'joe, blow, M, 1996' 6 # return f'{first_name}, blow, M, 1996' 7 return ( 8 f'{first_name}, {last_name},' 9 ' M, 1996' 10 ) 11 12 13def joe():the terminal shows the last AssertionError again.
I add
sexto the f-string in the factory function1# def factory(): 2# def factory(first_name): 3# def factory(first_name, last_name): 4def factory(first_name, last_name, sex): 5 # return 'joe, blow, M, 1996' 6 # return f'{first_name}, blow, M, 1996' 7 return ( 8 f'{first_name}, {last_name},' 9 # ' M, 1996' 10 f' {sex}, 1996' 11 ) 12 13 14def joe():the terminal is my friend, and shows AssertionError
AssertionError: assert 'jane, doe, F, 1996' == 'jane, doe, F, 1991'the first name, last name and sex match. Yes!
I add
year_of_birthto the return statement1# def factory(): 2# def factory(first_name): 3# def factory(first_name, last_name): 4def factory(first_name, last_name, sex): 5 # return 'joe, blow, M, 1996' 6 # return f'{first_name}, blow, M, 1996' 7 return ( 8 f'{first_name}, {last_name},' 9 # ' M, 1996' 10 # f' {sex}, 1996' 11 f' {sex}, {year_of_birth}' 12 ) 13 14 15def joe():the terminal is my friend, and shows NameError
NameError: name 'year_of_birth' is not definedI add
year_of_birthto the parentheses to define it in the factory function1# def factory(): 2# def factory(first_name): 3# def factory(first_name, last_name): 4# def factory(first_name, last_name, sex): 5def factory( 6 first_name, last_name, 7 sex, year_of_birth 8): 9 # return 'joe, blow, M, 1996' 10 # return f'{first_name}, blow, M, 1996' 11 return ( 12 f'{first_name}, {last_name},' 13 # ' M, 1996' 14 # f' {sex}, 1996' 15 f' {sex}, {year_of_birth}' 16 ) 17 18 19def joe():the terminal is my friend, and shows TypeError
TypeError: factory() missing 1 required positional argument: 'year_of_birth'because
I called the factory function with three keyword arguments (
first_name,last_nameandsex).The function definition (signature) of
factoryhas four required arguments (first_name,last_name,sexandyear_of_birth).I am violating the function signature when I call it in a way that it was not designed to be called, which raises TypeError.
I add
year_of_birth=1996to the call to the factory function in test_jane43def test_jane(): 44 assert jane() == 'jane, doe, F, 1991' 45 46 # reality = factory() 47 # reality = factory('jane') 48 # reality = factory('jane', 'doe') 49 reality = factory( 50 first_name='jane', 51 last_name='doe', 52 sex='F', 53 year_of_birth=1991, 54 ) 55 my_expectation = 'jane, doe, F, 1991' 56 assert reality == my_expectation 57 58 59def test_john():the terminal is my friend, and shows TypeError
TypeError: factory() missing 4 required positional arguments: 'first_name', 'last_name', 'sex', and 'year_of_birth'because
I called in test_joe the factory function with zero arguments.
The function definition (signature) of
factoryhas four required arguments (first_name,last_name,sexandyear_of_birth).I am violating the function signature when I call it in a way that it was not designed to be called, which raises TypeError.
Since there are more than two, I add keyword arguments to the call to the factory function in test_joe
35def test_joe(): 36 assert joe() == 'joe, blow, M, 1996' 37 38 # reality = factory() 39 reality = factory( 40 first_name='joe', 41 last_name='blow', 42 sex='M', 43 year_of_birth=1996, 44 ) 45 my_expectation = 'joe, blow, M, 1996' 46 assert reality == my_expectation 47 48 49def test_jane():the test passes and I have one function that I can use to make any number of people.
I remove the commented lines from the factory function
1def factory( 2 first_name, last_name, 3 sex, year_of_birth 4): 5 return ( 6 f'{first_name}, {last_name},' 7 f' {sex}, {year_of_birth}' 8 ) 9 10 11def joe():I comment out the call to
joein test_joe because I no longer need it since the factory function does the same thing27def test_joe(): 28 # assert joe() == 'joe, blow, M, 1996' 29 30 reality = factory( 31 first_name='joe', 32 last_name='blow', 33 sex='M', 34 year_of_birth=1996, 35 ) 36 my_expectation = 'joe, blow, M, 1996' 37 assert reality == my_expectation 38 39 40def test_jane():I add a variable for
'joe'in test_joe27def test_joe(): 28 # assert joe() == 'joe, blow, M, 1996' 29 first_name = 'joe' 30 31 reality = factory( 32 first_name='joe', 33 last_name='blow', 34 sex='M', 35 year_of_birth=1996, 36 ) 37 my_expectation = 'joe, blow, M, 1996' 38 assert reality == my_expectation 39 40 41def test_jane():I use the variable to remove repetition of
'joe'27def test_joe(): 28 # assert joe() == 'joe, blow, M, 1996' 29 first_name = 'joe' 30 31 reality = factory( 32 # first_name='joe', 33 first_name=first_name, 34 last_name='blow', 35 sex='M', 36 year_of_birth=1996, 37 ) 38 # my_expectation = 'joe, blow, M, 1996' 39 my_expectation = ( 40 f'{first_name}, blow,' 41 ' M, 1996' 42 ) 43 assert reality == my_expectation 44 45 46def test_jane():the test is still green.
I add a variable for
'blow'in test_joe27def test_joe(): 28 # assert joe() == 'joe, blow, M, 1996' 29 first_name = 'joe' 30 last_name = 'blow' 31 32 reality = factory( 33 # first_name='joe', 34 first_name=first_name, 35 last_name='blow', 36 sex='M', 37 year_of_birth=1996, 38 ) 39 # my_expectation = 'joe, blow, M, 1996' 40 my_expectation = ( 41 f'{first_name}, blow,' 42 ' M, 1996' 43 ) 44 assert reality == my_expectation 45 46 47def test_jane():I use the variable to remove repetition of
'blow'27def test_joe(): 28 # assert joe() == 'joe, blow, M, 1996' 29 first_name = 'joe' 30 last_name = 'blow' 31 32 reality = factory( 33 # first_name='joe', 34 first_name=first_name, 35 # last_name='blow', 36 last_name=last_name, 37 sex='M', 38 year_of_birth=1996, 39 ) 40 # my_expectation = 'joe, blow, M, 1996' 41 my_expectation = ( 42 # f'{first_name}, blow,' 43 f'{first_name}, {last_name},' 44 ' M, 1996' 45 ) 46 assert reality == my_expectation 47 48 49def test_jane():still green.
I add a variable for
'M'in test_joe27def test_joe(): 28 # assert joe() == 'joe, blow, M, 1996' 29 first_name = 'joe' 30 last_name = 'blow' 31 sex = 'M' 32 33 reality = factory( 34 # first_name='joe', 35 first_name=first_name, 36 # last_name='blow', 37 last_name=last_name, 38 sex='M', 39 year_of_birth=1996, 40 )I use the variable to remove repetition of
'M'27def test_joe(): 28 # assert joe() == 'joe, blow, M, 1996' 29 first_name = 'joe' 30 last_name = 'blow' 31 sex = 'M' 32 33 reality = factory( 34 # first_name='joe', 35 first_name=first_name, 36 # last_name='blow', 37 last_name=last_name, 38 # sex='M', 39 sex=sex, 40 year_of_birth=1996, 41 ) 42 # my_expectation = 'joe, blow, M, 1996' 43 my_expectation = ( 44 # f'{first_name}, blow,' 45 f'{first_name}, {last_name},' 46 # ' M, 1996' 47 f' {sex}, 1996' 48 ) 49 assert reality == my_expectation 50 51 52def test_jane():green.
I add a variable for
1996in test_joe27def test_joe(): 28 # assert joe() == 'joe, blow, M, 1996' 29 first_name = 'joe' 30 last_name = 'blow' 31 sex = 'M' 32 year_of_birth = 1996 33 34 reality = factory( 35 # first_name='joe', 36 first_name=first_name, 37 # last_name='blow', 38 last_name=last_name, 39 # sex='M', 40 sex=sex, 41 year_of_birth=1996, 42 )I use the variable to remove repetition of
199627def test_joe(): 28 # assert joe() == 'joe, blow, M, 1996' 29 first_name = 'joe' 30 last_name = 'blow' 31 sex = 'M' 32 year_of_birth = 1996 33 34 reality = factory( 35 # first_name='joe', 36 first_name=first_name, 37 # last_name='blow', 38 last_name=last_name, 39 # sex='M', 40 sex=sex, 41 # year_of_birth=1996, 42 year_of_birth=year_of_birth, 43 ) 44 # my_expectation = 'joe, blow, M, 1996' 45 my_expectation = ( 46 # f'{first_name}, blow,' 47 f'{first_name}, {last_name},' 48 # ' M, 1996' 49 # f' {sex}, 1996' 50 f' {sex}, {year_of_birth}' 51 ) 52 assert reality == my_expectation 53 54 55def test_jane():still green.
I remove the commented lines
27def test_joe(): 28 first_name = 'joe' 29 last_name = 'blow' 30 sex = 'M' 31 year_of_birth = 1996 32 33 reality = factory( 34 first_name=first_name, 35 last_name=last_name, 36 sex=sex, 37 year_of_birth=year_of_birth, 38 ) 39 my_expectation = ( 40 f'{first_name}, {last_name},' 41 f' {sex}, {year_of_birth}' 42 ) 43 assert reality == my_expectation 44 45 46def test_jane():
I comment out the call to
janein test_jane because I no longer need it since the factory function does the same thing46def test_jane(): 47 # assert jane() == 'jane, doe, F, 1991' 48 49 # reality = factory()I add a variable for
'jane'in test_jane46def test_jane(): 47 # assert jane() == 'jane, doe, F, 1991' 48 first_name = 'jane' 49 50 # reality = factory()I use the variable to remove repetition of
'jane'46def test_jane(): 47 # assert jane() == 'jane, doe, F, 1991' 48 first_name = 'jane' 49 50 # reality = factory() 51 # reality = factory('jane') 52 # reality = factory('jane', 'doe') 53 reality = factory( 54 # first_name='jane', 55 first_name=first_name, 56 last_name='doe', 57 sex='F', 58 year_of_birth=1991, 59 ) 60 # my_expectation = 'jane, doe, F, 1991' 61 my_expectation = ( 62 f'{first_name}, doe,' 63 ' F, 1991' 64 ) 65 assert reality == my_expectation 66 67 68def test_john():the test is still green.
I add a variable for
'doe'in test_jane46def test_jane(): 47 # assert jane() == 'jane, doe, F, 1991' 48 first_name = 'jane' 49 last_name = 'doe' 50 51 # reality = factory()I use the variable to remove repetition of
'doe'46def test_jane(): 47 # assert jane() == 'jane, doe, F, 1991' 48 first_name = 'jane' 49 last_name = 'doe' 50 51 # reality = factory() 52 # reality = factory('jane') 53 # reality = factory('jane', 'doe') 54 reality = factory( 55 # first_name='jane', 56 first_name=first_name, 57 # last_name='doe', 58 last_name=last_name, 59 sex='F', 60 year_of_birth=1991, 61 ) 62 # my_expectation = 'jane, doe, F, 1991' 63 my_expectation = ( 64 # f'{first_name}, doe,' 65 f'{first_name}, {last_name},' 66 ' F, 1991' 67 ) 68 assert reality == my_expectation 69 70 71def test_john():still green.
I add a variable for
'F'in test_jane46def test_jane(): 47 # assert jane() == 'jane, doe, F, 1991' 48 first_name = 'jane' 49 last_name = 'doe' 50 sex = 'F' 51 52 # reality = factory()I use the variable to remove repetition of
'F'46def test_jane(): 47 # assert jane() == 'jane, doe, F, 1991' 48 first_name = 'jane' 49 last_name = 'doe' 50 sex = 'F' 51 52 # reality = factory() 53 # reality = factory('jane') 54 # reality = factory('jane', 'doe') 55 reality = factory( 56 # first_name='jane', 57 first_name=first_name, 58 # last_name='doe', 59 last_name=last_name, 60 # sex='F', 61 sex=sex, 62 year_of_birth=1991, 63 ) 64 # my_expectation = 'jane, doe, F, 1991' 65 my_expectation = ( 66 # f'{first_name}, doe,' 67 f'{first_name}, {last_name},' 68 # ' F, 1991' 69 f' {sex}, 1991' 70 ) 71 assert reality == my_expectation 72 73 74def test_john():green.
I add a variable for
1991in test_jane46def test_jane(): 47 # assert jane() == 'jane, doe, F, 1991' 48 first_name = 'jane' 49 last_name = 'doe' 50 sex = 'F' 51 year_of_birth = 1991 52 53 # reality = factory()I use the variable to remove repetition of
199146def test_jane(): 47 # assert jane() == 'jane, doe, F, 1991' 48 first_name = 'jane' 49 last_name = 'doe' 50 sex = 'F' 51 year_of_birth = 1991 52 53 # reality = factory() 54 # reality = factory('jane') 55 # reality = factory('jane', 'doe') 56 reality = factory( 57 # first_name='jane', 58 first_name=first_name, 59 # last_name='doe', 60 last_name=last_name, 61 # sex='F', 62 sex=sex, 63 # year_of_birth=1991, 64 year_of_birth=year_of_birth, 65 ) 66 # my_expectation = 'jane, doe, F, 1991' 67 my_expectation = ( 68 # f'{first_name}, doe,' 69 f'{first_name}, {last_name},' 70 # ' F, 1991' 71 # f' {sex}, 1991' 72 f' {sex}, {year_of_birth}' 73 ) 74 assert reality == my_expectation 75 76 77def test_john():still green.
I remove the commented lines
46def test_jane(): 47 first_name = 'jane' 48 last_name = 'doe' 49 sex = 'F' 50 year_of_birth = 1991 51 52 reality = factory( 53 first_name=first_name, 54 last_name=last_name, 55 sex=sex, 56 year_of_birth=year_of_birth, 57 ) 58 my_expectation = ( 59 f'{first_name}, {last_name},' 60 f' {sex}, {year_of_birth}' 61 ) 62 assert reality == my_expectation 63 64 65def test_john():
I change the call in test_john to a call to the factory function
65def test_john(): 66 # assert john() == 'john, smith, M, 1580' 67 reality = factory( 68 first_name='john', 69 last_name='smith', 70 sex='M', 71 year_of_birth=1580, 72 ) 73 my_expectation = 'jane, doe, F, 1991' 74 assert reality == my_expectation 75 76 77def test_mary():the terminal is my friend, and shows AssertionError
AssertionError: assert 'john, smith, M, 1580' == 'jane, doe, F, 1991'I change
my_expectationto matchreality65def test_john(): 66 # assert john() == 'john, smith, M, 1580' 67 reality = factory( 68 first_name='john', 69 last_name='smith', 70 sex='M', 71 year_of_birth=1580, 72 ) 73 # my_expectation = 'jane, doe, F, 1991' 74 my_expectation = 'john, smith, M, 1580' 75 assert reality == my_expectation 76 77 78def test_mary():the test passes.
I add a variable for
'john'in test_john65def test_john(): 66 # assert john() == 'john, smith, M, 1580' 67 first_name = 'john' 68 69 reality = factory( 70 first_name='john', 71 last_name='smith', 72 sex='M', 73 year_of_birth=1580, 74 ) 75 # my_expectation = 'jane, doe, F, 1991' 76 my_expectation = 'john, smith, M, 1580' 77 assert reality == my_expectation 78 79 80def test_mary():I use the variable to remove repetition of
'john'65def test_john(): 66 # assert john() == 'john, smith, M, 1580' 67 first_name = 'john' 68 69 reality = factory( 70 # first_name='john', 71 first_name=first_name, 72 last_name='smith', 73 sex='M', 74 year_of_birth=1580, 75 ) 76 # my_expectation = 'jane, doe, F, 1991' 77 # my_expectation = 'john, smith, M, 1580' 78 my_expectation = ( 79 f'{first_name}, smith,' 80 ' M, 1580' 81 ) 82 assert reality == my_expectation 83 84 85def test_mary():the test is still green.
I add a variable for
'smith'in test_john65def test_john(): 66 # assert john() == 'john, smith, M, 1580' 67 first_name = 'john' 68 last_name = 'smith'I use the variable to remove repetition of
'smith'65def test_john(): 66 # assert john() == 'john, smith, M, 1580' 67 first_name = 'john' 68 last_name = 'smith' 69 70 reality = factory( 71 # first_name='john', 72 first_name=first_name, 73 # last_name='smith', 74 last_name=last_name, 75 sex='M', 76 year_of_birth=1580, 77 ) 78 # my_expectation = 'jane, doe, F, 1991' 79 # my_expectation = 'john, smith, M, 1580' 80 my_expectation = ( 81 # f'{first_name}, smith,' 82 f'{first_name}, {last_name},' 83 ' M, 1580' 84 ) 85 assert reality == my_expectation 86 87 88def test_mary():still green.
I add a variable for
'M'in test_john65def test_john(): 66 # assert john() == 'john, smith, M, 1580' 67 first_name = 'john' 68 last_name = 'smith' 69 sex = 'M'I use the variable to remove repetition of
'M'65def test_john(): 66 # assert john() == 'john, smith, M, 1580' 67 first_name = 'john' 68 last_name = 'smith' 69 sex = 'M' 70 71 reality = factory( 72 # first_name='john', 73 first_name=first_name, 74 # last_name='smith', 75 last_name=last_name, 76 # sex='M', 77 sex=sex, 78 year_of_birth=1580, 79 ) 80 # my_expectation = 'jane, doe, F, 1991' 81 # my_expectation = 'john, smith, M, 1580' 82 my_expectation = ( 83 # f'{first_name}, smith,' 84 f'{first_name}, {last_name},' 85 # ' M, 1580' 86 f' {sex}, 1580' 87 ) 88 assert reality == my_expectation 89 90 91def test_mary():green.
I add a variable for
1580in test_john65def test_john(): 66 # assert john() == 'john, smith, M, 1580' 67 first_name = 'john' 68 last_name = 'smith' 69 sex = 'M' 70 year_of_birth = 1580I use the variable to remove repetition of
158065def test_john(): 66 # assert john() == 'john, smith, M, 1580' 67 first_name = 'john' 68 last_name = 'smith' 69 sex = 'M' 70 year_of_birth = 1580 71 72 reality = factory( 73 # first_name='john', 74 first_name=first_name, 75 # last_name='smith', 76 last_name=last_name, 77 # sex='M', 78 sex=sex, 79 # year_of_birth=1580, 80 year_of_birth=year_of_birth, 81 ) 82 # my_expectation = 'jane, doe, F, 1991' 83 # my_expectation = 'john, smith, M, 1580' 84 my_expectation = ( 85 # f'{first_name}, smith,' 86 f'{first_name}, {last_name},' 87 # ' M, 1580' 88 # f' {sex}, 1580' 89 f' {sex}, {year_of_birth}' 90 ) 91 assert reality == my_expectation 92 93 94def test_mary():still green.
I remove the commented lines
65def test_john(): 66 first_name = 'john' 67 last_name = 'smith' 68 sex = 'M' 69 year_of_birth = 1580 70 71 reality = factory( 72 first_name=first_name, 73 last_name=last_name, 74 sex=sex, 75 year_of_birth=year_of_birth, 76 ) 77 my_expectation = ( 78 f'{first_name}, {last_name},' 79 f' {sex}, {year_of_birth}' 80 ) 81 assert reality == my_expectation 82 83 84def test_mary():I make the same change to test_mary
84def test_mary(): 85 # assert mary() == 'mary, public, F, 2000' 86 first_name = 'mary' 87 last_name = 'public' 88 sex = 'F' 89 year_of_birth = 2000 90 91 reality = factory( 92 first_name=first_name, 93 last_name=last_name, 94 sex=sex, 95 year_of_birth=year_of_birth, 96 ) 97 my_expectation = ( 98 f'{first_name}, {last_name},' 99 f' {sex}, {year_of_birth}' 100 ) 101 assert reality == my_expectation 102 103 104# Exceptions seenthe test is still green.
I remove the commented line
84def test_mary(): 85 first_name = 'mary' 86 last_name = 'public' 87 sex = 'F' 88 year_of_birth = 2000 89 90 reality = factory( 91 first_name=first_name, 92 last_name=last_name, 93 sex=sex, 94 year_of_birth=year_of_birth, 95 ) 96 my_expectation = ( 97 f'{first_name}, {last_name},' 98 f' {sex}, {year_of_birth}' 99 ) 100 assert reality == my_expectation 101 102 103# Exceptions seenI remove the
joe,jane,johnandmaryfunctions because they are no longer used1def factory( 2 first_name, last_name, 3 sex, year_of_birth 4): 5 return ( 6 f'{first_name}, {last_name},' 7 f' {sex}, {year_of_birth}' 8 ) 9 10 11def test_joe():the factory function can make a string for any person I want when I give it the first name, last name, sex and year of birth.
I open a new terminal then change directories to
personcd personI add a git commit message in the new terminal
git commit -am 'extract factory function'
separate and equal factory
RED: make it fail
I go back to the terminal where the tests are running
I change
realityfor test_joe to be the result of a call to the factory function of thepersonmodule in thesrcfolder instead of a call to the factory function intest_person.py11def test_joe(): 12 first_name = 'joe' 13 last_name = 'blow' 14 sex = 'M' 15 year_of_birth = 1996 16 17 # reality = factory( 18 reality = src.person.factory( 19 first_name=first_name, 20 last_name=last_name, 21 sex=sex, 22 year_of_birth=year_of_birth, 23 ) 24 my_expectation = ( 25 f'{first_name}, {last_name},' 26 f' {sex}, {year_of_birth}' 27 ) 28 assert reality == my_expectation 29 30 31def test_jane():the terminal is my friend, and shows NameError
NameError: name 'src' is notbecause
srcis not defined intest_person.py
GREEN: make it pass
I add an import statement at the top of
test_person.py1import src.person 2 3 4def factory( 5 first_name, last_name, 6 sex, year_of_birth 7):the terminal is my friend, and shows AttributeError
AttributeError: module 'src.person' has no attribute 'factory'because there is nothing named
factoryinperson.pyin thesrcfolder.I add AttributeError to the list of Exceptions seen
90# Exceptions seen 91# AssertionError 92# NameError 93# TypeError 94# AttributeErrorI open
person.pyfrom thesrcfolderI delete all the text in the file then add a copy of the factory function to
person.py1def factory( 2 first_name, last_name, 3 sex, year_of_birth 4): 5 return ( 6 f'{first_name}, {last_name},' 7 f' {sex}, {year_of_birth}' 8 )the test passes because
when
import src.personruns, Python brings in an object for theperson.pyfile from thesrcfolder so I can use it intest_person.pyassrc.personwhen
src.person.factoryis called, Python calls the factory function from the object it imported for theperson.pyfile from thesrcfolder (src.person)
I think of
src.person.factorylike an addressfactoryis something inperson, in this case it is a function inpersonpersonis something insrc, in this case it isperson.py(a module) in thesrcfoldersrcis something Python can import (a module, Python package or folder)src └── person.py └── def factory( first_name, last_name, sex, year_of_birth ): return ( f'{first_name}, {last_name},' f' {sex}, {year_of_birth}' )
REFACTOR: make it better
I remove the commented line from test_joe in
test_person.py14def test_joe(): 15 first_name = 'joe' 16 last_name = 'blow' 17 sex = 'M' 18 year_of_birth = 1996 19 20 reality = src.person.factory( 21 first_name=first_name, 22 last_name=last_name, 23 sex=sex, 24 year_of_birth=year_of_birth, 25 ) 26 my_expectation = ( 27 f'{first_name}, {last_name},' 28 f' {sex}, {year_of_birth}' 29 ) 30 assert reality == my_expectation 31 32 33def test_jane():I change
realityfor test_jane to be the result of a call to the factory function of thepersonmodule in thesrcfolder33def test_jane(): 34 first_name = 'jane' 35 last_name = 'doe' 36 sex = 'F' 37 year_of_birth = 1991 38 39 # reality = factory( 40 reality = src.person.factory( 41 first_name=first_name, 42 last_name=last_name, 43 sex=sex, 44 year_of_birth=year_of_birth, 45 ) 46 my_expectation = ( 47 f'{first_name}, {last_name},' 48 f' {sex}, {year_of_birth}' 49 ) 50 assert reality == my_expectation 51 52 53def test_john():the test is still green.
I remove the commented line from test_jane
33def test_jane(): 34 first_name = 'jane' 35 last_name = 'doe' 36 sex = 'F' 37 year_of_birth = 1991 38 39 reality = src.person.factory( 40 first_name=first_name, 41 last_name=last_name, 42 sex=sex, 43 year_of_birth=year_of_birth, 44 ) 45 my_expectation = ( 46 f'{first_name}, {last_name},' 47 f' {sex}, {year_of_birth}' 48 ) 49 assert reality == my_expectation 50 51 52def test_john():I change
realityfor test_john to be the result of a call to the factory function of thepersonmodule in thesrcfolder52def test_john(): 53 first_name = 'john' 54 last_name = 'smith' 55 sex = 'M' 56 year_of_birth = 1580 57 58 # reality = factory( 59 reality = src.person.factory( 60 first_name=first_name, 61 last_name=last_name, 62 sex=sex, 63 year_of_birth=year_of_birth, 64 ) 65 my_expectation = ( 66 f'{first_name}, {last_name},' 67 f' {sex}, {year_of_birth}' 68 ) 69 assert reality == my_expectation 70 71 72def test_mary():still green.
I remove the commented line
52def test_john(): 53 first_name = 'john' 54 last_name = 'smith' 55 sex = 'M' 56 year_of_birth = 1580 57 58 reality = src.person.factory( 59 first_name=first_name, 60 last_name=last_name, 61 sex=sex, 62 year_of_birth=year_of_birth, 63 ) 64 my_expectation = ( 65 f'{first_name}, {last_name},' 66 f' {sex}, {year_of_birth}' 67 ) 68 assert reality == my_expectation 69 70 71def test_mary():I do the same thing to the call to the factory function in test_mary
71def test_mary(): 72 first_name = 'mary' 73 last_name = 'public' 74 sex = 'F' 75 year_of_birth = 2000 76 77 # reality = factory( 78 reality = src.person.factory( 79 first_name=first_name, 80 last_name=last_name, 81 sex=sex, 82 year_of_birth=year_of_birth, 83 ) 84 my_expectation = ( 85 f'{first_name}, {last_name},' 86 f' {sex}, {year_of_birth}' 87 ) 88 assert reality == my_expectation 89 90 91# Exceptions seengreen.
I remove the commented line
71def test_mary(): 72 first_name = 'mary' 73 last_name = 'public' 74 sex = 'F' 75 year_of_birth = 2000 76 77 reality = src.person.factory( 78 first_name=first_name, 79 last_name=last_name, 80 sex=sex, 81 year_of_birth=year_of_birth, 82 ) 83 my_expectation = ( 84 f'{first_name}, {last_name},' 85 f' {sex}, {year_of_birth}' 86 ) 87 assert reality == my_expectation 88 89 90# Exceptions seen 91# AssertionError 92# NameError 93# TypeError 94# AttributeErrorI remove the factory function from
test_person.py1import src.person 2 3 4def test_joe(): 5 first_name = 'joe' 6 last_name = 'blow' 7 sex = 'M' 8 year_of_birth = 1996 9 10 reality = src.person.factory( 11 first_name=first_name, 12 last_name=last_name, 13 sex=sex, 14 year_of_birth=year_of_birth, 15 ) 16 my_expectation = ( 17 f'{first_name}, {last_name},' 18 f' {sex}, {year_of_birth}' 19 ) 20 assert reality == my_expectation 21 22 23def test_jane():all the tests are still green because the calls that were made to the factory function that was in
test_person.pyare now to the factory function inperson.pyin thesrcfolder. Whensrc.person.factoryis called, Python follows this pathsrc └── person.py └── def factory( first_name, last_name, sex, year_of_birth ): return ( f'{first_name}, {last_name},' f' {sex}, {year_of_birth}' )I add a git commit message in the other terminal
git commit -am \ 'move factory function to person.py'the terminal shows a summary of the changes then goes back to the command line.
test say_hi
I want the person I make to say hi. I can make a function that takes input about a person and returns a message.
RED: make it fail
I add an assertion to test_joe in
test_person.py1import src.person 2 3 4def test_joe(): 5 first_name = 'joe' 6 last_name = 'blow' 7 sex = 'M' 8 year_of_birth = 1996 9 10 reality = src.person.factory( 11 first_name=first_name, 12 last_name=last_name, 13 sex=sex, 14 year_of_birth=year_of_birth, 15 ) 16 my_expectation = ( 17 f'{first_name}, {last_name},' 18 f' {sex}, {year_of_birth}' 19 ) 20 assert reality == my_expectation 21 22 reality = say_hi( 23 first_name=first_name, 24 last_name=last_name, 25 year_of_birth=year_of_birth, 26 ) 27 my_expectation = ( 28 f'Hi, my name is {first_name}' 29 f' {last_name} and I am' 30 f' {2026-year_of_birth}.' 31 ) 32 assert reality == my_expectation 33 34 35def test_jane():the terminal is my friend, and shows NameError
NameError: name 'say_hi' is not defined
GREEN: make it pass
I add a function definition for it
1import src.person 2 3 4def say_hi(): 5 return None 6 7 8def test_joe():the terminal is my friend, and shows TypeError
TypeError: say_hi() got an unexpected keyword argument 'first_name'because
I called the say_hi function with three keyword arguments (
first_name,last_nameandyear_of_birth).The function definition (signature) of
factoryallows zero input, because the parentheses are empty.I am violating the function signature when I call it in a way that it was not designed to be called, which raises TypeError.
I add
first_namein parentheses4# def say_hi(): 5def say_hi(first_name): 6 return None 7 8 9def test_joe():the terminal is my friend, and shows TypeError
TypeError: say_hi() got an unexpected keyword argument 'last_name'. Did you mean 'first_name'?I add
last_namein parentheses4# def say_hi(): 5# def say_hi(first_name): 6def say_hi(first_name, last_name): 7 return None 8 9 10def test_joe():the terminal is my friend, and shows TypeError
TypeError: say_hi() got an unexpected keyword argument 'year_of_birth'because
I called the say_hi function with three keyword arguments (
first_name,last_nameandyear_of_birth).The function definition (signature) of
factoryallows two arguments (first_name,last_name).I am violating the function signature when I call it in a way that it was not designed to be called, which raises TypeError.
I add
year_of_birthin parentheses4# def say_hi(): 5# def say_hi(first_name): 6# def say_hi(first_name, last_name): 7def say_hi( 8 first_name, last_name, 9 year_of_birth 10): 11 return None 12 13 14def test_joe():the terminal is my friend, and shows AssertionError
AssertionError: assert None == 'Hi, my name is joe blow and I am 30.'I change the return statement to give the test what it wants
4# def say_hi(): 5# def say_hi(first_name): 6# def say_hi(first_name, last_name): 7def say_hi( 8 first_name, last_name, 9 year_of_birth 10): 11 # return None 12 return 'Hi, my name is joe blow and I am 30.' 13 14 15def test_joe():the test passes.
REFACTOR: make it better
I add an assertion for the say_hi function to test_jane in
test_person.py46def test_jane(): 47 first_name = 'jane' 48 last_name = 'doe' 49 sex = 'F' 50 year_of_birth = 1991 51 52 reality = src.person.factory( 53 first_name=first_name, 54 last_name=last_name, 55 sex=sex, 56 year_of_birth=year_of_birth, 57 ) 58 my_expectation = ( 59 f'{first_name}, {last_name},' 60 f' {sex}, {year_of_birth}' 61 ) 62 assert reality == my_expectation 63 64 reality = say_hi( 65 first_name=first_name, 66 last_name=last_name, 67 year_of_birth=year_of_birth, 68 ) 69 my_expectation = ( 70 f'Hi, my name is {first_name}' 71 f' {last_name} and I am' 72 f' {2026-year_of_birth}.' 73 ) 74 assert reality == my_expectation 75 76 77def test_john():the terminal is my friend, and shows AssertionError
AssertionError: assert 'Hi, my name ... and I am 30.' == 'Hi, my name ... and I am 35.'because the say_hi function always returns
'Hi, my name is joe blow and I am 30.'when it is called. It has to return a string based on the input it gets for me to be able to use it to make messages based on the person.I need better error messages.
I change the return statement of the say_hi function to an f-string to use
first_namein the output4# def say_hi(): 5# def say_hi(first_name): 6# def say_hi(first_name, last_name): 7def say_hi( 8 first_name, last_name, 9 year_of_birth 10): 11 # return None 12 # return 'Hi, my name is joe blow and I am 30.' 13 return ( 14 f'Hi, my name is {first_name}' 15 ' blow and I am 30.' 16 ) 17 18 19def test_joe():the terminal shows AssertionError
AssertionError: assert 'Hi, my name ... and I am 30.' == 'Hi, my name ... and I am 35.'the first names now match and I still need better error messages.
I add
last_nameto the return statement4# def say_hi(): 5# def say_hi(first_name): 6# def say_hi(first_name, last_name): 7def say_hi( 8 first_name, last_name, 9 year_of_birth 10): 11 # return None 12 # return 'Hi, my name is joe blow and I am 30.' 13 return ( 14 f'Hi, my name is {first_name}' 15 # ' blow and I am 30.' 16 f' {last_name} and I am 30.' 17 ) 18 19 20def test_joe():the terminal shows AssertionError
AssertionError: assert 'Hi, my name ... and I am 30.' == 'Hi, my name ... and I am 35.'the ages are different.
I add the age calculation to the return statement
4# def say_hi(): 5# def say_hi(first_name): 6# def say_hi(first_name, last_name): 7def say_hi( 8 first_name, last_name, 9 year_of_birth 10): 11 # return None 12 # return 'Hi, my name is joe blow and I am 30.' 13 age = 2026 - year_of_birth 14 15 return ( 16 f'Hi, my name is {first_name}' 17 # ' blow and I am 30.' 18 # f' {last_name} and I am 30.' 19 f' {last_name} and I am {age}.' 20 ) 21 22 23def test_joe():the test passes.
I add an assertion for the say_hi function to test_john in
test_person.py85def test_john(): 86 first_name = 'john' 87 last_name = 'smith' 88 sex = 'M' 89 year_of_birth = 1580 90 91 reality = src.person.factory( 92 first_name=first_name, 93 last_name=last_name, 94 sex=sex, 95 year_of_birth=year_of_birth, 96 ) 97 my_expectation = ( 98 f'{first_name}, {last_name},' 99 f' {sex}, {year_of_birth}' 100 ) 101 assert reality == my_expectation 102 103 reality = say_hi( 104 first_name=first_name, 105 last_name=last_name, 106 year_of_birth=year_of_birth, 107 ) 108 my_expectation = ( 109 'Hi, my name is jane' 110 f' {last_name} and I am' 111 f' {2026-year_of_birth}.' 112 ) 113 assert reality == my_expectation 114 115 116def test_mary():the terminal is my friend, and shows AssertionError
AssertionError: assert 'Hi, my name ...and I am 446.' == 'Hi, my name ...and I am 446.'The first names are different.
I want more detail in the error messages.
I change
my_expectationto matchrealityin test_john103 reality = say_hi( 104 first_name=first_name, 105 last_name=last_name, 106 year_of_birth=year_of_birth, 107 ) 108 my_expectation = ( 109 # 'Hi, my name is jane' 110 f'Hi, my name is {first_name}' 111 f' {last_name} and I am' 112 f' {2026-year_of_birth}.' 113 ) 114 assert reality == my_expectation 115 116 117def test_mary():the test passes.
I add an assertion for the say_hi function to test_mary
117def test_mary(): 118 first_name = 'mary' 119 last_name = 'public' 120 sex = 'F' 121 year_of_birth = 2000 122 123 reality = src.person.factory( 124 first_name=first_name, 125 last_name=last_name, 126 sex=sex, 127 year_of_birth=year_of_birth, 128 ) 129 my_expectation = ( 130 f'{first_name}, {last_name},' 131 f' {sex}, {year_of_birth}' 132 ) 133 assert reality == my_expectation 134 135 reality = say_hi( 136 first_name=first_name, 137 last_name=last_name, 138 year_of_birth=year_of_birth, 139 ) 140 my_expectation = ( 141 f'Hi, my name is {first_name}' 142 ' smith and I am' 143 f' {2026-year_of_birth}.' 144 ) 145 assert reality == my_expectation 146 147 148# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: assert 'Hi, my name ... and I am 26.' == 'Hi, my name ... and I am 26.'The last names are different.
I want better messages that show as much of the difference in the summary.
I change
my_expectationto matchrealityin test_mary135 reality = say_hi( 136 first_name=first_name, 137 last_name=last_name, 138 year_of_birth=year_of_birth, 139 ) 140 my_expectation = ( 141 f'Hi, my name is {first_name}' 142 # ' smith and I am' 143 f' {last_name} and I am' 144 f' {2026-year_of_birth}.' 145 ) 146 assert reality == my_expectation 147 148 149# Exceptions seenthe test passes.
I remove the commented line
116def test_mary(): 117 first_name = 'mary' 118 last_name = 'public' 119 sex = 'F' 120 year_of_birth = 2000 121 122 reality = src.person.factory( 123 first_name=first_name, 124 last_name=last_name, 125 sex=sex, 126 year_of_birth=year_of_birth, 127 ) 128 my_expectation = ( 129 f'{first_name}, {last_name},' 130 f' {sex}, {year_of_birth}' 131 ) 132 assert reality == my_expectation 133 134 reality = say_hi( 135 first_name=first_name, 136 last_name=last_name, 137 year_of_birth=year_of_birth, 138 ) 139 my_expectation = ( 140 f'Hi, my name is {first_name}' 141 f' {last_name} and I am' 142 f' {2026-year_of_birth}.' 143 ) 144 assert reality == my_expectation 145 146 147# Exceptions seenthe test passes because Python uses the string representation of the object in the curly braces
{ }say_hi( first_name=first_name, last_name=last_name, year_of_birth=year_of_birth, ) say_hi( first_name, last_name, year_of_birth, ) first_name = 'mary' last_name = 'public' year_of_birth = 1991 age = 2026 - year_of_birth age = 2026 - 1991 age = 35 return ( f'Hi, my name is {first_name}' f' {last_name} and I am {age}.' ) return f'Hi, my name is mary public and I am 35'
separate and equal say_hi
I change
realityto be the result of a call to the say_hi function of thepersonmodule in thesrcfolder instead of a call to the say_hi function intest_person.py117def test_mary(): 118 first_name = 'mary' 119 last_name = 'public' 120 sex = 'F' 121 year_of_birth = 2000 122 123 reality = src.person.factory( 124 first_name=first_name, 125 last_name=last_name, 126 sex=sex, 127 year_of_birth=year_of_birth, 128 ) 129 my_expectation = ( 130 f'{first_name}, {last_name},' 131 f' {sex}, {year_of_birth}' 132 ) 133 assert reality == my_expectation 134 135 # reality = say_hi( 136 reality = src.person.say_hi( 137 first_name=first_name, 138 last_name=last_name, 139 year_of_birth=year_of_birth, 140 ) 141 my_expectation = ( 142 f'Hi, my name is {first_name}' 143 # ' smith and I am' 144 f' {last_name} and I am' 145 f' {2026-year_of_birth}.' 146 ) 147 assert reality == my_expectation 148 149 150# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.person' has no attribute 'say_hi'because there is nothing named
say_hiin theperson.pyfile in thesrcfolder.I add a copy of the say_hi function without the commented lines to
person.py1def factory( 2 first_name, last_name, 3 sex, year_of_birth 4): 5 return ( 6 f'{first_name}, {last_name},' 7 f' {sex}, {year_of_birth}' 8 ) 9 10 11def say_hi( 12 first_name, last_name, 13 year_of_birth 14): 15 age = 2026 - year_of_birth 16 17 return ( 18 f'Hi, my name is {first_name}' 19 f' {last_name} and I am {age}.' 20 )the test passes.
I remove the commented lines from test_mary in
test_person.py117def test_mary(): 118 first_name = 'mary' 119 last_name = 'public' 120 sex = 'F' 121 year_of_birth = 2000 122 123 reality = src.person.factory( 124 first_name=first_name, 125 last_name=last_name, 126 sex=sex, 127 year_of_birth=year_of_birth, 128 ) 129 my_expectation = ( 130 f'{first_name}, {last_name},' 131 f' {sex}, {year_of_birth}' 132 ) 133 assert reality == my_expectation 134 135 reality = src.person.say_hi( 136 first_name=first_name, 137 last_name=last_name, 138 year_of_birth=year_of_birth, 139 ) 140 my_expectation = ( 141 f'Hi, my name is {first_name}' 142 f' {last_name} and I am' 143 f' {2026-year_of_birth}.' 144 ) 145 assert reality == my_expectation 146 147 148# Exceptions seen 149# AssertionError 150# NameError 151# TypeError 152# AttributeErrorI change
realityfor test_john to be the result of a call to the say_hi function of thepersonmodule in thesrcfolder85def test_john(): 86 first_name = 'john' 87 last_name = 'smith' 88 sex = 'M' 89 year_of_birth = 1580 90 91 reality = src.person.factory( 92 first_name=first_name, 93 last_name=last_name, 94 sex=sex, 95 year_of_birth=year_of_birth, 96 ) 97 my_expectation = ( 98 f'{first_name}, {last_name},' 99 f' {sex}, {year_of_birth}' 100 ) 101 assert reality == my_expectation 102 103 # reality = say_hi( 104 reality = src.person.say_hi( 105 first_name=first_name, 106 last_name=last_name, 107 year_of_birth=year_of_birth, 108 ) 109 my_expectation = ( 110 # 'Hi, my name is jane' 111 f'Hi, my name is {first_name}' 112 f' {last_name} and I am' 113 f' {2026-year_of_birth}.' 114 ) 115 assert reality == my_expectation 116 117 118def test_mary():the test is still green.
I remove the commented lines from test_john
85def test_john(): 86 first_name = 'john' 87 last_name = 'smith' 88 sex = 'M' 89 year_of_birth = 1580 90 91 reality = src.person.factory( 92 first_name=first_name, 93 last_name=last_name, 94 sex=sex, 95 year_of_birth=year_of_birth, 96 ) 97 my_expectation = ( 98 f'{first_name}, {last_name},' 99 f' {sex}, {year_of_birth}' 100 ) 101 assert reality == my_expectation 102 103 reality = src.person.say_hi( 104 first_name=first_name, 105 last_name=last_name, 106 year_of_birth=year_of_birth, 107 ) 108 my_expectation = ( 109 f'Hi, my name is {first_name}' 110 f' {last_name} and I am' 111 f' {2026-year_of_birth}.' 112 ) 113 assert reality == my_expectation 114 115 116def test_mary():I change
realityfor test_joe to be the result of a call to the say_hi function of thepersonmodule in thesrcfolder23def test_joe(): 24 first_name = 'joe' 25 last_name = 'blow' 26 sex = 'M' 27 year_of_birth = 1996 28 29 reality = src.person.factory( 30 first_name=first_name, 31 last_name=last_name, 32 sex=sex, 33 year_of_birth=year_of_birth, 34 ) 35 my_expectation = ( 36 f'{first_name}, {last_name},' 37 f' {sex}, {year_of_birth}' 38 ) 39 assert reality == my_expectation 40 41 # reality = say_hi( 42 reality = src.person.say_hi( 43 first_name=first_name, 44 last_name=last_name, 45 year_of_birth=year_of_birth, 46 ) 47 my_expectation = ( 48 f'Hi, my name is {first_name}' 49 f' {last_name} and I am' 50 f' {2026-year_of_birth}.' 51 ) 52 assert reality == my_expectation 53 54 55def test_jane():the test is still green.
I remove the commented line from test_joe
23def test_joe(): 24 first_name = 'joe' 25 last_name = 'blow' 26 sex = 'M' 27 year_of_birth = 1996 28 29 reality = src.person.factory( 30 first_name=first_name, 31 last_name=last_name, 32 sex=sex, 33 year_of_birth=year_of_birth, 34 ) 35 my_expectation = ( 36 f'{first_name}, {last_name},' 37 f' {sex}, {year_of_birth}' 38 ) 39 assert reality == my_expectation 40 41 reality = src.person.say_hi( 42 first_name=first_name, 43 last_name=last_name, 44 year_of_birth=year_of_birth, 45 ) 46 my_expectation = ( 47 f'Hi, my name is {first_name}' 48 f' {last_name} and I am' 49 f' {2026-year_of_birth}.' 50 ) 51 assert reality == my_expectation 52 53 54def test_jane():I change
realityfor test_jane to be the result of a call to the say_hi function of thepersonmodule in thesrcfolder54def test_jane(): 55 first_name = 'jane' 56 last_name = 'doe' 57 sex = 'F' 58 year_of_birth = 1991 59 60 reality = src.person.factory( 61 first_name=first_name, 62 last_name=last_name, 63 sex=sex, 64 year_of_birth=year_of_birth, 65 ) 66 my_expectation = ( 67 f'{first_name}, {last_name},' 68 f' {sex}, {year_of_birth}' 69 ) 70 assert reality == my_expectation 71 72 # reality = say_hi( 73 reality = src.person.say_hi( 74 first_name=first_name, 75 last_name=last_name, 76 year_of_birth=year_of_birth, 77 ) 78 my_expectation = ( 79 f'Hi, my name is {first_name}' 80 f' {last_name} and I am' 81 f' {2026-year_of_birth}.' 82 ) 83 assert reality == my_expectation 84 85 86def test_john():the test is still green.
I remove the commented line from test_jane
54def test_jane(): 55 first_name = 'jane' 56 last_name = 'doe' 57 sex = 'F' 58 year_of_birth = 1991 59 60 reality = src.person.factory( 61 first_name=first_name, 62 last_name=last_name, 63 sex=sex, 64 year_of_birth=year_of_birth, 65 ) 66 my_expectation = ( 67 f'{first_name}, {last_name},' 68 f' {sex}, {year_of_birth}' 69 ) 70 assert reality == my_expectation 71 72 reality = src.person.say_hi( 73 first_name=first_name, 74 last_name=last_name, 75 year_of_birth=year_of_birth, 76 ) 77 my_expectation = ( 78 f'Hi, my name is {first_name}' 79 f' {last_name} and I am' 80 f' {2026-year_of_birth}.' 81 ) 82 assert reality == my_expectation 83 84 85def test_john():I remove the say_hi function from
test_person.py1import src.person 2 3 4def test_joe():all the tests are still green because the calls that were made to the say_hi function that was in
test_person.pyare now to the say_hi function inperson.pyin thesrcfolder. Whensrc.person.say_hiis called, Python follows this pathsrc └── person.py └── def say_hi( first_name, last_name, year_of_birth ): age = 2026 - year_of_birth return ( f'Hi, my name is {first_name}' f' {last_name} and I am {age}.' )I add a git commit message in the other terminal
git commit -am 'add say_hi function'the terminal shows a summary of the changes then goes back to the command line.
test_person
Since the solutions are separate from the tests, I can write the programs that make the tests pass without looking at test_person.py.
RED: make it fail
I close
test_person.pyI delete all the text in
person.pyand the terminal shows 9 failures. I start with the last AttributeErrorFAILED ...::test_joe - AttributeError: module 'src.person' has no attribute 'factory' FAILED ...::test_jane - AttributeError: module 'src.person' has no attribute 'factory' FAILED ...::test_john - AttributeError: module 'src.person' has no attribute 'factory' FAILED ...::test_mary - AttributeError: module 'src.person' has no attribute 'factory' =================== 4 failed 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 add the name to
person.py1factorythe terminal is my friend, and shows NameError
NameError: name 'factory' is not definedI point
factoryto None (the simplest object) to define it1# factory 2factory = Nonethe terminal is my friend, and shows TypeError
TypeError: 'NoneType' object is not callablebecause
factorypoints to None and I cannot call None like a function.I change
factoryto a function to make it callable1# factory 2# factory = None 3def factory(): 4 return Nonethe terminal is my friend, and shows TypeError
TypeError: factory() got an unexpected keyword argument 'first_name'because this function definition does not allow any inputs, the parentheses are empty.
I add
first_namein the parentheses so the function can take input1# factory 2# factory = None 3# def factory(): 4def factory(first_name): 5 return Nonethe terminal is my friend, and shows TypeError
TypeError: factory() got an unexpected keyword argument 'last_name'. Did you mean 'first_name'?because the function definition now only allows one input (
first_name) and it was called with a keyword argument (last_name).I add
last_nameto the parentheses1# factory 2# factory = None 3# def factory(): 4# def factory(first_name): 5def factory(first_name, last_name): 6 return Nonethe terminal is my friend, and shows TypeError
TypeError: factory() got an unexpected keyword argument 'sex'because the function definition only allows two inputs (
first_nameandlast_name) and it was called with a keyword argument (sex).I add
sexto the parentheses1# factory 2# factory = None 3# def factory(): 4# def factory(first_name): 5# def factory(first_name, last_name): 6def factory(first_name, last_name, sex): 7 return Nonethe terminal is my friend, and shows TypeError
TypeError: factory() got an unexpected keyword argument 'year_of_birth'because the function definition only allows three inputs (
first_name,last_name,sex) and it was called with a keyword argument (year_of_birth).I add
year_of_birthto the parentheses1# factory 2# factory = None 3# def factory(): 4# def factory(first_name): 5# def factory(first_name, last_name): 6# def factory(first_name, last_name, sex): 7def factory( 8 first_name, last_name, 9 sex, year_of_birth 10 ): 11 return Nonethe terminal is my friend, and shows AssertionError
AssertionError: assert None == 'mary, public, F, 2000'I change the return statement to match the expectation of the test
1# factory 2# factory = None 3# def factory(): 4# def factory(first_name): 5# def factory(first_name, last_name): 6# def factory(first_name, last_name, sex): 7def factory( 8 first_name, last_name, 9 sex, year_of_birth 10 ): 11 return 'mary, public, F, 2000'the terminal is my friend, and shows AttributeError
AttributeError: module 'src.person' has no attribute 'say_hi'I add the name
1say_hi 2 3 4# factory 5# factory = None 6# def factory(): 7# def factory(first_name): 8# def factory(first_name, last_name): 9# def factory(first_name, last_name, sex): 10def factory( 11 first_name, last_name, 12 sex, year_of_birth 13 ): 14 return 'mary, public, F, 2000'the terminal is my friend, and shows NameError
NameError: name 'say_hi' is not definedI point it to None to define it
1# say_hi 2say_hi = None 3 4 5# factorythe terminal is my friend, and shows TypeError
TypeError: 'NoneType' object is not callablebecause
say_hipoints to None and I cannot call None like a function.I make
say_hia function to make it callable1# say_hi 2# say_hi = None 3def say_hi(): 4 return None 5 6 7# factorythe terminal is my friend, and shows TypeError
TypeError: say_hi() got an unexpected keyword argument 'first_name'because this function definition does not allow any inputs, the parentheses are empty.
I add
first_namein the parentheses1# say_hi 2# say_hi = None 3# def say_hi(): 4def say_hi(first_name): 5 return None 6 7 8# factorythe terminal is my friend, and shows TypeError
TypeError: say_hi() got an unexpected keyword argument 'last_name'. Did you mean 'first_name'?because the function definition now only allows one input (
first_name) and it was called with a keyword argument (last_name).I add
last_nameto the parentheses1# say_hi 2# say_hi = None 3# def say_hi(): 4# def say_hi(first_name): 5def say_hi(first_name, last_name): 6 return None 7 8 9# factorythe terminal is my friend, and shows TypeError
TypeError: say_hi() got an unexpected keyword argument 'year_of_birth'because the function definition only allows two inputs (
first_nameandlast_name) and it was called with a keyword argument (year_of_birth).I add
year_of_birthto the parentheses1# say_hi 2# say_hi = None 3# def say_hi(): 4# def say_hi(first_name): 5# def say_hi(first_name, last_name): 6def say_hi( 7 first_name, last_name, year_of_birth 8): 9 return None 10 11 12# factorythe terminal is my friend, and shows AssertionError
AssertionError: assert None == 'Hi, my name is mary public and I am 26.'I use ctrl/command+c (Windows & Linux/MacOS) on the keyboard to copy the string from the terminal and ctrl/command+v to paste it to replace None in the return statement
1# say_hi 2# say_hi = None 3# def say_hi(): 4# def say_hi(first_name): 5# def say_hi(first_name, last_name): 6def say_hi( 7 first_name, last_name, year_of_birth 8): 9 # return None 10 return 'Hi, my name is mary public and I am 26.' 11 12 13# factorythe terminal is my friend, and shows AssertionError
AssertionError: assert 'mary, public, F, 2000' == 'john, smith, M, 1580'because the factory function always returns
'mary, public, F, 2000'and this test expects'john, smith, M, 1580'.I change the return statement of the factory function to see the difference between the input and the expected output (remember the identity function?)
13# factory 14# factory = None 15# def factory(): 16# def factory(first_name): 17# def factory(first_name, last_name): 18# def factory(first_name, last_name, sex): 19def factory( 20 first_name, last_name, 21 sex, year_of_birth 22 ): 23 # return 'mary, public, F, 2000' 24 return first_name, last_name, sex, year_of_birththe terminal is my friend, and shows AssertionError
AssertionError: assert ('mary', 'public', 'F', 2000) == 'mary, public, F, 2000'the
first_name,last_name,sexandyear_of_birthare part of the output.I change the return statement to an f-string with those values
13# factory 14# factory = None 15# def factory(): 16# def factory(first_name): 17# def factory(first_name, last_name): 18# def factory(first_name, last_name, sex): 19def factory( 20 first_name, last_name, 21 sex, year_of_birth 22 ): 23 # return 'mary, public, F, 2000' 24 # return first_name, last_name, sex, year_of_birth 25 return ( 26 f'{first_name}, {last_name},' 27 f' {sex}, {year_of_birth}' 28 )the terminal is my friend, and shows AssertionError
AssertionError: assert 'Hi, my name ... and I am 26.' == 'Hi, my name ...and I am 446.'because the say_hi function always returns
'Hi, my name is mary public and I am 26.'and this test expects'Hi, my name is john smith and I am 446.'I change the return statement of the say_hi function to see the difference between the input and the expected output
1# say_hi 2# say_hi = None 3# def say_hi(): 4# def say_hi(first_name): 5# def say_hi(first_name, last_name): 6def say_hi( 7 first_name, last_name, year_of_birth 8): 9 # return None 10 # return 'Hi, my name is mary public and I am 26.' 11 return first_name, last_name, year_of_birth 12 13 14# factorythe terminal is my friend, and shows AssertionError
AssertionError: assert ('mary', 'public', 'F', 2000) == 'mary, public, F, 2000'the
first_nameandlast_nameare part of the output.I change the return statement to an f-string with the input values
1# say_hi 2# say_hi = None 3# def say_hi(): 4# def say_hi(first_name): 5# def say_hi(first_name, last_name): 6def say_hi( 7 first_name, last_name, year_of_birth 8): 9 # return None 10 # return 'Hi, my name is mary public and I am 26.' 11 # return first_name, last_name, year_of_birth 12 return ( 13 f'Hi, my name is {first_name}' 14 f' {last_name} and I am {year_of_birth}.' 15 ) 16 17 18# factorythe terminal is my friend, and shows AssertionError
AssertionError: assert 'Hi, my name ...nd I am 2000.' == 'Hi, my name ... and I am 26.'It looks like
26is the age.I change the
year_of_birthvalue to a calculation of the age1# say_hi 2# say_hi = None 3# def say_hi(): 4# def say_hi(first_name): 5# def say_hi(first_name, last_name): 6def say_hi( 7 first_name, last_name, year_of_birth 8): 9 # return None 10 # return 'Hi, my name is mary public and I am 26.' 11 # return first_name, last_name, year_of_birth 12 return ( 13 f'Hi, my name is {first_name}' 14 # f' {last_name} and I am {year_of_birth}.' 15 f' {last_name} and I am' 16 f' {2026-year_of_birth}.' 17 ) 18 19 20# factoryall tests are green!
I remove the commented lines
1def say_hi( 2 first_name, last_name, year_of_birth 3): 4 return ( 5 f'Hi, my name is {first_name}' 6 f' {last_name} and I am' 7 f' {2026-year_of_birth}.' 8 ) 9 10 11def factory( 12 first_name, last_name, 13 sex, year_of_birth 14 ): 15 return ( 16 f'{first_name}, {last_name},' 17 f' {sex}, {year_of_birth}' 18 )
close the project
I close
person.pyI 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
personcd ..the terminal shows
...\pumping_pythonI am back in the
pumping_pythondirectory.
review
I ran tests to write one function that makes a person when given
first_name,last_name,sexandyear_of_birthso I do not have to make one function for each person.I also ran tests to make another function that uses f-strings to make a string that represents the person I make saying hi when I give it
first_name,last_name, andyear_of_birth.I saw the following Exceptions
My tests and solutions have a few problems,
Each test is basically the same two tests, there has to be a way that I can use one test for all the people.
The factory and say_hi functions use three of the same inputs
first_namelast_nameyear_of_birth
There has to be a better way, where I can give those values once, and get a representation for a person when I call the factory function and a message when I call the say_hi function.
For now, I am going to clean up the functions project so the tests and solutions are in separate files.
code from the chapter
what is next?
You know
Would you like to see me separate the tests and functions in the functions 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.