Skip to content

Commit 97c3cd4

Browse files
authored
Merge pull request #13 from martinRenou/optional_events_notebooks
Add optional events notebooks
2 parents a9b47a6 + ace9b29 commit 97c3cd4

8 files changed

+1037
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"<!--NAVIGATION-->\n",
8+
"< [Widgets Events](02.00-events.ipynb) | [*OPTIONAL* Password generator: `observe`](02.02-OPTIONAL-Widget_Events_2--bad_password_generator.ipynb) >"
9+
]
10+
},
11+
{
12+
"cell_type": "markdown",
13+
"metadata": {},
14+
"source": [
15+
"# *OPTIONAL* Three approaches to events"
16+
]
17+
},
18+
{
19+
"cell_type": "markdown",
20+
"metadata": {},
21+
"source": [
22+
"The next series of notebooks presents three ways of handling widget events. In each of the notebooks we'll construct the same simple password generator.\n",
23+
"\n",
24+
"The first uses a mix of functions and global variables, an approach like that in the notebook introducing widget events.\n",
25+
"\n",
26+
"The second separates the logic of the password generation from the password generation user interface.\n",
27+
"\n",
28+
"The third takes that separation a step further by using a class for the user interface, a class for the logic, and a class to bring them together."
29+
]
30+
}
31+
],
32+
"metadata": {
33+
"kernelspec": {
34+
"display_name": "Python 3",
35+
"language": "python",
36+
"name": "python3"
37+
},
38+
"language_info": {
39+
"codemirror_mode": {
40+
"name": "ipython",
41+
"version": 3
42+
},
43+
"file_extension": ".py",
44+
"mimetype": "text/x-python",
45+
"name": "python",
46+
"nbconvert_exporter": "python",
47+
"pygments_lexer": "ipython3",
48+
"version": "3.8.5"
49+
}
50+
},
51+
"nbformat": 4,
52+
"nbformat_minor": 4
53+
}
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"metadata": {
7+
"jupyter": {
8+
"outputs_hidden": true
9+
}
10+
},
11+
"outputs": [],
12+
"source": [
13+
"import ipywidgets as widgets"
14+
]
15+
},
16+
{
17+
"cell_type": "markdown",
18+
"metadata": {},
19+
"source": [
20+
"<!--NAVIGATION-->\n",
21+
"< [*OPTIONAL* Three approaches to events](02.01-OPTIONAL-Widget_Events_2.ipynb) | [*OPTIONAL* Separating the logic from the widgets](02.03-OPTIONAL-Widget_Events_2--Separating_Concerns.ipynb) >"
22+
]
23+
},
24+
{
25+
"cell_type": "markdown",
26+
"metadata": {},
27+
"source": [
28+
"# *OPTIONAL* Password generator: `observe`\n",
29+
"\n",
30+
"Consider a super-simple (and super-bad) password generator widget: given a password length, represented by a slider in the interface, it constructs a sequence of random letters of that length and displays it. \n",
31+
"\n",
32+
"\n",
33+
"This notebook illustrates how to connect the function that calculates the password to the length slider using `observe` but mixes together the code to calculate the password and the code to handle the events generated by the interface"
34+
]
35+
},
36+
{
37+
"cell_type": "markdown",
38+
"metadata": {},
39+
"source": [
40+
"## Construct the interface (widget)\n",
41+
"\n",
42+
"The widget should look like this once constructed:\n",
43+
"\n",
44+
"![Password generator](passgen.png)\n",
45+
"\n",
46+
"Compose the widget out of three basic widgets, one each for the title, the (currently not set) password, and one for the slider. \n",
47+
"\n",
48+
"In the cell below construct each of the basic widgets. "
49+
]
50+
},
51+
{
52+
"cell_type": "code",
53+
"execution_count": null,
54+
"metadata": {
55+
"jupyter": {
56+
"outputs_hidden": true
57+
}
58+
},
59+
"outputs": [],
60+
"source": [
61+
"helpful_title = 0 # Replace with some that displays \"Generated password is:\"\n",
62+
"password_text = 0 # Replace with something that displays \"No password set\"\n",
63+
"password_length = 0 # Replace with slider\n"
64+
]
65+
},
66+
{
67+
"cell_type": "markdown",
68+
"metadata": {},
69+
"source": [
70+
"Combine these three into a single widget...the output should look like the image above."
71+
]
72+
},
73+
{
74+
"cell_type": "code",
75+
"execution_count": null,
76+
"metadata": {
77+
"jupyter": {
78+
"outputs_hidden": true
79+
}
80+
},
81+
"outputs": [],
82+
"source": [
83+
"password_widget = widgets.VBox(children=[helpful_title, password_text, password_length])\n",
84+
"password_widget"
85+
]
86+
},
87+
{
88+
"cell_type": "code",
89+
"execution_count": null,
90+
"metadata": {
91+
"jupyter": {
92+
"outputs_hidden": true
93+
}
94+
},
95+
"outputs": [],
96+
"source": [
97+
"# %load solutions/bad-pass-pass1-widgets.py"
98+
]
99+
},
100+
{
101+
"cell_type": "markdown",
102+
"metadata": {},
103+
"source": [
104+
"## Calculate the password...\n",
105+
"\n",
106+
"The function below calculates the password and should set the value of the `password_text` widget. The first part has been done, you just need to add the line that sets the widget value."
107+
]
108+
},
109+
{
110+
"cell_type": "code",
111+
"execution_count": null,
112+
"metadata": {
113+
"jupyter": {
114+
"outputs_hidden": true
115+
}
116+
},
117+
"outputs": [],
118+
"source": [
119+
"def calculate_password(change):\n",
120+
" import string\n",
121+
" from secrets import choice\n",
122+
" length = change.new\n",
123+
" # Generate a list of random letters of the correct length.\n",
124+
" password = ''.join(choice(string.ascii_letters) for _ in range(length))\n",
125+
" # Add a line below to set the value of the widget password_text\n"
126+
]
127+
},
128+
{
129+
"cell_type": "code",
130+
"execution_count": null,
131+
"metadata": {
132+
"jupyter": {
133+
"outputs_hidden": true
134+
}
135+
},
136+
"outputs": [],
137+
"source": [
138+
"# %load solutions/bad-pass-pass1-passgen.py"
139+
]
140+
},
141+
{
142+
"cell_type": "markdown",
143+
"metadata": {},
144+
"source": [
145+
"## ...and link password to widgets\n",
146+
"\n",
147+
"Fill in the line below. You want `calculate_password` to be called when the value of `password_length` changes. Here is a link to [Widget Events](06-Widget_Events.ipynb) in case you need it."
148+
]
149+
},
150+
{
151+
"cell_type": "code",
152+
"execution_count": null,
153+
"metadata": {
154+
"jupyter": {
155+
"outputs_hidden": true
156+
}
157+
},
158+
"outputs": [],
159+
"source": [
160+
"# call calculate_password whenever the password length changes"
161+
]
162+
},
163+
{
164+
"cell_type": "code",
165+
"execution_count": null,
166+
"metadata": {
167+
"jupyter": {
168+
"outputs_hidden": true
169+
}
170+
},
171+
"outputs": [],
172+
"source": [
173+
"# %load solutions/bad-pass-pass1-observe.py"
174+
]
175+
},
176+
{
177+
"cell_type": "markdown",
178+
"metadata": {},
179+
"source": [
180+
"Now that the connection is made, try moving the slider and you should see the password update."
181+
]
182+
},
183+
{
184+
"cell_type": "markdown",
185+
"metadata": {},
186+
"source": [
187+
"<!--NAVIGATION-->\n",
188+
"< [*OPTIONAL* Three approaches to events](02.01-OPTIONAL-Widget_Events_2.ipynb) | [*OPTIONAL* Separating the logic from the widgets](02.03-OPTIONAL-Widget_Events_2--Separating_Concerns.ipynb) >"
189+
]
190+
}
191+
],
192+
"metadata": {
193+
"kernelspec": {
194+
"display_name": "Python 3",
195+
"language": "python",
196+
"name": "python3"
197+
},
198+
"language_info": {
199+
"codemirror_mode": {
200+
"name": "ipython",
201+
"version": 3
202+
},
203+
"file_extension": ".py",
204+
"mimetype": "text/x-python",
205+
"name": "python",
206+
"nbconvert_exporter": "python",
207+
"pygments_lexer": "ipython3",
208+
"version": "3.8.5"
209+
}
210+
},
211+
"nbformat": 4,
212+
"nbformat_minor": 4
213+
}

0 commit comments

Comments
 (0)