1
00:00:00,360 --> 00:00:02,100
In the previous lessons today,

2
00:00:02,250 --> 00:00:07,250
we looked at how we can use the JSON format to store and load data into our

3
00:00:08,880 --> 00:00:09,713
program.

4
00:00:10,050 --> 00:00:15,050
We also looked at how we can use the try, except, else, and finally keywords to

5
00:00:15,750 --> 00:00:20,750
handle exceptions in our program to make sure that it doesn't fail and end up

6
00:00:21,540 --> 00:00:26,010
crashing our program so the user ends up with a bad user experience.

7
00:00:26,430 --> 00:00:30,810
Instead, we can anticipate the things that might happen. For example,

8
00:00:30,810 --> 00:00:32,640
the first time when we run our program,

9
00:00:32,850 --> 00:00:37,740
we might not have a data.json file and we deal with it accordingly.

10
00:00:38,520 --> 00:00:42,720
Now, all that's left to do is to put in the last bit of functionality,

11
00:00:42,840 --> 00:00:45,960
which is the search functionality, because after all,

12
00:00:45,960 --> 00:00:49,680
we don't want to be digging through a JSON file to find out all email and

13
00:00:49,680 --> 00:00:52,800
password combinations for the websites that we've stored.

14
00:00:53,460 --> 00:00:57,300
So what we want to be able to do is to add a search button

15
00:00:57,540 --> 00:01:02,160
and it's going to look very similar in size to the generate password button

16
00:01:02,520 --> 00:01:06,210
and it's going to be in the same grid column. Now,

17
00:01:06,240 --> 00:01:09,660
when we type in a website and we hit search,

18
00:01:09,870 --> 00:01:13,110
it's going to look through our JSON, find that data,

19
00:01:13,650 --> 00:01:18,650
load that data up and look through it for a key that matches the one the user

20
00:01:19,680 --> 00:01:21,750
typed in. If they find it,

21
00:01:21,900 --> 00:01:26,900
then we get a pop up showing up and it tells us the email and the password

22
00:01:27,030 --> 00:01:29,040
that's associated with that account.

23
00:01:30,060 --> 00:01:35,040
So you've actually done all of this before. Creating tkinter widgets,

24
00:01:35,310 --> 00:01:37,350
laying out tkinter widgets,

25
00:01:37,650 --> 00:01:42,650
creating message boxes or these popups and giving it a title,

26
00:01:42,840 --> 00:01:44,160
giving it a message.

27
00:01:44,520 --> 00:01:49,520
You've also seen how you can load JSON data and get the data in the format of a

28
00:01:52,260 --> 00:01:55,920
Python dictionary. Now, once you have the Python dictionary,

29
00:01:55,980 --> 00:02:00,660
then you can use your usual dictionary methods to try and get hold of the data

30
00:02:00,660 --> 00:02:02,880
that's inside. And finally,

31
00:02:02,910 --> 00:02:06,030
you also know how to deal with exceptions.

32
00:02:06,330 --> 00:02:10,020
So remember, there might also be an exception in this case,

33
00:02:10,410 --> 00:02:15,120
because if this was the first time that we were running this password manager,

34
00:02:15,480 --> 00:02:16,110
and in fact,

35
00:02:16,110 --> 00:02:21,110
we hadn't stored any websites or any emails or passwords in our database,

36
00:02:21,450 --> 00:02:25,230
then if you hit search, it might actually just give you a file

37
00:02:25,230 --> 00:02:29,820
not found error as well. So there's quite a few components involved,

38
00:02:29,910 --> 00:02:33,060
but I'm pretty sure that you can actually get this to work.

39
00:02:33,690 --> 00:02:38,040
So the end outcome you're looking for looks something like this in terms of

40
00:02:38,040 --> 00:02:38,873
layout,

41
00:02:39,120 --> 00:02:44,120
and you should be able to test this so that when you start out without a data

42
00:02:45,150 --> 00:02:49,290
.json file and you hit search, it should tell you error,

43
00:02:49,530 --> 00:02:50,970
No data file found.

44
00:02:51,450 --> 00:02:56,310
But, if you had saved a password under that name and you added it to the

45
00:02:56,310 --> 00:02:58,770
database, then you try to find it,

