how to make a calculator 10: part 3
I want the numbers to stay when I press a button so that I can make numbers that have more than one digit.
preview
These are the tests I have by the end of the chapter
1import random
2import streamlit.testing.v1
3import tests.test_calculator
4import unittest
5
6
7class TestStreamlitCalculator(unittest.TestCase):
8
9 def press_button(self, key):
10 self.tester.button(key).click().run()
11
12 def setUp(self):
13 self.tester = streamlit.testing.v1.AppTest.from_file(
14 'src/streamlit_calculator.py'
15 )
16 self.tester.run()
17
18 def test_streamlit_calculator_title(self):
19 self.assertEqual(self.tester.title[0].value, 'Calculator')
20
21 def test_streamlit_calculator_display(self):
22 display = (
23 self.tester.main.children[1].proto
24 .flex_container
25 )
26 self.assertEqual(display.gap_config.gap_size, 1)
27 self.assertEqual(display.direction, 1)
28 self.assertEqual(display.justify, 1)
29 self.assertEqual(display.align, 1)
30 self.assertTrue(display.border)
31
32 def test_streamlit_calculator_columns_and_buttons(self):
33 self.assertEqual(len(self.tester.columns), 4)
34
35 for column, keys in (
36 (0, ('<-', '7', '4', '1', '+/-')),
37 (1, ('C', '8', '5', '2', '0')),
38 (2, ('AC', '9', '6', '3', '.')),
39 (3, ('/', 'X', r'\-', r'\+', '=')),
40 ):
41 for key in keys:
42 with self.subTest(key=key):
43 self.assertEqual(
44 (
45 self.tester.columns[column]
46 .button(key)
47 .label
48 ),
49 key
50 )
51
52 def test_streamlit_calculator_operations_buttons(self):
53 for key in ('/', 'X', r'\-', r'\+', '=', 'C', 'AC'):
54 with self.subTest(key=key):
55 self.assertEqual(
56 self.tester.button(key).proto.type,
57 'primary'
58 )
59
60 def test_streamlit_session_state(self):
61 numbers = '0123456789'
62 self.assertEqual(self.tester.session_state['number'], '0')
63
64 expectation = random.choice(numbers)
65 while expectation == '0':
66 expectation = random.choice(numbers)
67 else:
68 self.press_button(expectation)
69
70 self.assertEqual(
71 self.tester.session_state['number'], expectation
72 )
73
74 for _ in range(0, len(numbers)):
75 a_random_number = random.choice(numbers)
76 self.press_button(a_random_number)
77 expectation += a_random_number
78
79 self.assertEqual(
80 self.tester.session_state['number'],
81 expectation
82 )
83
84 def test_streamlit_calculator_w_decimals(self):
85 for key in ('0.23.5.6.7.89'):
86 self.press_button(key)
87
88 self.assertEqual(
89 self.tester.session_state['number'],
90 '0.2356789'
91 )
92
93 def test_streamlit_calculator_backspace(self):
94 a_random_number = tests.test_calculator.a_random_number()
95 while a_random_number < 0:
96 a_random_number = tests.test_calculator.a_random_number()
97 a_random_number = str(a_random_number)
98
99 for key in a_random_number:
100 self.press_button(key)
101 self.press_button('<-')
102
103 self.assertEqual(
104 self.tester.session_state['number'],
105 a_random_number[:-1]
106 )
107
108 self.press_button('<-')
109 self.assertEqual(
110 self.tester.session_state['number'],
111 a_random_number[:-2]
112 )
113
114 def test_streamlit_calculator_w_plus_minus(self):
115 a_number = '963.0258741'
116 for key in a_number:
117 self.press_button(key)
118 self.assertEqual(
119 self.tester.session_state['number'], a_number
120 )
121
122 self.press_button('+/-')
123 self.assertEqual(
124 self.tester.session_state['number'], f'-{a_number}'
125 )
126
127 self.press_button('+/-')
128 self.assertEqual(
129 self.tester.session_state['number'], a_number
130 )
131
132
133# Exceptions seen
134# NameError
135# AttributeError
136# AssertionError
137# SyntaxError
138# KeyError
139# streamlit.errors.StreamlitDuplicateElementKey
open the project
I change directory to the
calculatorfoldercd calculatorI use
pytest-watcherto run the testsuv run pytest-watcher . --nowthe terminal is my friend, and shows
rootdir: .../pumping_python/calculator configfile: pyproject.toml collected 12 items tests/test_calculator.py ..... [ 41%] tests/test_calculator_website.py ... [ 66%] tests/test_streamlit_calculator.py .... [100%] ======================== 12 passed in X.YZs =========================I open another terminal then use uv in the
calculatorfolderuv run streamlit run src/streamlit_calculator.pythe terminal is my friend, and shows
Collecting usage statistics. To deactivate, set browser.gatherUsageStats to false. You can now view your Streamlit app in your browser. Local URL: http://localhost:8501 Network URL: http://ABC.DEF.GHI.JKL:8501 External URL: http://MNO.PQR.STU.VWX:8501I use ctrl/option on the keyboard and click on
http://localhost:8501with the mouse to open the browser and it shows
test_streamlit_session_state
streamlit has a session state object that I can use to keep values in between button presses. They work the same as class attributes and they are dictionaries - I can add key-value pairs to them
RED: make it fail
I hold ctrl/command on the keyboard and click on
tests/test_streamlit_calculator.pywith the mouse to open it in the editorI add a test for the session state object, I want it to hold the number when I click the buttons, in
test_streamlit_calculator.py47 def test_streamlit_calculator_operations_buttons(self): 48 for key in ('/', 'X', r'\-', r'\+', '=', 'C', 'AC'): 49 with self.subTest(key=key): 50 self.assertEqual( 51 self.tester.button(key).proto.type, 52 'primary' 53 ) 54 55 def test_streamlit_session_state(self): 56 self.assertIsNone(self.tester.session_state['number']) 57 58 59# Exceptions seenthe terminal is my friend, and shows KeyError
KeyError: 'st.session_state has no key "number". Did you forget to initialize it? More info: https://docs.streamlit.io/develop/concepts/architecture/session-state#initialization'
GREEN: make it pass
I use the setdefault method to add a key that will hold the numbers to show in the Calculator, in
streamlit_calculator.py90def main(): 91 streamlit.title('Calculator') 92 streamlit.session_state.setdefault('number', '0') 93 display = streamlit.container(border=True) 94 95 column_1, column_2, column_3, operations = streamlit.columns(4) 96 add_buttons_to_column_1(column_1, display) 97 add_buttons_to_column_2(column_2, display) 98 add_buttons_to_column_3(column_3, display) 99 add_buttons_to_column_4(operations)the terminal is my friend, and shows AssertionError
AssertionError: 0 is not NoneI add
0as the expectation intest_streamlit_calculator.py55 def test_streamlit_session_state(self): 56 self.assertIsNone(self.tester.session_state['number'], '0')the terminal is my friend, and shows AssertionError
AssertionError: '0' is not None : 0I change the assertIsNone to assertEqual
56 self.assertEqual(self.tester.session_state['number'], '0')the test passes
REFACTOR: make it better
I add the session state object to the
showfunction so that when a button is clicked, it will be added to the session state object then shown in the disply4def show(display, number): 5 # display.write(number) 6 streamlit.session_state['number'] += number 7 display.write(streamlit.session_state['number']) 8 9 10def add_buttons_to_column_1(column_1, display):the test passes
I remove the commented line
4def show(display, number): 5 streamlit.session_state['number'] += number 6 display.write(streamlit.session_state['number'])I add an assertion to test what happens to the session state object when I press a button for a number
55 def test_streamlit_session_state(self): 56 self.assertEqual(self.tester.session_state['number'], '0') 57 self.tester.button('1').click().run() 58 self.assertEqual(self.tester.session_state['number'], '0').click()presses the button.run()runs the program -streamlit_calculator.py, which is what happens when a person uses the application in the browser
the terminal is my friend, and shows AssertionError
AssertionError: '01' != '0'this is a problem
I change the expectation to match
58 self.assertEqual(self.tester.session_state['number'], '01')the test passes
I add more button presses and another assertion
55 def test_streamlit_session_state(self): 56 self.assertEqual(self.tester.session_state['number'], '0') 57 self.tester.button('1').click().run() 58 self.assertEqual(self.tester.session_state['number'], '01') 59 self.tester.button('2').click().run() 60 self.tester.button('3').click().run() 61 self.tester.button('4').click().run() 62 self.assertEqual(self.tester.session_state['number'], '01')the terminal is my friend, and shows AssertionError
AssertionError: '01234' != '01'I change the expectation to match
62 self.assertEqual( 63 self.tester.session_state['number'], '01234' 64 )the test passes
I refresh the browser and click on all the numbers
the calculator keeps numbers when I press the buttons and the number starts with
0like the testI want the calculator to remove
0when it is the first number after I click on other numbers. I change the assertions55 def test_streamlit_session_state(self): 56 self.assertEqual(self.tester.session_state['number'], '0') 57 self.tester.button('1').click().run() 58 self.assertEqual(self.tester.session_state['number'], '1') 59 self.tester.button('2').click().run() 60 self.tester.button('3').click().run() 61 self.tester.button('4').click().run() 62 self.assertEqual( 63 self.tester.session_state['number'], '1234' 64 )the terminal is my friend, and shows AssertionError
AssertionError: '01' != '1'I add a condition to the
showfunction instreamlit_calculator.py4def show(display, number): 5 if streamlit.session_state['number'] == '0': 6 streamlit.session_state['number'] = number 7 else: 8 streamlit.session_state['number'] += number 9 display.write(streamlit.session_state['number'])the test passes
I refresh the browser and try all the numbers
the number no longer starts with
0I import the random module to use random numbers for the test, in
test_streamlit_calculator.py1import random 2import streamlit.testing.v1 3import unittest 4 5 6class TestStreamlitCalculator(unittest.TestCase):I use it in test_streamlit_session_state
56 def test_streamlit_session_state(self): 57 numbers = '0123456789' 58 self.assertEqual(self.tester.session_state['number'], '0') 59 # self.tester.button('1').click().run() 60 x = random.choice(numbers) 61 self.tester.button(x).click().run() 62 self.assertEqual(self.tester.session_state['number'], '1')numbers = '0123456789'makes a string with ten numbersx = random.choice(numbers)picks a random number from the ten numbers and pointsxto it
the terminal is my friend, and shows. AssertionError
AssertionError: 'X' != '1'where
Xis a random numberI change the expectation
56 def test_streamlit_session_state(self): 57 numbers = '0123456789' 58 self.assertEqual(self.tester.session_state['number'], '0') 59 # self.tester.button('1').click().run() 60 x = random.choice(numbers) 61 self.tester.button(x).click().run() 62 self.assertEqual(self.tester.session_state['number'], x) 63 self.tester.button('2').click().run() 64 self.tester.button('3').click().run() 65 self.tester.button('4').click().run() 66 self.assertEqual( 67 self.tester.session_state['number'], '1234' 68 )when
xis not1, the terminal is my friend, and shows AssertionErrorAssertionError: 'X234' != '1234'I use random numbers for the other button presses
62 self.assertEqual(self.tester.session_state['number'], x) 63 # self.tester.button('2').click().run() 64 # self.tester.button('3').click().run() 65 # self.tester.button('4').click().run() 66 y = random.choice(numbers) 67 self.tester.button(y).click().run() 68 z = random.choice(numbers) 69 self.tester.button(z).click().run() 70 a = random.choice(numbers) 71 self.tester.button(a).click().run() 72 self.assertEqual( 73 self.tester.session_state['number'], '1234' 74 )the terminal is my friend, and shows AssertionError
AssertionError: 'XYZA' != '1234'I use the random numbers in the expectation of the assertion
72 self.assertEqual( 73 self.tester.session_state['number'], f'{x}{y}{z}{a}' 74 )when
xis0, the terminal is my friend, and shows AssertionErrorAssertionError: 'YZA' != '0YZA'
what is a while loop?
I can use a while loop to make sure that
xis never0, since thesession_state['number']is always0at the beginning. I add a while loop to test_streamlit_session_state56 def test_streamlit_session_state(self): 57 numbers = '0123456789' 58 self.assertEqual(self.tester.session_state['number'], '0') 59 # self.tester.button('1').click().run() 60 x = random.choice(numbers) 61 while x == '0': 62 x = random.choice(numbers) 63 else: 64 self.tester.button(x).click().run() 65 66 self.assertEqual(self.tester.session_state['number'], x) 67 # self.tester.button('2').click().run()x = random.choice(numbers)pointsxto a random number from thenumbersvariableif
xis not equal to'0'it goes to the next block which iselse: self.tester.button(x).click().run()if
xis equal to'0'it goes towhile x == '0':which makes a loop that will continue to run as long asxis equal to'0'inside the loop
x = random.choice(numbers)pointsxto a random number from thenumbersstring then checks again to see ifxis equal to'0'if
xis equal to0the loop runs againif
xis not equal to0in the loop, it leaves the loop and goes to the next block which iselse: self.tester.button(x).click().run()
I use ctrl+s on the keyboard a few times and there are no more random failures
I add a for loop to test with a 10 digit number
56 def test_streamlit_session_state(self): 57 numbers = '0123456789' 58 self.assertEqual(self.tester.session_state['number'], '0') 59 # self.tester.button('1').click().run() 60 x = random.choice(numbers) 61 while x == '0': 62 x = random.choice(numbers) 63 else: 64 self.tester.button(x).click().run() 65 66 self.assertEqual(self.tester.session_state['number'], x) 67 # self.tester.button('2').click().run() 68 # self.tester.button('3').click().run() 69 # self.tester.button('4').click().run() 70 y = random.choice(numbers) 71 self.tester.button(y).click().run() 72 z = random.choice(numbers) 73 self.tester.button(z).click().run() 74 a = random.choice(numbers) 75 self.tester.button(a).click().run() 76 self.assertEqual( 77 self.tester.session_state['number'], f'{x}{y}{z}{a}' 78 ) 79 80 for _ in range(0, len(numbers)): 81 a_random_number = random.choice(numbers) 82 ( 83 self.tester.button(a_random_number) 84 .click().run() 85 ) 86 x += a_random_number 87 88 self.assertEqual( 89 self.tester.session_state['number'], 90 x 91 ) 92 93 94# Exceptions seenfor _ in range(0, 10):uses_because I do not need a name for each number from the range object in the for loop since I do not use itthe terminal is my friend, and shows AssertionError
AssertionError: 'XYZABCDEFGHIJK' != 'XBCDEFGHIJK'the first number and the last 10 numbers are the same in the two strings
I comment out the other lines
56 def test_streamlit_session_state(self): 57 numbers = '0123456789' 58 self.assertEqual(self.tester.session_state['number'], '0') 59 # self.tester.button('1').click().run() 60 x = random.choice(numbers) 61 while x == '0': 62 x = random.choice(numbers) 63 else: 64 self.tester.button(x).click().run() 65 66 self.assertEqual(self.tester.session_state['number'], x) 67 # self.tester.button('2').click().run() 68 # self.tester.button('3').click().run() 69 # self.tester.button('4').click().run() 70 # y = random.choice(numbers) 71 # self.tester.button(y).click().run() 72 # z = random.choice(numbers) 73 # self.tester.button(z).click().run() 74 # a = random.choice(numbers) 75 # self.tester.button(a).click().run() 76 # self.assertEqual( 77 # self.tester.session_state['number'], f'{x}{y}{z}{a}' 78 # ) 79 80 for _ in range(0, len(numbers)): 81 a_random_number = random.choice(numbers) 82 ( 83 self.tester.button(a_random_number) 84 .click().run() 85 ) 86 x += a_random_number 87 88 self.assertEqual( 89 self.tester.session_state['number'], 90 x 91 )I use ctrl+s on the keyboard to run the tests a few times and the test is still green
I remove the commented lines
56 def test_streamlit_session_state(self): 57 numbers = '0123456789' 58 self.assertEqual(self.tester.session_state['number'], '0') 59 60 x = random.choice(numbers) 61 while x == '0': 62 x = random.choice(numbers) 63 else: 64 self.tester.button(x).click().run() 65 66 self.assertEqual(self.tester.session_state['number'], x) 67 68 for _ in range(0, len(numbers)): 69 a_random_number = random.choice(numbers) 70 ( 71 self.tester.button(a_random_number) 72 .click().run() 73 ) 74 x += a_random_number 75 76 self.assertEqual( 77 self.tester.session_state['number'], 78 x 79 )I use the
Rename Symbolfeature of the Integrated Development Environment (IDE) to changextoexpectationbecause I like the name better55 def test_streamlit_session_state(self): 56 numbers = '0123456789' 57 self.assertEqual(self.tester.session_state['number'], '0') 58 59 expectation = random.choice(numbers) 60 while expectation == '0': 61 expectation = random.choice(numbers) 62 else: 63 self.tester.button(expectation).click().run() 64 65 self.assertEqual( 66 self.tester.session_state['number'], expectation 67 ) 68 69 for _ in range(0, len(numbers)): 70 a_random_number = random.choice(numbers) 71 ( 72 self.tester.button(a_random_number) 73 .click().run() 74 ) 75 expectation += a_random_number 76 77 self.assertEqual( 78 self.tester.session_state['number'], 79 expectation 80 ) 81 82 83# Exceptions seen
test_streamlit_calculator_w_decimals
RED: make it fail
I add a test for decimal numbers
78 self.assertEqual( 79 self.tester.session_state['number'], 80 expectation 81 ) 82 83 def test_streamlit_calculator_w_decimals(self): 84 self.tester.button('0').click().run() 85 self.tester.button('.').click().run() 86 self.tester.button('2').click().run() 87 self.tester.button('3').click().run() 88 self.tester.button('.').click().run() 89 self.tester.button('5').click().run() 90 self.tester.button('.').click().run() 91 self.tester.button('6').click().run() 92 self.tester.button('.').click().run() 93 self.tester.button('7').click().run() 94 self.tester.button('.').click().run() 95 self.tester.button('8').click().run() 96 self.tester.button('9').click().run() 97 self.assertEqual( 98 self.tester.session_state['number'], 99 '0.2356789' 100 ) 101 102 103# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: '.23.5.6.7.89' != '0.2356789'I refresh the browser and do the same thing
the Calculator allows me add many decimal points
GREEN: make it pass
I add a function for decimals in
streamlit_calculator.py1import streamlit 2 3 4def handle_decimals(display, number): 5 if streamlit.session_state['number'].count('.') >= 1: 6 return None 7 else: 8 streamlit.session_state['number'] += number 9 display.write(streamlit.session_state['number']) 10 11 12def show(display, number):the terminal still shows AssertionError
I change the
on_clickparameter for the.button in theadd_buttons_to_column_3function to use the new function78 column_3.button( 79 label='.', key='.', width='stretch', 80 # on_click=show, args=[display, '.'], 81 on_click=handle_decimals, args=[display, '.'], 82 )the test passes
I remove the commented line
62def add_buttons_to_column_3(column_3, display): 63 column_3.button( 64 label='AC', key='AC', width='stretch', type='primary', 65 ) 66 column_3.button( 67 label='9', key='9', width='stretch', 68 on_click=show, args=[display, '9'], 69 ) 70 column_3.button( 71 label='6', key='6', width='stretch', 72 on_click=show, args=[display, '6'], 73 ) 74 column_3.button( 75 label='3', key='3', width='stretch', 76 on_click=show, args=[display, '3'], 77 ) 78 column_3.button( 79 label='.', key='.', width='stretch', 80 on_click=handle_decimals, args=[display, '.'], 81 ) 82 83 84def add_buttons_to_column_4(column_4):
REFACTOR: make it better
I change the else clause to an if statement to make it simpler
4def handle_decimals(display, number): 5 if streamlit.session_state['number'].count('.') >= 1: 6 return None 7 # else: 8 if streamlit.session_state['number'].count('.') == 0: 9 streamlit.session_state['number'] += number 10 display.write(streamlit.session_state['number'])the test is still green
I remove the other if statement
4def handle_decimals(display, number): 5 if streamlit.session_state['number'].count('.') == 0: 6 streamlit.session_state['number'] += number 7 display.write(streamlit.session_state['number']) 8 9 10def show(display, number):still green
if streamlit.session_state['number'].count('.') == 0:checks if.is insession_state['number']streamlit.session_state['number'].count('.')counts how many times.shows up insession_state['number']if
.is NOT insession_state['number'], then.gets added tosession_state['number']and the program runs the next line, which isdisplay.write(streamlit.session_state['number'])if
.is insession_state['number'], then the program runs the next line, which isdisplay.write(streamlit.session_state['number'])
I refresh the browser and try many decimals again
Yes! I can only do one decimal in a number
I add a for loop to test_streamlit_calculator_w_decimals in
test_streamlit_calculator.py83 def test_streamlit_calculator_w_decimals(self): 84 for key in ('0.23.5.6.7.89'): 85 ( 86 self.tester.button(key) 87 .click().run() 88 ) 89 90 self.tester.button('0').click().run() 91 self.tester.button('.').click().run() 92 self.tester.button('2').click().run() 93 self.tester.button('3').click().run() 94 self.tester.button('.').click().run() 95 self.tester.button('5').click().run() 96 self.tester.button('.').click().run() 97 self.tester.button('6').click().run() 98 self.tester.button('.').click().run() 99 self.tester.button('7').click().run() 100 self.tester.button('.').click().run() 101 self.tester.button('8').click().run() 102 self.tester.button('9').click().run() 103 self.assertEqual( 104 self.tester.session_state['number'], 105 '0.2356789' 106 )the terminal is my friend, and shows AssertionError
AssertionError: '0.235678902356789' != '0.2356789'I remove the other button presses
83 def test_streamlit_calculator_w_decimals(self): 84 for key in ('0.23.5.6.7.89'): 85 ( 86 self.tester.button(key) 87 .click().run() 88 ) 89 90 self.assertEqual( 91 self.tester.session_state['number'], 92 '0.2356789' 93 ) 94 95 96# Exceptions seenthe test passes
I keep writing
self.tester.button(key).click().run(), time to add a method for button presses6class TestStreamlitCalculator(unittest.TestCase): 7 8 def press_button(self, key): 9 self.tester.button(key).click().run() 10 11 def setUp(self):I use the new method in test_streamlit_session_state
59 def test_streamlit_session_state(self): 60 numbers = '0123456789' 61 self.assertEqual(self.tester.session_state['number'], '0') 62 63 expectation = random.choice(numbers) 64 while expectation == '0': 65 expectation = random.choice(numbers) 66 else: 67 # self.tester.button(expectation).click().run() 68 self.press_button(expectation) 69 70 self.assertEqual( 71 self.tester.session_state['number'], expectation 72 ) 73 74 for _ in range(0, len(numbers)): 75 a_random_number = random.choice(numbers) 76 # ( 77 # self.tester.button(a_random_number) 78 # .click().run() 79 # ) 80 self.press_button(a_random_number) 81 expectation += a_random_number 82 83 self.assertEqual( 84 self.tester.session_state['number'], 85 expectation 86 )the tests are still green
I remove the commented lines
59 def test_streamlit_session_state(self): 60 numbers = '0123456789' 61 self.assertEqual(self.tester.session_state['number'], '0') 62 63 expectation = random.choice(numbers) 64 while expectation == '0': 65 expectation = random.choice(numbers) 66 else: 67 self.press_button(expectation) 68 69 self.assertEqual( 70 self.tester.session_state['number'], expectation 71 ) 72 73 for _ in range(0, len(numbers)): 74 a_random_number = random.choice(numbers) 75 self.press_button(a_random_number) 76 expectation += a_random_number 77 78 self.assertEqual( 79 self.tester.session_state['number'], 80 expectation 81 ) 82 83 def test_streamlit_calculator_w_decimals(self):I use the
press_buttonmethod in test_streamlit_calculator_w_decimals83 def test_streamlit_calculator_w_decimals(self): 84 for key in ('0.23.5.6.7.89'): 85 # ( 86 # self.tester.button(key) 87 # .click().run() 88 # ) 89 self.press_button(key) 90 91 self.assertEqual( 92 self.tester.session_state['number'], 93 '0.2356789' 94 )still green
I remove the commented lines
83 def test_streamlit_calculator_w_decimals(self): 84 for key in ('0.23.5.6.7.89'): 85 self.press_button(key) 86 87 self.assertEqual( 88 self.tester.session_state['number'], 89 '0.2356789' 90 ) 91 92 93# Exceptions seen
test_streamlit_calculator_backspace
I want to be able to remove the last digit of a number with the <- button
RED: make it fail
I add a new test
87 self.assertEqual( 88 self.tester.session_state['number'], 89 '0.2356789' 90 ) 91 92 def test_streamlit_calculator_backspace(self): 93 self.press_button('1') 94 self.press_button('2') 95 self.press_button('3') 96 self.press_button('4') 97 self.press_button('<-') 98 self.assertEqual( 99 self.tester.session_state['number'], 100 '123' 101 ) 102 103 104# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: '1234' != '123'I try the same thing in the browser and it clears the screen
GREEN: make it pass
I add a function to
streamlit_calculator.py1import streamlit 2 3 4def backspace(display): 5 number = streamlit.session_state['number'][:-1] 6 streamlit.session_state['number'] = number 7 display.write(streamlit.session_state['number']) 8 9 10def handle_decimals(display, number):the terminal still shows AssertionError
I add the
on_clickparameter to the<-button in theadd_buttons_to_column_1function24def add_buttons_to_column_1(column_1, display): 25 column_1.button( 26 label='<-', key='<-', width='stretch', 27 on_click=backspace, args=[display], 28 ) 29 column_1.button( 30 label='7', key='7', width='stretch', 31 on_click=show, args=[display, '7'], 32 ) 33 column_1.button( 34 label='4', key='4', width='stretch', 35 on_click=show, args=[display, '4'], 36 ) 37 column_1.button( 38 label='1', key='1', width='stretch', 39 on_click=show, args=[display, '1'], 40 ) 41 column_1.button( 42 label='+/-', key='+/-', width='stretch', 43 on_click=show, args=[display, '+/-'], 44 ) 45 46 47def add_buttons_to_column_2(column_2, display):the test passes
REFACTOR: make it better
I add an import statement for
tests/test_calculator.pyintest_streamlit_calculator.py1import random 2import streamlit.testing.v1 3import tests.test_calculator 4import unittest 5 6 7class TestStreamlitCalculator(unittest.TestCase):I add a variable with a for loop for a random number in test_streamlit_calculator_backspace
93 def test_streamlit_calculator_backspace(self): 94 a_random_number = tests.test_calculator.a_random_number() 95 a_random_number = str(a_random_number) 96 97 for key in a_random_number: 98 self.press_button(key) 99 self.press_button('<-') 100 101 self.assertEqual( 102 self.tester.session_state['number'], 103 a_random_number 104 ) 105 106 self.press_button('1') 107 self.press_button('2') 108 self.press_button('3') 109 self.press_button('4') 110 self.press_button('<-') 111 self.assertEqual( 112 self.tester.session_state['number'], 113 '123' 114 )a_random_number = tests.test_calculator.a_random_number()uses thea_random_numberfunction fromtest_calculator.pythat I made in how to use random numbersa_random_number = str(a_random_number)changes the random number to a string since all the tests of the calculator have been done with strings so far
I use ctrl+s on the keyboard to run the test a few times because I am using random numbers. If the number is positive, the terminal is my friend, and shows AssertionError
AssertionError: 'LMN.OPQRSTUVWXYZ' != 'LMN.OPQRSTUVWXYZA'the last number was not removed
If the random number is negative, the terminal is my friend, and shows KeyError
KeyError: '-'I need a test for the ‘+/-’ button
I add a while loop to make sure
a_random_numberis never negative93 def test_streamlit_calculator_backspace(self): 94 a_random_number = tests.test_calculator.a_random_number() 95 while a_random_number < 0: 96 a_random_number = tests.test_calculator.a_random_number() 97 a_random_number = str(a_random_number) 98 99 for key in a_random_number:I use ctrl+s on the keyboard to run the tests a few times and the terminal is my friend, and shows AssertionError
AssertionError: 'BCD.EFGHIJKLMNOP' != 'BCD.EFGHIJKLMNOPQ'I remove this while statement when I test the ‘+/-’ button
I change the expectation to remove the last digit from the random number
103 self.assertEqual( 104 self.tester.session_state['number'], 105 a_random_number[:-1] 106 )the terminal shows AssertionError
AssertionError: 'RS.TUVWXYZABCDEF123' != '123'because I have button presses after the test. I need a way to reset the numbers back to 0
I comment out the other button presses
93 def test_streamlit_calculator_backspace(self): 94 a_random_number = tests.test_calculator.a_random_number() 95 while a_random_number < 0: 96 a_random_number = tests.test_calculator.a_random_number() 97 a_random_number = str(a_random_number) 98 99 for key in a_random_number: 100 self.press_button(key) 101 self.press_button('<-') 102 103 self.assertEqual( 104 self.tester.session_state['number'], 105 a_random_number[:-1] 106 ) 107 108 # self.press_button('1') 109 # self.press_button('2') 110 # self.press_button('3') 111 # self.press_button('4') 112 self.press_button('<-') 113 self.assertEqual( 114 self.tester.session_state['number'], 115 '123' 116 )the terminal is my friend, and shows AssertionError
AssertionError: 'GHI.JKLMNOPQRS' != '123'I change the expectation
93 def test_streamlit_calculator_backspace(self): 94 a_random_number = tests.test_calculator.a_random_number() 95 while a_random_number < 0: 96 a_random_number = tests.test_calculator.a_random_number() 97 a_random_number = str(a_random_number) 98 99 for key in a_random_number: 100 self.press_button(key) 101 self.press_button('<-') 102 103 self.assertEqual( 104 self.tester.session_state['number'], 105 a_random_number[:-1] 106 ) 107 108 # self.press_button('1') 109 # self.press_button('2') 110 # self.press_button('3') 111 # self.press_button('4') 112 self.press_button('<-') 113 self.assertEqual( 114 self.tester.session_state['number'], 115 # '123' 116 a_random_number[:-2] 117 )the test passes
I remove the commented lines
93 def test_streamlit_calculator_backspace(self): 94 a_random_number = tests.test_calculator.a_random_number() 95 while a_random_number < 0: 96 a_random_number = tests.test_calculator.a_random_number() 97 a_random_number = str(a_random_number) 98 99 for key in a_random_number: 100 self.press_button(key) 101 self.press_button('<-') 102 103 self.assertEqual( 104 self.tester.session_state['number'], 105 a_random_number[:-1] 106 ) 107 108 self.press_button('<-') 109 self.assertEqual( 110 self.tester.session_state['number'], 111 a_random_number[:-2] 112 ) 113 114 115# Exceptions seenI go to the browser and click on a few numbers, then click on
<-and it removes the last number. Fantastic!
test_streamlit_calculator_w_plus_minus
Nothing happens when I click +/- in the calculator. I want it to
change positive numbers to negative numbers
change negative numbers to positive numbers
RED: make it fail
I add a new test for the +/- button
108 self.press_button('<-')
109 self.assertEqual(
110 self.tester.session_state['number'],
111 a_random_number[:-2]
112 )
113
114 def test_streamlit_calculator_w_plus_minus(self):
115 self.press_button('9')
116 self.assertEqual(
117 self.tester.session_state['number'], '9'
118 )
119
120 self.press_button('+/-')
121 self.assertEqual(
122 self.tester.session_state['number'], '-9'
123 )
124
125
126 # Exceptions seen
the terminal is my friend, and shows AssertionError
AssertionError: '9' != '-9'
GREEN: make it pass
I add a function for the
+/-button instreamlit_calculator.py1import streamlit 2 3 4def plus_minus(display): 5 if not streamlit.session_state['number'].startswith('-'): 6 number = '-' + streamlit.session_state['number'] 7 streamlit.session_state['number'] = number 8 display.write(streamlit.session_state['number']) 9 10 11def backspace(display):the terminal still shows AssertionError
I add the
on_clickparameter for the+/-button in theadd_buttons_to_column_1function31def add_buttons_to_column_1(column_1, display): 32 column_1.button( 33 label='<-', key='<-', width='stretch', 34 on_click=backspace, args=[display], 35 ) 36 column_1.button( 37 label='7', key='7', width='stretch', 38 on_click=show, args=[display, '7'], 39 ) 40 column_1.button( 41 label='4', key='4', width='stretch', 42 on_click=show, args=[display, '4'], 43 ) 44 column_1.button( 45 label='1', key='1', width='stretch', 46 on_click=show, args=[display, '1'], 47 ) 48 column_1.button( 49 label='+/-', key='+/-', width='stretch', 50 on_click=plus_minus, args=[display], 51 ) 52 53 54def add_buttons_to_column_2(column_2, display):the test passes. I can turn a positive number to a negative number with the
+/-button. Can I turn a negative number to a positive number with the+/-button?
REFACTOR: make it better
I add a button press and assertion to make sure I can turn a negative number to a positive number with the
+/-button, intest_streamlit_calculator.py114 def test_streamlit_calculator_w_plus_minus(self): 115 self.press_button('9') 116 self.assertEqual( 117 self.tester.session_state['number'], '9' 118 ) 119 120 self.press_button('+/-') 121 self.assertEqual( 122 self.tester.session_state['number'], '-9' 123 ) 124 125 self.press_button('+/-') 126 self.assertEqual( 127 self.tester.session_state['number'], '9' 128 ) 129 130 131# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: '-9' != '9'I add another if statement to the
plus_minusfunction instreamlit_calculator.py4def plus_minus(display): 5 if streamlit.session_state['number'].startswith('-'): 6 number = streamlit.session_state['number'][1:] 7 if not streamlit.session_state['number'].startswith('-'): 8 number = '-' + streamlit.session_state['number'] 9 streamlit.session_state['number'] = number 10 11 display.write(streamlit.session_state['number'])the test passes
I use else for the second if statement
4def plus_minus(display): 5 if streamlit.session_state['number'].startswith('-'): 6 number = streamlit.session_state['number'][1:] 7 # if not streamlit.session_state['number'].startswith('-'): 8 else: 9 number = '-' + streamlit.session_state['number'] 10 streamlit.session_state['number'] = number 11 12 display.write(streamlit.session_state['number'])the test is still green
I remove the commented line
4def plus_minus(display): 5 if streamlit.session_state['number'].startswith('-'): 6 number = streamlit.session_state['number'][1:] 7 else: 8 number = '-' + streamlit.session_state['number'] 9 streamlit.session_state['number'] = number 10 11 display.write(streamlit.session_state['number']) 12 13 14def backspace(display):I add a variable to remove repetition from test_streamlit_calculator_w_plus_minus in
test_streamlit_calculator.py114 def test_streamlit_calculator_w_plus_minus(self): 115 a_number = '9' 116 self.press_button('9') 117 self.assertEqual(I use the variable in the assertions and button presses
114 def test_streamlit_calculator_w_plus_minus(self): 115 a_number = '9' 116 # self.press_button('9') 117 self.press_button(a_number) 118 self.assertEqual( 119 # self.tester.session_state['number'], '9' 120 self.tester.session_state['number'], a_number 121 ) 122 123 self.press_button('+/-') 124 self.assertEqual( 125 # self.tester.session_state['number'], '-9' 126 self.tester.session_state['number'], f'-{a_number}' 127 ) 128 129 self.press_button('+/-') 130 self.assertEqual( 131 # self.tester.session_state['number'], '9' 132 self.tester.session_state['number'], a_number 133 )the test is still green
I remove the commented lines
114 def test_streamlit_calculator_w_plus_minus(self): 115 a_number = '9' 116 self.press_button(a_number) 117 self.assertEqual( 118 self.tester.session_state['number'], a_number 119 ) 120 121 self.press_button('+/-') 122 self.assertEqual( 123 self.tester.session_state['number'], f'-{a_number}' 124 ) 125 126 self.press_button('+/-') 127 self.assertEqual( 128 self.tester.session_state['number'], a_number 129 )I try a bigger number
114 def test_streamlit_calculator_w_plus_minus(self): 115 a_number = '96' 116 self.press_button(a_number)the terminal is my friend, and shows KeyError
KeyError: '96'I need separate button presses for the two numbers
I add a for loop
114 def test_streamlit_calculator_w_plus_minus(self): 115 a_number = '96' 116 for key in a_number: 117 self.press_button(key) 118 self.assertEqual( 119 self.tester.session_state['number'], a_number 120 ) 121 122 self.press_button('+/-')the test passes
I try a number with all the digits and decimals
114 def test_streamlit_calculator_w_plus_minus(self): 115 a_number = '963.0258741' 116 for key in a_number: 117 self.press_button(key) 118 self.assertEqual( 119 self.tester.session_state['number'], a_number 120 ) 121 122 self.press_button('+/-') 123 self.assertEqual( 124 self.tester.session_state['number'], f'-{a_number}' 125 ) 126 127 self.press_button('+/-') 128 self.assertEqual( 129 self.tester.session_state['number'], a_number 130 ) 131 132 133# Exceptions seenthe test is still green
I refresh the browser and try to make a negative number
when I click on the
+/-button it turns a positive number negativeI try the
+/-button again
the
-is removed from the number to make it a positive number. Progress!
REFACTOR: make it better
The last 4 functions in
streamlit_calculator.py-plus_minus,backspace,handle_decimalsandshowlook the same. 2 of the functions havenumberin the function signature, all 4 havedisplayin the function signaturedef function_name(display): def function_name(display, number): statements display.write(streamlit.session_state['number'])I add
numberin the parentheses for theplus_minusfunction to make it have the same signature as theshowandhandle_decimalsfunctions4def plus_minus(display, number): 5 if streamlit.session_state['number'].startswith('-'): 6 number = streamlit.session_state['number'][1:] 7 else: 8 number = '-' + streamlit.session_state['number'] 9 streamlit.session_state['number'] = number 10 11 display.write(streamlit.session_state['number']) 12 13 14def backspace(display):the terminal is my friend, and shows AssertionError
'963.0258741' != '-963.0258741'and TypeError
TypeError: plus_minus() missing 1 required positional argument: 'number'I add a second argument to the
argsparameter for the+/-button in theadd_buttons_to_column_1function34def add_buttons_to_column_1(column_1, display): 35 column_1.button( 36 label='<-', key='<-', width='stretch', 37 on_click=backspace, args=[display], 38 ) 39 column_1.button( 40 label='7', key='7', width='stretch', 41 on_click=show, args=[display, '7'], 42 ) 43 column_1.button( 44 label='4', key='4', width='stretch', 45 on_click=show, args=[display, '4'], 46 ) 47 column_1.button( 48 label='1', key='1', width='stretch', 49 on_click=show, args=[display, '1'], 50 ) 51 column_1.button( 52 label='+/-', key='+/-', width='stretch', 53 on_click=plus_minus, args=[display, '+/-'], 54 ) 55 56 57def add_buttons_to_column_2(column_2, display):the test is green again
I add
numberin the parentheses for thebackspacefunction to make it have the same signature as theshow,handle_decimalsandplus_minusfunctions14def backspace(display, number): 15 number = streamlit.session_state['number'][:-1] 16 streamlit.session_state['number'] = number 17 display.write(streamlit.session_state['number']) 18 19 20def handle_decimals(display, number):the terminal is my friend, and shows AssertionError
AssertionError: 'RST.UVWXYZABCDEFGH' != 'RST.UVWXYZABCDEFG'it also shows TypeError
TypeError: backspace() missing 1 required positional argument: 'number'I add a second argument to the
argsparameter for the<-button in theadd_buttons_to_column_1function34def add_buttons_to_column_1(column_1, display): 35 column_1.button( 36 label='<-', key='<-', width='stretch', 37 on_click=backspace, args=[display, '<-'], 38 ) 39 column_1.button( 40 label='7', key='7', width='stretch', 41 on_click=show, args=[display, '7'], 42 ) 43 column_1.button( 44 label='4', key='4', width='stretch', 45 on_click=show, args=[display, '4'], 46 ) 47 column_1.button( 48 label='1', key='1', width='stretch', 49 on_click=show, args=[display, '1'], 50 ) 51 column_1.button( 52 label='+/-', key='+/-', width='stretch', 53 on_click=plus_minus, args=[display, '+/-'], 54 ) 55 56 57def add_buttons_to_column_2(column_2, display):the test is green again
I add a new function for showing the
numberkey of the session state object1import streamlit 2 3 4def show_number(display): 5 display.write(streamlit.session_state['number']) 6 7 8def plus_minus(display, number):I use the new function in the
plus_minusfunction8def plus_minus(display, number): 9 if streamlit.session_state['number'].startswith('-'): 10 number = streamlit.session_state['number'][1:] 11 else: 12 number = '-' + streamlit.session_state['number'] 13 streamlit.session_state['number'] = number 14 15 # display.write(streamlit.session_state['number']) 16 show_number(display)the test is still green
I remove the commented line
8def plus_minus(display, number): 9 if streamlit.session_state['number'].startswith('-'): 10 number = streamlit.session_state['number'][1:] 11 else: 12 number = '-' + streamlit.session_state['number'] 13 streamlit.session_state['number'] = number 14 15 show_number(display) 16 17 18def backspace(display, number):I use the new function in the
backspacefunction18def backspace(display, number): 19 number = streamlit.session_state['number'][:-1] 20 streamlit.session_state['number'] = number 21 # display.write(streamlit.session_state['number']) 22 show_number(display)the test is still green
I remove the commented line
18def backspace(display, number): 19 number = streamlit.session_state['number'][:-1] 20 streamlit.session_state['number'] = number 21 show_number(display) 22 23 24def handle_decimals(display, number):I use the new function in the
handle_decimalsfunction24def handle_decimals(display, number): 25 if streamlit.session_state['number'].count('.') == 0: 26 streamlit.session_state['number'] += number 27 # display.write(streamlit.session_state['number']) 28 show_number(display)the test is still green
I remove the commented line
24def handle_decimals(display, number): 25 if streamlit.session_state['number'].count('.') == 0: 26 streamlit.session_state['number'] += number 27 show_number(display) 28 29 30def show(display, number):I use the new function in the
showfunction30def show(display, number): 31 if streamlit.session_state['number'] == '0': 32 streamlit.session_state['number'] = number 33 else: 34 streamlit.session_state['number'] += number 35 # display.write(streamlit.session_state['number']) 36 show_number(display)the test is still green
I remove the commented line
30def show(display, number): 31 if streamlit.session_state['number'] == '0': 32 streamlit.session_state['number'] = number 33 else: 34 streamlit.session_state['number'] += number 35 show_number(display) 36 37 38def add_buttons_to_column_1(column_1, display):I add a new function for adding the number to the session state object
24def handle_decimals(display, number): 25 if streamlit.session_state['number'].count('.') == 0: 26 streamlit.session_state['number'] += number 27 show_number(display) 28 29 30def add_number_to_state(number): 31 if streamlit.session_state['number'] == '0': 32 streamlit.session_state['number'] = number 33 else: 34 streamlit.session_state['number'] += number 35 36 37def show(display, number):I add a function to handle all the button clicks
37def show(display, number): 38 if streamlit.session_state['number'] == '0': 39 streamlit.session_state['number'] = number 40 else: 41 streamlit.session_state['number'] += number 42 show_state(display) 43 44 45def on_click(function, display, value): 46 function(value) 47 show_state(display) 48 49 50def add_buttons():I try the
on_clickfunction with the7button in theadd_buttons_to_column_1function50def add_buttons_to_column_1(column_1, display): 51 column_1.button( 52 label='<-', key='<-', width='stretch', 53 on_click=backspace, args=[display, '<-'], 54 ) 55 column_1.button( 56 label='7', key='7', width='stretch', on_click=on_click, 57 # on_click=show, args=[display, '7'], 58 args=[add_number_to_state, display, '7'], 59 ) 60 column_1.button( 61 label='4', key='4', width='stretch', 62 on_click=show, args=[display, '4'], 63 ) 64 column_1.button( 65 label='1', key='1', width='stretch', 66 on_click=show, args=[display, '1'], 67 ) 68 column_1.button( 69 label='+/-', key='+/-', width='stretch', 70 on_click=plus_minus, args=[display, '+/-'], 71 )the tests are still green! Yes!!
I use the
on_clickfunction with all the other number buttons in theadd_buttons_to_column_1function50def add_buttons_to_column_1(column_1, display): 51 column_1.button( 52 label='<-', key='<-', width='stretch', 53 on_click=backspace, args=[display, '<-'], 54 ) 55 column_1.button( 56 label='7', key='7', width='stretch', on_click=on_click, 57 # on_click=show, args=[display, '7'], 58 args=[add_number_to_state, display, '7'], 59 ) 60 column_1.button( 61 label='4', key='4', width='stretch', on_click=on_click, 62 # on_click=show, args=[display, '4'], 63 args=[add_number_to_state, display, '4'], 64 ) 65 column_1.button( 66 label='1', key='1', width='stretch', on_click=on_click, 67 # on_click=show, args=[display, '1'], 68 args=[add_number_to_state, display, '1'], 69 ) 70 column_1.button( 71 label='+/-', key='+/-', width='stretch', 72 on_click=plus_minus, args=[display, '+/-'], 73 )still green
I remove the commented lines
50def add_buttons_to_column_1(column_1, display): 51 column_1.button( 52 label='<-', key='<-', width='stretch', 53 on_click=backspace, args=[display, '<-'], 54 ) 55 column_1.button( 56 label='7', key='7', width='stretch', on_click=on_click, 57 args=[add_number_to_state, display, '7'], 58 ) 59 column_1.button( 60 label='4', key='4', width='stretch', on_click=on_click, 61 args=[add_number_to_state, display, '4'], 62 ) 63 column_1.button( 64 label='1', key='1', width='stretch', on_click=on_click, 65 args=[add_number_to_state, display, '1'], 66 ) 67 column_1.button( 68 label='+/-', key='+/-', width='stretch', 69 on_click=plus_minus, args=[display, '+/-'], 70 ) 71 72 73def add_buttons_to_column_2(column_2, display):I use the
on_clickfunction with all the number buttons in theadd_buttons_to_column_2function73def add_buttons_to_column_2(column_2, display): 74 column_2.button( 75 label='C', key='C', width='stretch', type='primary', 76 ) 77 column_2.button( 78 label='8', key='8', width='stretch', on_click=on_click, 79 # on_click=show, args=[display, '8'], 80 args=[add_number_to_state, display, '8'], 81 ) 82 column_2.button( 83 label='5', key='5', width='stretch', on_click=on_click, 84 # on_click=show, args=[display, '5'], 85 args=[add_number_to_state, display, '5'], 86 ) 87 column_2.button( 88 label='2', key='2', width='stretch', on_click=on_click, 89 # on_click=show, args=[display, '2'], 90 args=[add_number_to_state, display, '2'], 91 ) 92 column_2.button( 93 label='0', key='0', width='stretch', on_click=on_click, 94 # on_click=show, args=[display, '0'], 95 args=[add_number_to_state, display, '0'], 96 )green
I remove the commented lines
73def add_buttons_to_column_2(column_2, display): 74 column_2.button( 75 label='C', key='C', width='stretch', type='primary', 76 ) 77 column_2.button( 78 label='8', key='8', width='stretch', on_click=on_click, 79 args=[add_number_to_state, display, '8'], 80 ) 81 column_2.button( 82 label='5', key='5', width='stretch', on_click=on_click, 83 args=[add_number_to_state, display, '5'], 84 ) 85 column_2.button( 86 label='2', key='2', width='stretch', on_click=on_click, 87 args=[add_number_to_state, display, '2'], 88 ) 89 column_2.button( 90 label='0', key='0', width='stretch', on_click=on_click, 91 args=[add_number_to_state, display, '0'], 92 ) 93 94 95def add_buttons_to_column_3(column_3, display):I use the
on_clickfunction with all the number buttons in theadd_buttons_to_column_3function95def add_buttons_to_column_3(column_3, display): 96 column_3.button( 97 label='AC', key='AC', width='stretch', type='primary', 98 ) 99 column_3.button( 100 label='9', key='9', width='stretch', on_click=on_click, 101 # on_click=show, args=[display, '9'], 102 args=[add_number_to_state, display, '9'], 103 ) 104 column_3.button( 105 label='6', key='6', width='stretch', on_click=on_click, 106 # on_click=show, args=[display, '6'], 107 args=[add_number_to_state, display, '6'], 108 ) 109 column_3.button( 110 label='3', key='3', width='stretch', on_click=on_click, 111 # on_click=show, args=[display, '3'], 112 args=[add_number_to_state, display, '3'], 113 ) 114 column_3.button( 115 label='.', key='.', width='stretch', 116 on_click=handle_decimals, args=[display, '.'], 117 )still green
I remove the commented lines
95def add_buttons_to_column_3(column_3, display): 96 column_3.button( 97 label='AC', key='AC', width='stretch', type='primary', 98 ) 99 column_3.button( 100 label='9', key='9', width='stretch', on_click=on_click, 101 args=[add_number_to_state, display, '9'], 102 ) 103 column_3.button( 104 label='6', key='6', width='stretch', on_click=on_click, 105 args=[add_number_to_state, display, '6'], 106 ) 107 column_3.button( 108 label='3', key='3', width='stretch', on_click=on_click, 109 args=[add_number_to_state, display, '3'], 110 ) 111 column_3.button( 112 label='.', key='.', width='stretch', 113 on_click=handle_decimals, args=[display, '.'], 114 ) 115 116 117def add_buttons_to_column_4(column_4):I remove the
showfunction because it is no longer used30def add_number_to_state(number): 31 if streamlit.session_state['number'] == '0': 32 streamlit.session_state['number'] = number 33 else: 34 streamlit.session_state['number'] += number 35 36 37def on_click(function, display, value):
I add a new function to make decimal numbers
24def handle_decimals(display, number): 25 if streamlit.session_state['number'].count('.') == 0: 26 streamlit.session_state['number'] += number 27 show_number(display) 28 29 30def add_decimal(): 31 if streamlit.session_state['number'].count('.') == 0: 32 streamlit.session_state['number'] += '.' 33 34 35def add_number_to_state(number):I use the new function with the
.button in theadd_buttons_to_column_3function92def add_buttons_to_column_3(column_3, display): 93 column_3.button( 94 label='AC', key='AC', width='stretch', type='primary', 95 ) 96 column_3.button( 97 label='9', key='9', width='stretch', on_click=on_click, 98 args=[add_number_to_state, display, '9'], 99 ) 100 column_3.button( 101 label='6', key='6', width='stretch', on_click=on_click, 102 args=[add_number_to_state, display, '6'], 103 ) 104 column_3.button( 105 label='3', key='3', width='stretch', on_click=on_click, 106 args=[add_number_to_state, display, '3'], 107 ) 108 column_3.button( 109 label='.', key='.', width='stretch', on_click=on_click, 110 # on_click=handle_decimals, args=[display, '.'], 111 args=[add_decimal, display] 112 )the terminal is my friend, and shows KeyError
FAILED ... - KeyError: 'I' FAILED ... - KeyError: '2' FAILED ... - KeyError: '0'and TypeError
TypeError: on_click() missing 1 required positional argument: 'value'I make the
valueparameter a choice in theon_clickfunction42def on_click(function, display, *value): 43 function(*value) 44 show_number(display) 45 46 47def add_buttons_to_column_1(column_1, display):the test passes
I remove the commented line from the
add_buttons_to_column_3function92def add_buttons_to_column_3(column_3, display): 93 column_3.button( 94 label='AC', key='AC', width='stretch', type='primary', 95 ) 96 column_3.button( 97 label='9', key='9', width='stretch', on_click=on_click, 98 args=[add_number_to_state, display, '9'], 99 ) 100 column_3.button( 101 label='6', key='6', width='stretch', on_click=on_click, 102 args=[add_number_to_state, display, '6'], 103 ) 104 column_3.button( 105 label='3', key='3', width='stretch', on_click=on_click, 106 args=[add_number_to_state, display, '3'], 107 ) 108 column_3.button( 109 label='.', key='.', width='stretch', on_click=on_click, 110 args=[add_decimal, display] 111 ) 112 113 114def add_buttons_to_column_4(column_4):I remove the
handle_decimalsfunction because it is no longer used18def backspace(display, number): 19 number = streamlit.session_state['number'][:-1] 20 streamlit.session_state['number'] = number 21 show_number(display) 22 23 24def add_decimal():
I change the
on_clickandargsparameters for the<-button in theadd_buttons_to_column_1function41def add_buttons_to_column_1(column_1, display): 42 column_1.button( 43 label='<-', key='<-', width='stretch', on_click=on_click, 44 # on_click=backspace, args=[display, '<-'], 45 args=[backspace, display], 46 )the terminal is my friend, and shows AssertionError
AssertionError: 'MNO.PQRSTUVWXYZABCD' != 'MNO.PQRSTUVWXYZABC'and TypeError
TypeError: backspace() missing 2 required positional arguments: 'display' and 'number'I change the
backspacefunction18# def backspace(display, number): 19def backspace(): 20 number = streamlit.session_state['number'][:-1] 21 streamlit.session_state['number'] = number 22 # show_number(display)the test passes
I remove the commented lines from the
backspacefunction18def backspace(): 19 number = streamlit.session_state['number'][:-1] 20 streamlit.session_state['number'] = number 21 22 23def add_decimal():
I change the
on_clickandargsparameters for the+/-button in theadd_buttons_to_column_1function40def add_buttons_to_column_1(column_1, display): 41 column_1.button( 42 label='<-', key='<-', width='stretch', on_click=on_click, 43 # on_click=backspace, args=[display, '<-'], 44 args=[backspace, display], 45 ) 46 column_1.button( 47 label='7', key='7', width='stretch', on_click=on_click, 48 args=[add_number_to_state, display, '7'], 49 ) 50 column_1.button( 51 label='4', key='4', width='stretch', on_click=on_click, 52 args=[add_number_to_state, display, '4'], 53 ) 54 column_1.button( 55 label='1', key='1', width='stretch', on_click=on_click, 56 args=[add_number_to_state, display, '1'], 57 ) 58 column_1.button( 59 label='+/-', key='+/-', width='stretch', on_click=on_click, 60 # on_click=plus_minus, args=[display, '+/-'], 61 args=[plus_minus, display], 62 )the terminal is my friend, and shows AssertionError
AssertionError: '963.0258741' != '-963.0258741'and TypeError
TypeError: plus_minus() missing 2 required positional arguments: 'display' and 'number'I change the
plus_minusfunction8# def plus_minus(display, number): 9def plus_minus(): 10 if streamlit.session_state['number'].startswith('-'): 11 number = streamlit.session_state['number'][1:] 12 else: 13 number = '-' + streamlit.session_state['number'] 14 streamlit.session_state['number'] = number 15 16 # show_number(display)the test passes
I remove the commented lines from the
plus_minusfunction8def plus_minus(): 9 if streamlit.session_state['number'].startswith('-'): 10 number = streamlit.session_state['number'][1:] 11 else: 12 number = '-' + streamlit.session_state['number'] 13 streamlit.session_state['number'] = number 14 15 16def backspace():I remove the commented lines from the
add_buttons_to_column_1function42def add_buttons_to_column_1(column_1, display): 43 column_1.button( 44 label='<-', key='<-', width='stretch', on_click=on_click, 45 args=[backspace, display], 46 ) 47 column_1.button( 48 label='7', key='7', width='stretch', on_click=on_click, 49 args=[add_number_to_state, display, '7'], 50 ) 51 column_1.button( 52 label='4', key='4', width='stretch', on_click=on_click, 53 args=[add_number_to_state, display, '4'], 54 ) 55 column_1.button( 56 label='1', key='1', width='stretch', on_click=on_click, 57 args=[add_number_to_state, display, '1'], 58 ) 59 column_1.button( 60 label='+/-', key='+/-', width='stretch', on_click=on_click, 61 args=[plus_minus, display], 62 ) 63 64 65def add_buttons_to_column_2(column_2, display):
That was a lot! I am going to take a nap. I will work on the operations after that.
close the project
I close
test_streamlit_calculator.py,streamlit_calculator.pyin the editorI click in the first terminal, then use q on the keyboard to leave the tests. The terminal goes back to the command line
I change directory to the parent of
calculatorcd ..the terminal is my friend, and shows
.../pumping_pythonI am back in the
pumping_pythondirectoryI click in the second terminal, then use ctrl+c on the keyboard to close the web server. The terminal goes back to the command line
I change directory to the parent of
calculatorcd ..the terminal is my friend, and shows
.../pumping_pythonI am back in the
pumping_pythondirectory
review
I made a website using Streamlit with a
I used while loops and added tests for
code from the chapter
what is next?
You now know how to:
build a website with streamlit
how to test the parts of the website
how to add functions to streamlit buttons to make them do things from
Would you like to continue with the operation buttons of the calculator?
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