Modern Python Projects Transcripts
Chapter: Let's build a CLI
Lecture: First version of uptimer

Login or purchase this course to watch this video and the rest of the course contents.
0:00 So I start with an empty folder,
0:06 and as you can see, I already have poetry install.
0:08 So to start the project, using a poetry,
0:10 we would have to run poetry new and the name of the project.
0:18 I'm going to call my up time monitoring to uptimer,
0:21 but before we do that, let's talk about where poetry stores the virtual environments.
0:27 By default. Poetry stores the virtual environments outside of the project folder.
0:31 If we want poetry to store them inside the project,
0:34 we can modify the poetry configuration and said the virtualenvs.inproject option to true
0:40 So let's do that. If you see that error message,
0:55 it means I used a wrong config option.
0:58 It actually should be without the settings.
1:01 Okay, now we are good.
1:02 So now we can run poetry New.
1:04 and poetry will create a virtual environments in the current folder.
1:08 So later, when we use VSCode,
1:10 VSCode will automatically detect this virtual environment so it will be more convenient to
1:15 use it like that. Well,
1:16 let's create a project. And now let's add our dependencies.
1:38 I want to use the latest version of each of those tools. So I'm not providing
1:42 a specific version and we get a error because poetry is still using pytest py.
1:48 So let's fix that. Let's go to the pyproject toml and remove pytest from
1:53 there. And let's rerun. Okay,
2:05 we have all the dependencies installed and pinned.
2:09 Now we can open VSCode and start writing some code.
2:13 The default convention with poetry is that inside of your project,
2:17 you will have a folder called the Same as your projects and inside of that folder
2:21 this is the place where you should put all your python files.
2:26 Well, let's go inside the uptimer.
2:30 We have the underscore init file(__init__) that tells python that
2:33 this is a python package. Inside,
2:37 we only have the version number,
2:39 so it's not very important. Let's actually go one folder up and open this folder
2:44 in the VSCode. Okay,
2:47 so, inside our uptimer,
2:49 let's create a file called,
2:51 And this is where we are going to store all the code
2:56 for our application. First, we need the function that will send ahead request and
3:01 return the status code. Let's write the standard python snippet that will execute some code
3:18 When you call this file with Python,
3:25 let's provide some random URL, I know at least one that should work,
3:35 and we get some errors because we have incorrect indentation, so you can run a command
3:41 called format file, format Document. And now we are good.
3:47 To test if this code works, we have to actually print something.
3:51 Let's run this code in the terminal to see if this actually works.
4:03 Perfect. So we got a status code 200 which means that my modernpythonProject
4:08 website is still up and running.
4:10 Let's change it, so that it can accept URL as an argument.
4:15 Well, let's write a new function that will check,
4:17 given URL. And now we have to mark this check command as a
4:32 click command. so we can do this with the decorator.
4:38 And ofcourse, we have to import click.
4:44 And we also have to tell Click that this URL parameter should be provided by a
4:48 user. So we do click arguments and that should work.
4:58 Let's try, agin, if we don't provide an argument,
5:05 we got this error message. So let's specify the URL here.
5:15 Let's other colorized output now. Since status is an integer,
5:26 we have to check if this integer starts with 100,200, 300, 400,or 500.
5:33 One way to do this is to write a nested if statement,
5:40 so let's actually start checking from 200.
5:43 So first we actually check if the state is divided by 100 then rounded down returns
5:49 true, this will be true for all the numbers from 200 to 299.
5:55 So that's what we need. So if the status is 200 we want to return
5:59 green text. Let's make sure that still works.
6:21 Perfect. We got some colors,
6:23 so let's take care of other statuses, in just in case we have a
6:43 different status. Let's also display it with a different color.
6:50 We can either go and try to find the website of this broken,
6:54 or we can use this website called,
6:59 It contains examples of different websites that return different response codes.
7:06 So let's take one with the status code 301 Okay,
7:11 that's not very useful. Copy link address.
7:23 I'm using 302, but it doesn't matter.
7:26 Perfect. It's yellow. Let's try a broken page.
7:33 Okay? And now 543 Cool.
7:36 So it's working. But what happens if we provide the URL that doesn't even exist
7:40 I really hope no one will go and register this domain to break my code.
7:48 So please don't do that.
7:50 Oh, now we have an exception.
7:54 So we're not handling the case when the website doesn't even exist.
7:57 So let's take care of that.
8:01 Let's simply catch this exception. And let's return an error message saying that this is
8:06 not a proper URL. That should work.
8:25 No, it doesn't. Like that,
8:36 Still wrong, Actually Let's do this here.
8:55 Okay, now it's fixed and the other website are still working.
9:09 We have 301, because I forgot to add the US here before we move
9:14 on. Let's clean up our code a bit.
9:17 I'm not a big fan of this huge if else statements,
9:20 So, let's try to refactor it a bit.
9:51 So, now we have a dictionary where the colors are corresponding to a key that we
9:55 get from dividing status by 100 and then rounding it down. We also need to add the
10:02 magenta color that we should get when none of the other colors feed.
10:07 So, let's add the default value of -1,
10:24 and that should work. We can remove all that and let's reformat.
10:32 Okay, this dictionary is now kind of ruined
10:35 but let's leave it like that.
10:37 Let's make sure it still works.
10:44 Okay, Cool. One more thing that I don't like is that we have to
10:47 call this poetry run python and the name of the file.
10:51 And that doesn't really feel like a proper CLI application.
10:55 I would prefer to call uptimer and the URL of the website.
11:00 Not all this long command. And we can actually actually that very easily, we can
11:05 go to the poetry settings and define a script there.
11:11 While we are here, we can also move pytest and sphinx to the dev dependencies
11:16 just to indicate that they are part of.
11:19 Dev dependency, is not part of the dependencies for our final package.
11:24 The difference here is that if you want to install this up time on the production
11:28 server, you can call poetry,
11:31 install --no-dev
11:33 and it will install everything from poetry dependencies,
11:36 but not from poetry dev dependencies.
11:39 So let's add a new section with our script when you type,
11:48 make sure you don't make any spelling errors.
11:51 For example, when I was first recording this part,
11:54 I made a typo, and instead of writing Tool,
11:56 I wrote tools. I got no error from poetry saying that this config value is
12:01 incorrect. And when I was trying to run my script,
12:03 I was getting some weird file,
12:05 not found error. But I spent like,
12:07 half on hour trying to fix this,
12:08 so, make sure you don't make the same mistake.
12:12 Under the poetry scripts, we can define some scripts and map them to some functions
12:17 in the code. So let's say I want to have a script called uptimer
12:22 and this should go inside my up timer package and call function check from my
12:31 file. Once you have that,
12:36 go back to the terminal and run poetry install to make sure that poetry recognizes the
12:41 script. And now we can do poetry.
12:46 Run uptimer. Great. We still have to add this poetry run because that's
13:01 the way to run our command inside the virtual environment of poetry.
13:06 But if we are inside of the poetry virtual environment,
13:09 which we can do by running poetry shell. from here,
13:14 we can just call uptimer.
13:22 So here it really feels like a proper CLI command.
13:26 And that's what we wanted to achieve.
13:28 So we have the first version of our uptimer ready. In the next video,
13:32 we're going to add more features to it.