46
00:02:59,080 --> 00:03:02,200
then it should find you the email and the password that you saved.

47
00:03:02,590 --> 00:03:04,180
So this is what you're aiming for

48
00:03:04,330 --> 00:03:07,900
and I'm pretty sure that you can do it with just a little bit of thought and 

49
00:03:07,900 --> 00:03:11,590
a little bit of time spent problem-solving. Once you're ready,

50
00:03:11,710 --> 00:03:15,910
pause the video and give this final challenge a go to complete the password

51
00:03:15,910 --> 00:03:16,380
manager

52
00:03:16,380 --> 00:03:18,030
project. Good luck.

53
00:03:22,440 --> 00:03:23,440
Alright, so I hope

54
00:03:23,880 --> 00:03:27,750
you gave that a good go. And as I always say, if there's no struggle,

55
00:03:27,750 --> 00:03:28,620
there's no learning.

56
00:03:28,920 --> 00:03:33,900
So make sure that you've allocated at least 20 minutes to trying things out and

57
00:03:33,900 --> 00:03:38,790
figuring things out and debugging and just messing with the code yourself before

58
00:03:38,790 --> 00:03:41,280
you're coming to the solution. But all right,

59
00:03:41,340 --> 00:03:43,530
I'm going to walk through the solution with you together.

60
00:03:44,130 --> 00:03:49,050
And the first thing we're going to do is we're going to add a button next to our

61
00:03:49,050 --> 00:03:50,280
website entry.

62
00:03:51,360 --> 00:03:56,360
So right here. Now notice how we've got our three columns in our grid system.

63
00:03:57,450 --> 00:04:02,450
So our search button is going to go in pretty much in the same column as our

64
00:04:02,490 --> 00:04:07,350
generate password button. So let's go ahead and create our

65
00:04:07,530 --> 00:04:09,120
search button.

66
00:04:10,470 --> 00:04:14,850
This is going to be a button with the text that says

67
00:04:15,300 --> 00:04:16,132
Search.

68
00:04:17,519 --> 00:04:21,630
Now, once we've created that, let's go ahead and lay it out

69
00:04:21,630 --> 00:04:23,250
uusing the grid system.

70
00:04:23,970 --> 00:04:28,970
Now the search button is going to go onto the grid in the same row as the

71
00:04:29,550 --> 00:04:34,290
website label and the website entry. So that is row 1.

72
00:04:34,560 --> 00:04:38,940
So let's go ahead and add row equals 1 and column-wise,

73
00:04:38,970 --> 00:04:42,600
it's going to go in the same column as the generate password.

74
00:04:42,990 --> 00:04:47,730
So that is a column 2. Now, if we run our code, as it is

75
00:04:47,730 --> 00:04:48,450
however,

76
00:04:48,450 --> 00:04:53,280
you'll see that the search button seems to be sitting inside the entry.

77
00:04:53,790 --> 00:04:57,210
And the reason is because initially when we created this entry,

78
00:04:57,240 --> 00:04:59,520
we gave it a column span of 2

79
00:04:59,880 --> 00:05:03,690
so that it spans this second and third column.

80
00:05:04,260 --> 00:05:05,670
So we have to change that.

81
00:05:06,150 --> 00:05:11,150
Let's go and find our website entry and delete this column span equals 2.

82
00:05:12,150 --> 00:05:16,260
So now you can see that this has a column span of 1,

83
00:05:16,260 --> 00:05:18,300
so it's only in this middle column,

84
00:05:18,660 --> 00:05:23,010
but it's so large that it's pushing the rest of our layout out of the way.

85
00:05:23,580 --> 00:05:26,520
So what we need to do is we need to make this entry

86
00:05:26,700 --> 00:05:29,220
the same width as the password entry

87
00:05:29,490 --> 00:05:31,860
so that it'll actually fit into our layout.

88
00:05:32,490 --> 00:05:35,550
So our password entry has a width of 21.

89
00:05:35,850 --> 00:05:40,850
So our website entry is also going to need to change down to a smaller size.

90
00:05:42,750 --> 00:05:47,750
Now you can see the entry is now the same size and its looking a lot better. If

91
00:05:47,970 --> 00:05:51,540
you want, and this is really not strictly necessary

