📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

Makefiles in Python For Professional Automation

NeuralNine13:43

Transcription

What is going on guys? Welcome back! In today's video, we're going to learn how to use makefiles for Python in order to automate processes like building projects, installing requirements, and running scripts. So, let us get right into it.

[Music]

All right, so we're going to talk about makefiles in the Python context today. Now, makefiles are not something that belongs to the Python ecosystem. It's something that is language-independent. So, makefiles can be used in a C context, in a C++ context, Java context, and so on, with different libraries, different frameworks, different languages. And the basic idea is that we define certain procedures like building a project, installing requirements, running the project, setting up something, or cleaning the project, and stuff like that. We have these certain procedures defined with names and with sets of instructions, and we have all those defined in a makefile so that we don't always have to run the same commands. We can just say `make install`, `make run`, `make clean`, `make build`, and so on, to execute these procedures.

And today, we're going to look at what this looks like in Python. And for that, we're going to use a very simple structure. We're going to have a directory which we're going to call now, `my_package`. And inside of that directory, we're going to define a `main.py` file. Here, we're going to now say `print("Hello world")`. This is going to be our functionality. And then we're going to also define a file called `__init__.py`. This is basically just defining this as a package. So, when we have an `init` file in here, this is recognized as a package.

And then we also want to have, outside of this directory, another file which we're going to call `setup.py`. And for this, we're going to need a library called, or a package called, `setuptools`. So, we're going to open up the command line and we're going to type `pip install setuptools`. And this is going to be our build file. So, once you have `setuptools` installed, you can go into that file and we can say `from setuptools import setup, find_packages`. Let me just uh zoom out a little bit.

And then what we're going to do is we're going to say `setup()`. This is the function, and we're going to define a couple of things here. First of all, the name of the project is going to be, I don't know, `my_project_name`. Then we're going to say that the version is going to be `1.0`. And then we're going to say that the packages that we want to include in this, uh, in this final package, is going to be the result of `find_packages()`. So, we're going to call `find_packages()`. This is going to recognize the `my_package` since it has an `init` file in it, and then it's going to build it when we call it properly. That is the basic structure of what we want to do here.

Now, in this context, we can do a bunch of different things. So, first of all, we can run the script. We can just say `python main.py`. Then it's going to run the functionality. So, I can go here into my command line, which is just CMD. I can navigate to the directory, so to this one here, and then I can just say `python my_package/main.py`. So, this would be the running command.

Then I could do some other stuff, like I could build the project. How do I build the project? Quite simple: `python setup.py build bdist_wheel`. Because we want to have a wheel file with the final build. And this creates a `build` and a `dist` directory, and here we have the wheel file of the project. So, that is one thing that we can do.

But then again, you know, I can also go ahead and delete all of that. So, I can go ahead and say, okay, if the directories exist, I can just call `rd /s /q` on the `build` directory to remove it. I can do the same thing on the `dist` directory, and then those directories are gone. So, that would be a cleanup.

And then we can also, uh, install requirements. So, I can specify here a file `requirements.txt`. I can provide `setuptools` here as a requirement, and you can also provide some other, uh, packages, whatever. And in order to install these requirements, what we do is we say `pip install -r requirements.txt`. And then it installs `setuptools` in this case, which is already installed.

And those are the processes that we have here. Those are the procedures that we would like to have professionally and simply in a makefile. Now, why do we want to have that? Because it's quite tedious to always do the same stuff. So, let's say I do some changes. I make some changes. I go into the `main` file, and I don't want to print "Hello world" now, I want to print "Hello world now". I changed something. I want to rebuild the whole thing. What do I have to do? First of all, maybe I want to run it. That's not too complicated. I run it, I see it works. Okay, now I want to build again. So, I have to say, uh, `python setup.py build bdist_wheel`. I have to remember the commands. And maybe you even have some more complicated procedures. And also the cleanup. You have to clean up multiple directories. You have to also remove this directory here, which is also quite tedious to do it every time yourself. So, you can just have all this under the name of one procedure. And this is done using makefiles. That is the purpose of a makefile.

And in order to create a makefile, we just create here a new file. And the important thing is the makefile has to be called `Makefile` with a capital M. So, we want to call it `Makefile` like this. And in this case, in PyCharm, I already have, um, a plugin that recognizes makefiles. The important thing about makefiles, as far as I understand, is that we have to use tabs instead of spaces. So, when you have something like `some_command:` and you want to define what the command is, you have to tab into that command. You are not allowed to use spaces. So, you're not allowed to use one, two, three, four. It has to be a tab. This is important for makefiles.