92
00:05:51,570 --> 00:05:56,520
but I think it's quite neat, is you can tweak and adjust the width of this search

93
00:05:56,520 --> 00:06:00,440
button so that it's roughly the same as the generate password button.

94
00:06:01,130 --> 00:06:05,540
Now this button is this width because it's what is needed to accommodate all of

95
00:06:05,540 --> 00:06:09,710
the words in that button, but we can manually change the search button

96
00:06:09,950 --> 00:06:11,990
so that it's about the same width.

97
00:06:13,790 --> 00:06:18,770
And in this case, I'm literally just using trial and error to figure it out. Width as

98
00:06:18,770 --> 00:06:23,210
10 looks maybe a little bit small, let's try width of 13

99
00:06:23,750 --> 00:06:28,280
and it looks just about right. Now that I'm done with my layout,

100
00:06:28,490 --> 00:06:32,420
it's onto the next part which is adding functionality.

101
00:06:33,110 --> 00:06:36,890
Now the functionality is going to come when the search button is pressed.

102
00:06:37,250 --> 00:06:39,620
So I'm going to add a command to this

103
00:06:40,280 --> 00:06:45,280
and the command is going to call a method which I'll call find_password. We've

104
00:06:46,370 --> 00:06:49,970
got generate_password and we'll now have find_password.

105
00:06:50,690 --> 00:06:54,680
Now I'm going to go and create my find_password.

106
00:06:56,090 --> 00:06:59,450
And just because we've got all these sections set up, I'm going to add 

107
00:06:59,450 --> 00:07:04,450
another section which I'll call find_password. Inside

108
00:07:05,270 --> 00:07:08,270
the section is where we're going to be creating our

109
00:07:08,300 --> 00:07:12,980
find_ password function. And this find_password,

110
00:07:13,040 --> 00:07:15,380
let's just check to make sure there were no errors here

111
00:07:15,380 --> 00:07:16,910
and we've spelled at the same way.

112
00:07:17,720 --> 00:07:22,720
And this find_password function is going to need to get hold of the entry

113
00:07:23,360 --> 00:07:25,550
that's inside the website entry.

114
00:07:26,480 --> 00:07:31,480
So the website that we're looking for comes from the website_entry.get,

115
00:07:32,000 --> 00:07:36,440
and then we'll be able to get the value of whatever the user typed inside this

116
00:07:36,440 --> 00:07:37,273
entry.

117
00:07:37,640 --> 00:07:42,050
And then we're going to use that to search through our data.json.

118
00:07:42,890 --> 00:07:47,890
Now the easiest way for this to work is actually to first add a website.

119
00:07:48,020 --> 00:07:53,020
So I'm just going to generate a website with my email and password and add it so

120
00:07:53,660 --> 00:07:56,510
that it gets saved inside my data.json.

121
00:07:56,960 --> 00:08:00,320
This way I'll be able to print things and I'll be able to work with the data a

122
00:08:00,320 --> 00:08:01,160
little bit easier.

123
00:08:01,730 --> 00:08:04,490
And then we'll address the exception catching a little bit later on.

124
00:08:05,120 --> 00:08:07,400
What exactly are we looking for? Well,

125
00:08:07,430 --> 00:08:11,960
we're looking to load up the data inside this JSON file.

126
00:08:12,470 --> 00:08:14,780
So we're going to be opening up that file.

127
00:08:14,780 --> 00:08:19,250
So with open and then the filename is data.json,

128
00:08:19,610 --> 00:08:22,520
and then we'll save this as the data_file.

129
00:08:24,350 --> 00:08:26,660
Now, once we've got our data file,

130
00:08:26,660 --> 00:08:30,830
then we can use our JSON module to load up that file

131
00:08:31,340 --> 00:08:34,970
and we're going to be getting hold of the data that's inside.

132
00:08:35,240 --> 00:08:38,720
So we can save this to a variable called data.

133
00:08:39,350 --> 00:08:42,559
Now this data, if I go ahead and print it,

134
00:08:43,370 --> 00:08:47,570
you should remember is basically just a dictionary.

135
00:08:48,020 --> 00:08:51,770
So as soon as I hit search, that should trigger this find_password

136
00:08:52,100 --> 00:08:54,800
and now I've got my dictionary printed in here.

137
00:08:55,500 --> 00:08:58,740
So what do we want to do with this dictionary? Well,

138
00:08:58,740 --> 00:09:03,740
we want to look through it and check to see if this website that we're searching

139
00:09:04,020 --> 00:09:07,320
for actually exists inside that dictionary.

140
00:09:07,950 --> 00:09:12,950
The way we do that is we say if website in data,

141
00:09:15,030 --> 00:09:18,300
well, in that case, it's actually success, right?

142
00:09:18,300 --> 00:09:21,030
We've managed to find it inside the data

143
00:09:21,300 --> 00:09:25,170
and we now just need to get hold of the email and password values.

144
00:09:26,580 --> 00:09:31,580
So let's create a variable called email and we want to pick out this particular

145
00:09:31,860 --> 00:09:34,050
value from this dictionary.

146
00:09:34,740 --> 00:09:36,930
If this is the entire dictionary,

147
00:09:37,230 --> 00:09:42,230
then we want to get hold of the dictionary and pick out the item with the key

148
00:09:42,900 --> 00:09:47,280
that matches the website that we're searching for, like this.

149
00:09:47,880 --> 00:09:50,490
Now, once we've gotten hold of this,

150
00:09:50,550 --> 00:09:53,220
this is going to be a nested dictionary.

151
00:09:53,250 --> 00:09:57,690
So it's equivalent to basically this part of the dictionary.

152
00:09:58,290 --> 00:10:00,210
So this in itself is the dictionary,

153
00:10:00,240 --> 00:10:02,190
which you could save to a separate variable,

154
00:10:02,490 --> 00:10:07,380
but I think it's actually easy enough to understand that we can tag on another

155
00:10:07,380 --> 00:10:08,213
key here

156
00:10:08,310 --> 00:10:13,310
which is the word email in order to get hold of the value that's associated with

157
00:10:13,830 --> 00:10:15,480
that key. So that way,

158
00:10:15,480 --> 00:10:18,840
this email variable now saves this value here.

159
00:10:19,590 --> 00:10:23,880
And in the same way, we can get the password from data

160
00:10:24,060 --> 00:10:29,060
getting hold of the data under the website key and then passing in the password

161
00:10:29,850 --> 00:10:33,780
key. Now that we've got the email and password,

162
00:10:33,840 --> 00:10:38,840
we can go ahead and create our message box using show info. And we'll set the

163
00:10:39,210 --> 00:10:43,020
title to be the website that the user is searching for

164
00:10:43,470 --> 00:10:46,320
and the message is going to be a f-string,

165
00:10:46,710 --> 00:10:49,950
which has the email listed.

166
00:10:50,640 --> 00:10:52,710
And then on a new line,

167
00:10:52,740 --> 00:10:57,000
it's also got the password that's going to be listed as well.

168
00:10:58,400 --> 00:10:59,233
Like that.

169
00:11:01,160 --> 00:11:04,460
Let's go ahead and run this code and make sure that it works.

170
00:11:05,690 --> 00:11:10,310
Let's say that we have a couple more passwords that we save in here.

171
00:11:11,900 --> 00:11:15,590
Now I should have three entries, Amazon, eBay, and Twitter,

172
00:11:15,980 --> 00:11:19,460
and I want to go and search for my password for eBay.

173
00:11:19,940 --> 00:11:24,770
Once I hit the search button, it goes into that find_password function

174
00:11:25,130 --> 00:11:28,880
and if it finds that one of these has the key eBay,

175
00:11:29,210 --> 00:11:34,130
then it's going to fetch all of these relevant pieces of data that I wanted from

176
00:11:34,160 --> 00:11:35,540
that JSON file.

177
00:11:37,010 --> 00:11:42,010
So now what we have to do is to make sure that we catch any exceptions that

178
00:11:42,740 --> 00:11:47,740
might occur and you might already have realized that this works really well

179
00:11:48,110 --> 00:11:50,240
right now because we have data

180
00:11:50,630 --> 00:11:53,260
and because we have this data.json file.

181
00:11:53,860 --> 00:11:57,250
But the first time that I run my program,

182
00:11:57,490 --> 00:11:59,140
this is not going to exist.