Now, before we define the actual makefile, one thing that's important is, uh, that you have to be able to run makefiles. Now, if you have the Windows Subsystem for Linux, that's quite simple because on Windows Subsystem for Linux, we can just use `make`, and it is going to look for makefiles. So, if I say `make`, it will say "no makefile found" because there is no makefile on my desktop. If there is a makefile, it's going to recognize that and execute it. On Windows, that's not the case by default. Now, in my case, it is the case because I already have `make` installed. But by default, you don't have `make` on Windows. What you need to do in order to get `make` on Windows is you either have to go and download the installer. You will find hopefully a link in the description down below. Or the simple way is to install, uh, I'm not sure what it's pronounced, `choco` or something like that. It's written like that: `choco`. I think that's, that's the name of the tool. And once you have this command-line tool installed, you can just, hopefully, find a link in the description down below on how to get this. Once you have `choco` installed, you can just say `choco install make`. And then you're going to be able to use the `make` command. So, this is what you want to have in order to be able to execute these, um, commands here.

So, what we're going to do now is we're going to say that we have a procedure `run`. And the `run` procedure is going to just say `python my_package/main.py`. Then I want to have one `install`. This is just going to say `pip install -r requirements.txt`. Then I want to have one `build`. `build` is going to be `python setup.py build bdist_wheel`. And then I want to have one `clean`, for example, where I want to say `rd /s /q` the `build`. That's basically, uh, not exactly the same, I think, but roughly the same as `rm -rf` on, so `rm -rf` on Linux. But you want to do this here for `build`, you want to do this here for `dist`. We want to do this, uh, what was the name? I think now I don't know what the name of the third directory was. Maybe we have to build it first. So, let's go ahead: `python setup.py build bdist_wheel`. Then it should create directories again. It's `my_project_name.egg-info`. So, `rd /s /q my_project_name.egg-info`. And the important thing here on Windows is, if you don't want this to crash, you need to also say `if exist` and then in quotation marks `./build` if that directory exists, only then do all of this. Because the important thing is, if it tries to delete something that does not exist, it's going to crash. It's not going to do anything. And this also means that if you have, for example, the `dist` directory, but the `build` is already deleted, it's not going to execute the second command because you don't have, uh, by the way, it's not `exists`, it's `exist` without the S. Um, but you need to make sure that what you're trying to do here actually works because otherwise it's not going to execute the other command. So, for example, if `build` does not exist and I'm not checking here, then it's also not going to delete this because it's going to crash here. That's what I'm trying to say.

So, this is now the `Makefile`. We can go into our command line on Windows here, the CMD command line, and I can say now `make install`. And you can see it runs `pip install -r requirements`. And then I can do `make run`. And then it says "Hello worlds". Um, I can also say `make build`. `build` is up to date, which basically means that nothing changes if I run `build` because we already have all of this here. Um, and because of that, I can do `make clean`. And `make clean` is going to delete these directories. Now you can see they're gone. Um, and then I can say `make build`. And usually, oftentimes, you have something like `make all` if necessary. In this case, probably doesn't make a lot of sense, but you can chain commands. So, if you have multiple things that have to be done in a row, you can just say `make all`, and it's going to do all of them in a row, all these procedures in a row.

But yeah, this is how you can automate this. And what you can also do here, which I didn't do, is you can provide also certain files that need to exist. So, I can say `build: setup.py` and `install: requirements.txt`. Which basically means that this command is not going to be executed if the file does not exist, right? So, that's important as well, sometimes.

Now, one thing that you might be wondering is, um, what do I do if I have different commands on Linux and on Windows? So, if I use this `Makefile` on Windows, it might work. But what if I want to use it on Linux? On my Linux subsystem, for example, if I go to, uh, if I go to the directory here, I think some of it will work, but actually not because `python` is not the command that we have to use on Linux. Here, it's `python3`, and it's also not `pip`, it's `pip3`. And it's also not `rd /s /q`, it's `rm -rf`. So, how do I change the commands based on the operating system? Quite simple. We can go up here and we can say `ifneq ($(OS), Windows_NT)`. This basically means if the operating system is not Windows NT, then do all of this. Define all of this. Otherwise, we can then copy all of this here and basically this is now Linux, and Mac, and other operating systems. You can define an `endif` down here. And now we can change the command. So, `python3`, `pip3`, `python3`. And here we can just do `rm -rf`. So, actually, can I? There you go. Oh, actually, what do I want to do? I want to do, let me just do it like that: `rm -rf` like this. So, those would now be the Linux commands.

And if I now go into Linux and I say `make run`, you can see it works. I can also say `make install`. And you can see this works. I can do `make clean`. Works as well. And `make build`. And you can see this works as well. And if I now try to do `make build` again, you will see that it says it's up to date. Nothing changes if I run this again.

So, this is how you professionally use makefiles in the context of Python. So, that's it for today's video. I hope you enjoyed it and hope you learned something. If so, let me know by hitting a like button and leaving a comment in the comment section down below. And of course, don't forget to subscribe to this channel and hit the notification bell to not miss a single future video for free. Other than that, thank you much for watching. See you next video and bye.

[Music]