183
00:11:59,650 --> 00:12:04,600
So this is a more realistic version of what the program will look like

184
00:12:04,660 --> 00:12:09,340
the first time we run it. And the first time that we go ahead and run this

185
00:12:09,430 --> 00:12:13,870
and I search for something that is going to look for a file that doesn't exist

186
00:12:14,110 --> 00:12:18,340
immediately, our program crashes, and we get the file not found error.

187
00:12:18,970 --> 00:12:23,740
So what we need to do is we need to be aware enough that these things like

188
00:12:23,770 --> 00:12:26,020
opening files can fail.

189
00:12:26,440 --> 00:12:31,420
So what we have to do is we have to catch the exceptions and handle them.

190
00:12:32,080 --> 00:12:37,000
Let's go ahead and indent this entire block and put it inside the try.

191
00:12:37,570 --> 00:12:40,300
Now, the part that's most likely to fail in fact,

192
00:12:40,330 --> 00:12:44,050
the first time the program starts, this is definitely going to fail.

193
00:12:44,710 --> 00:12:48,640
But what we want to do is we want to catch the exception

194
00:12:48,670 --> 00:12:53,020
that is file not found error. And in the situation,

195
00:12:53,050 --> 00:12:57,820
what we want to do is we want to create a message box that tells the user

196
00:12:58,120 --> 00:13:00,430
this data file doesn't exist.

197
00:13:01,060 --> 00:13:03,340
This is just a simple showinfo

198
00:13:03,700 --> 00:13:08,700
and we'll give it a title of error and we'll give it a message of no data file

199
00:13:12,730 --> 00:13:13,563
found,

200
00:13:15,220 --> 00:13:19,420
or you can put any other message you can think of. However,

201
00:13:19,420 --> 00:13:22,060
if we were successful in opening this file,

202
00:13:22,420 --> 00:13:25,720
then this is the part of the code that we want to implement.

203
00:13:26,140 --> 00:13:29,230
So let's go ahead and bring it up to the right indentation.

204
00:13:29,680 --> 00:13:31,360
And we searched through our data,

205
00:13:31,690 --> 00:13:36,690
look for this website and then give the user a popup if it exists.

206
00:13:37,620 --> 00:13:41,910
Now, if we run our code again and we search for something

207
00:13:42,060 --> 00:13:45,720
even though we don't have a data file, we haven't saved anything yet,

208
00:13:46,050 --> 00:13:49,830
then we get this error popup and it tells us no data files found.

209
00:13:50,160 --> 00:13:51,930
And hopefully the user would realize, well,

210
00:13:51,930 --> 00:13:54,060
actually I haven't actually saved any passwords.

211
00:13:54,900 --> 00:13:58,620
So there's one other situation that we haven't yet addressed however.

212
00:13:59,280 --> 00:14:02,820
If I had, um, let's say Amazon, um,

213
00:14:02,970 --> 00:14:07,970
eBay and Twitter saved in my JSON file,

214
00:14:10,680 --> 00:14:13,680
but I decided to search for something that I never saved.

215
00:14:13,830 --> 00:14:18,780
Let's say my details for Facebook. Well in this situation, actually

216
00:14:18,810 --> 00:14:23,220
nothing really happens. And it's a little bit confusing because for the user,

217
00:14:23,220 --> 00:14:27,300
it seems like our program just doesn't work. But in fact, we

218
00:14:27,300 --> 00:14:31,350
as the programmers know what the problem is. It's basically this

219
00:14:31,560 --> 00:14:36,510
if statement is coming out as false. The website doesn't exist in the data.

220
00:14:36,960 --> 00:14:40,920
So none of this gets carried out and the function ends.

221
00:14:41,460 --> 00:14:45,030
That's probably not the best user experience. Instead,

222
00:14:45,060 --> 00:14:49,560
we probably want to catch it with an else statement and we want to use a message

223
00:14:49,560 --> 00:14:52,430
box to tell the that again,

224
00:14:52,670 --> 00:14:55,010
there is a error in this situation

225
00:14:55,850 --> 00:14:59,090
but the reason for this error is because

226
00:15:01,940 --> 00:15:06,380
there are no details that currently exist for the website that they're searching

227
00:15:06,380 --> 00:15:08,030
for. That way

228
00:15:08,060 --> 00:15:13,060
they're not sitting there confused as to why searching for some sort of website

229
00:15:13,910 --> 00:15:15,410
doesn't actually come up with anything.

230
00:15:15,680 --> 00:15:19,070
It tells them that there are no details and they would have to add it

231
00:15:19,280 --> 00:15:21,410
if they wanna find it in the database.

232
00:15:22,400 --> 00:15:24,770
A lot of students might be wondering at this point, well,

233
00:15:24,950 --> 00:15:27,680
why don't we catch this with some sort of exception?

234
00:15:29,240 --> 00:15:32,570
And in fact, we could create an exception.

235
00:15:32,570 --> 00:15:36,890
We could raise an exception here and then we could catch it somewhere else and

236
00:15:36,920 --> 00:15:38,390
show this message box.

237
00:15:38,780 --> 00:15:43,780
But the thing you want to keep in mind is that if you can do something with if

238
00:15:44,000 --> 00:15:47,690
and else very easily, then you should stick to if and else.

239
00:15:48,170 --> 00:15:52,460
If you can't do it with if and else very easily, and it's actually an error

240
00:15:52,460 --> 00:15:55,910
that's going to be thrown that you don't have any other way of dealing with,

241
00:15:56,210 --> 00:16:00,950
then you should be using the try, except, else, finally, keywords.

242
00:16:01,670 --> 00:16:03,500
And in fact, if you think about this,

243
00:16:03,920 --> 00:16:08,920
I don't have an easy way of checking to see if this data file ends up being not

244
00:16:10,490 --> 00:16:14,660
found. But I do have this file not found error

245
00:16:14,660 --> 00:16:18,230
which is going to be thrown every time that I try to open a file and that

246
00:16:18,230 --> 00:16:19,010
doesn't exist.

247
00:16:19,010 --> 00:16:24,010
The other way to think about it is that an exception is something that is

248
00:16:24,020 --> 00:16:27,560
meant to be exceptional. It's something that happens very rarely.

249
00:16:28,100 --> 00:16:32,120
Whereas if and else catches things that happen frequently.

250
00:16:32,420 --> 00:16:36,290
It's pretty often that your user might search through the website

251
00:16:36,530 --> 00:16:40,550
thinking that they saved some sort of details for a website. But in fact,

252
00:16:40,580 --> 00:16:43,970
they didn't. Think about this when you're writing your code

253
00:16:44,090 --> 00:16:49,090
and remember that only use exception handling when you don't have an easy

254
00:16:49,520 --> 00:16:52,100
alternative. There you have it.

255
00:16:52,430 --> 00:16:56,990
That's the completed code for our upgraded password manager.

256
00:16:57,500 --> 00:16:59,750
If you want to take a look at any of this code,

257
00:16:59,810 --> 00:17:02,570
then, as always, head over to the course resources

258
00:17:02,870 --> 00:17:06,319
and you'll see a link to the completed code that you can review.

259
00:17:06,859 --> 00:17:08,150
But in today's lessons,

260
00:17:08,390 --> 00:17:13,369
we added a lot more knowledge regarding things like error handling and saving

261
00:17:13,369 --> 00:17:18,369
data in JSON formats and handling and loading and updating and dealing with

262
00:17:18,530 --> 00:17:23,530
all of that data in order to create this fully-fledged password manager project.

263
00:17:24,829 --> 00:17:27,920
Now, I'm sure there's a lot more improvements you can add to this,

264
00:17:28,160 --> 00:17:31,880
but it's going to go beyond the allocated time for today's lessons.

265
00:17:32,330 --> 00:17:33,163
So if you want,

266
00:17:33,170 --> 00:17:37,550
please continue messing around with the code and improving it and make your own

267
00:17:37,550 --> 00:17:39,590
customizations and modifications.

268
00:17:39,920 --> 00:17:41,810
If you create something that you thought was cool,

269
00:17:41,840 --> 00:17:46,340
then be sure to share it with us in the Q/A below the lesson so that we can

270
00:17:46,340 --> 00:17:50,810
all admire your hard work and maybe improve our own code as a result.

271
00:17:51,380 --> 00:17:55,880
So have fun playing around with this program and I'll see you tomorrow.

