Submind YouTube summaries
Thumbnail for Creating a command-line app in Python [PythonLiveLessons #4]

Creating a command-line app in Python [PythonLiveLessons #4]

Watch on YouTube

Video summary

In this episode of Python Live Lessons, Sebastien Amato continues the series on building a command-line application in Python by transforming a previously created module called `markdown_code_exec` into a standalone executable tool. The project's core functionality involves reading a Markdown file containing code blocks, executing that code within a controlled environment, and capturing the output to insert it back into the original text. Throughout the session, Amato emphasizes the importance of live interaction to address viewer questions in real-time, explaining how the application processes syntax like Python code blocks defined by triple backticks and curly braces to generate dynamic content directly within Markdown files. To convert the module into a command-line application, the presenter introduces the concept of an entry point, which is a specific function that serves as the main execution target when the script is run from the terminal. He creates a separate file named `markdown_code_exec.py` that imports this entry point function and utilizes the standard Python idiom `if __name__ == "__main__":` to ensure the application only runs when executed directly rather than when imported as a library. This structure allows the program to accept command-line arguments for input and output files, enabling users to specify source and destination paths using flags like `-i` and `-o`, or to pipe data through standard input and output streams for use in complex tool chains. The tutorial then delves into implementing argument parsing using the built-in `argparse` module, which simplifies the process of handling user inputs and generating helpful usage instructions via a `--help` flag. Amato demonstrates how to handle scenarios where no files are specified by reading from standard input and writing to standard output, effectively allowing the tool to be used in Unix-style pipelines. He also covers version control best practices by committing the changes to Git, staging the relevant files while ignoring generated outputs, and creating a release tag to mark this milestone as version 0.1.0, ensuring that the project's history is properly documented on GitHub. By the end of the episode, the module has been successfully evolved into a fully functional command-line utility capable of operating in multiple modes: processing specific files, handling piped input, and integrating with other tools. Amato concludes by summarizing the key takeaways, noting that creating a command-line app generally involves defining an entry point function, parsing arguments with libraries like `argparse`, and wrapping the logic in a top-level script that checks for direct execution. He briefly touches upon the differences between Python scripting and shell languages like PowerShell, reinforcing Python's versatility as a full programming language suitable for complex automation tasks beyond simple batch operations.
Read the full video transcript
to join a live broadcast of python live lessons tune in to my youtube channel sebastia amato every tuesday 10 p.m new delhi time 6 pm central european time and 9 am los angeles time hope to see you then and for now enjoy this episode [Music] hi everyone welcome to episode 4 the fifth episode of python live lessons my name is sebastie amato hi everyone i eduardo ole oye oleole and what i want to do today is pick up where we left off during the last we do episodes of the previous episodes in which we made a python module called a markdown code exec um yeah happy to be here too happy to see that there are some some viewers um and what we're going to do today is actually take the python module that we made during the previous episodes and turn it into a command line application so something that you can run from the console or the terminal or the command line however you want to call it so let's actually really very briefly say what our project does mark down code exec and as always so the main reason for me to do this live rather than to actually just record it and put it online is to uh to to allow a few questions right so if you have questions interrupt me at any time and i will try to engage with with the questions so what does our project do markdown code exec so it essentially takes a markdown file as input and markdown is text and with a particular simple markup syntax that allows you to indicate for example that something is code so here between the three backticks we have a bit of python code that says print hello world and the attributes between the curly braces indicate that that is actually python code and that we want to capture the output now in the capturing of the output that's where our markdown code exec application comes in or a module right now it's just a module and what does that mean well it literally means that it just captures the output of the print statement print function call which is hello world in this case and actually inserts it into the markdown after the code that was executed that's what it does um so so um what have we done so far so we in the first episode we created the sketch so sort of a basic outline of what the applic program is supposed to do approximately then we turned that sketch into a nice python module or python package that you can import as you are used to doing with other python modules then we actually uploaded our project to get in github just to keep track of the versions and everything and today we're going to turn our program into a command line program so what does that mean it means you don't no longer have to start python and then import it but rather that you can actually execute it as as you can execute a normal command line program um and how do we actually want to execute our program well let's call the program markdown code exec um and then i want to be able to call it in two different ways i want to be able to sort of use the hyphen i or hyphen hyphen input argument and then specify an input file and a hyphen o and then the output file right and that would mean read from in dot md and write the process output dot output to output md and i want to have a slightly fancier for the sort of the code phonetics fancier way of being able to actually run this application i want markdown code exec to be able to read directly from the standard input and to write to the standard output if that doesn't mean much to you basically the idea is that in linux and also mac os you have a sort of concept of sort of a standard input that is sort of fed into your program and a standard output which is what the program prints out and then there are tools in which you with which you can connect these things this sounds a little bit abstract but the example that you see here that get in dot md means print out the what the contents of in dot md then sort of the vertical line means channel that into what comes next what comes next is markdown code exec so our program that will print it out to the standard output and then this thing indicates that we want to write that output from the standard output to the file called out.md in other words in a slightly less user-friendly way it does the exact same thing as the thing before but the reason i want to be able to allow also this more complex way of using the command line app is that then you can use this the the app in in sort of uh in a chain of other tools that you might use right but most people would of course do the thing above okay um so let's actually switch to uh rapunzel the code editor and let's get to work so what we have here is on the left hand side we have the application as we've been working on so far we have our module called markdown code exec and you know what let's actually take a look at how we can use it so here we have a file called demo md i will change the working directory oh and also go back to yup there we go go back to this mode and then in order to actually read from demo.md we created in our module markdown code exec a function called parse file here and i can use it in following way you can watch back to previous episodes if you want if you're unclear on how that works but basically i can say from markdown code exec i'm typing this directly in the terminal import parse file and then parse file and then input file demo.md and let's say demo out dot md and then it will actually process the contents from demo.md and write it to demo.md here we are and what you see here here we have this thing that should be captured and indeed the output is captured and inserted below um so this is the the way you can use it as a module how are we now actually going to turn this into a into a an application and there are a few ways to do it i will show you my preferred way and the first thing that you need to do is so create a so-called entry point and the entry point is just a function that is called and that basically is the command line app and i'm going to put that in a separate module that i call underscoreapp.buy the underscore indicates that it's not intended to be used from the outside that's what the underscore means and then in this i'm going to actually define a function and i'm also going to call it app right now i'm going to leave the function empty so i just say app um how can we then so this is just adding a function to the module so it's not yet a command line app if we want to turn this into a command line app i'm going to create a file a top level file and i will call it markdown code exec dot by up there it is and i will very simply in that file mark down code exec i will say from markdown code exec up dot underscore app import app and then i will do something that is a little bit special i will say if name equals main up call the app that's all sounds a bit mysterious but let me explain what this means so basically this is simple right this is just an import statement uh that imports this function from the from the add module then what we're doing here is we're checking whether the magic variable main name sorry has the content is has the value underscore underscore main underscore underscore and why well because python is hard coded is built such that this is only true for a for a script that you call directly so here in the here in this this this module there will also be an underscore name variable but it will have a different value and only if you call a script from directly from as a top level script will this condition be true i hope that makes some kind of sense if not please don't hesitate to ask questions and then we can execute it actually so um let me actually open a terminal here up open tilex yeah should have prepared that better there we are so now i have a terminal here and i will if i now say python and i say markdown code exec.buy i execute that file that works but it does nothing of course because we still have to actually do everything right so basically it doesn't crash but it also doesn't do anything so let's switch back so what we need to do in the in our in our app is basically take control do a few things yeah yeah that's what okay happy to clarify that's the clarified the underscore underscore name thing for you yeah um we need to do a few things basically we want to from the from this module what we want to do we're actually not going to use the parse file function but we're going to use the simpler function called parse text and that takes text so not a file name but just text that's already been written and it returns new text that has been processed so it takes the original markdown as input and and and then x returns the process markdown as output um so that's what we want to do now let's say that we already know sort of what the input file is so we say in markdown in for example is demo built md and markdown out is demo out dot md of course we don't know we this is just for explanatory purposes because later we don't know this right exactly how this works uh how what these files are called because they are specified on the command line but let's say that we actually do uh we do know what they are then what we can do is say okay we're going to read let's call this actually path in and pass out then we can say okay with open path in sfd md in is fd.read so we read all the contents from the from the from the input path then we actually need to call the parse text function so we say from markdown code exec import parse text um and i say md out is pars text md in and then we have done the heavy lifting already and then we simply need to say with open path out sfd and we need to specify actually that this file is for writing up fd build right md out so this would actually work to the extent that oh i should have two empty lines here for style this would work to the extent that it would actually read from read from demo.md and it would write to demo.out.md but of course we don't always want to do that we want to be able to specify that on the command line so how are we going to do that for that we actually need to use the so-called import so-called arc parse module from python this is part of the python standard library and it is and it allows you to basically read get the command line arguments that were passed to your program in a standardized way um and nippodam is saying just as a reminder i'm still interested in how django routers work the rest framework well thank you um perhaps perhaps i should switch to django and beef up the number of live viewers um so it is noted i'm also just i i'm also not personally so familiar with django so i'm it's not just out of uh and i need to know of course how something works in order to be to explain it and then atishe asks what's the significance is does that refer to the comment about django or does it refer to something that i did please clarify if you want so um what we're going to do is use the arcbars module i'm picking up here to actually read the read the command line arguments that were passed to our script and it works like this i will type it and then you will sort of understand how it works because it is relatively intuitive let's actually close this because we don't need it anymore so up there we go so we create a parser object um and then um so at the show you say see my comment i don't know what comment that refers to actually if you specify that a bit more detail then i will try to answer and then to the to the parser object we add some arguments um and it goes like this so what we're saying is that our uh our command line app should be able to accept uh an input file either specified by hyphen i as i showed in the example or by the more elaborate way of saying hyphen hyphen input it should be a string and this is the help thing i will show you in a bit what it means why why why this is useful if you don't spec um and the magic is such that it will automatically go to a variable that is called parser.input you will see that in a bit oh i want to do something very similar of course for the output output output markdown file that's it there are only two arguments and then i say arcs is parser dot parse arcs and this this these lines will do basically the magic of parsing the arguments that are passed to the command line you can do many more things as well here i'm having a very sort of standard criterion but you can have all kinds of checks and different ways to specify arguments the arc bars module is very versatile but in this case in this case we're just basically saying you can specify input or you can specify output and then we have the path in which will be rx dot input and path out which will be arcs.output um this is actually really enough already for our the basic way of calling the function with these arguments so let's actually go here to the terminal and then if i say python markdown code exec dot pi right now i'm still doing it in kind of an ugly way by by first calling the python interpreter and then the name of the script with dot py once we actually create a python package that you can install with with pip we will do that in future episodes this is actually no longer necessary and we can just call it as markdown code exec without anything which is nicer but the the general idea would be the same if i execute this oh we get a oh wait yeah did i yeah okay sorry if i execute this and i say help that's what i wanted to do you you see now the help right and that's why it makes sense to actually specify the help in the in the specify the help when creating the arc parser and that's that will be used here and you see also that you get some explanation of how you can actually use use the the the command line app now if we want to actually run it we say by park code exec.by input demo.md output demo out.md and it will do basically the same as we did before right actually demo.out demo out.md already existed but if let's see actually for just for the sake of argument say demo out 2 dot md if i switch back you see that now we have demo out 2.md that was created this however doesn't allow us yet to actually also read from the standard i input and write to the standard output because you see here that we're assuming that path in is actually a file name and it doesn't necessarily need to be a file name so what happens if we don't actually specify an input or an output well then these variables variables will actually become non and we can make use of that so we can say if path in is non then here we're going to do something that is go that we're going to read from the standard output input sorry else we're going to read from the file all right so here we need to we didn't specify an input so we need to write read from the standard input how do you do that well up there are a few ways to do it but basically i see your comment morpheus and we'll get back to it in a second we will say uh md in is first an empty string and then for line in sys dot std in md in plus equals line so basically systoled std in is like the content of a file and you read it line by line we start with an empty string and we just concatenate the lines that we read to the standard input until the standard input is exhausted and that will go automatically we don't need to check and then we've basically read everything from the standard input something something similar we can do with um wait actually let me answer morpheus would you say that arc parse has advantages over similar libraries except for being in the standard library i used dokopt many many years ago there are probably better ones today i actually the only two libraries that i know for argument parsing are opt bars and arc bars where arc parse is basically the improved version of opt bars both of which are in the standard library i think i don't know dog bars so i cannot really doc opt so i cannot really comment as to whether it is better or worse i can't imagine that there are many things that you would want to do that arc parse doesn't do actually so in that sense it's very uh very convenient but maybe doc opt has some advantages that i don't know all right so and in the same way right here we're assuming that we're going to write to the standard to to to a file that was specified but if we didn't specify an output file then md out or sorry path out will be num so we say if path out is null then we need to do something to write to the standard output and else we write to the file that was specified right here now how do we write to the standard output that is very simple actually really we just say print md out right so what kind of logic do we have here maybe i should comment the code a little bit it's always good to comment the code parse command line arguments that's maybe not actually should i comment that i always feel when i'm commenting code you want to add comments but only things that are not already obvious from the code itself right because if you add obvious things it just takes space if no input file was specified dot read from the standard input input else read from the input file okay do the actual parsing if no output file was specified dot right to the standard output output else right to the output file okay so now we have a little bit of useful comments so let's see whether this actually really works right so um how can we check that well so remember that cat demo dot md will actually print the output print the contents of demo.md here to the output just to the terminal if we say let me clear if we say getdemo.md and we pipeline it as it is called with this vertical line that's typical unix linux mac os stuff basically this will not work on the windows unless of course you install the linux subset for windows or whatever it's called and we pipeline it into our program dot pi then it will actually print out almost the same thing but you see that now it has actually done the parsing right captured the output all right if we now do again almost the same thing but rewrite it to demo out three dot md we have an alternative way of parsing these uh parsing the code of basically parsing a file and writing it to a new file if i switch back to to rapunzel you see here we have demo out three dot md so we have demo out dot md which we created by using a markdown code exec as a module demo out2.md which we did by by sort of specifying an input and an output file and demo out 3.md which we created by using this kind of linux pipelining thing and it works very well i think so um now we have so if you have questions if it's our questions in the chat about uh about actually how to to to do this aspect of creating a command line app i hope it's kind of clear i feel also this is bad this is already the first few episodes were kind of rough in terms of difficulty but here we're actually really doing something that i think is quite doable right um while waiting for that let's actually now because we're doing the entire um the entire code workflow python coding workflow and part of that is of course after you've made some kind of notable improvement then we're going to commit this to git so i'm going to use my favorite tool git gui but there are many other tools and we talked about that in the previous episode so i start get gui up just to remind you here are the unstaged changes which are the things that git doesn't know about but that you might want to do something with well the demo out things we don't want to do anything with it but here's the script the sort of the top level script that we created with the name is main that's what we want to get and here is our module the app module so we also want to get that we click on it and by clicking on the changes we move them from the unstaged changes to the stage changes which remember are the changes that we are going to commit that we're going to give a name and actually log as such so turn module into command line app so this is the name of the commit that identifies what i say up commit push i push it to github there we go it's gone um and actually maybe so if i go to github now say markdown code exec you will see that here we have our commit turn into command line app right so that's the thing that we just did it would also make sense i think now to actually tag this let's say that this is release 0.1.0 we're going to polish it later but this is already a release worthy thing that we did how can you do that in git how can you tag a release well you can say i'm going to do this now not in the gui but on the command line but it's the same thing i typed this slash just so that the cursor goes to the next line that's a bit easier for you to see i feel that way i say git tag release 0.1. oh up there it is git push origin release 0.1.0 up it pushes it what is does it mean to push a tag well it basically means if we switch to back to github i reload the page it means that here under releases you see there is one tag if i click on it tags you see that this is release 0.1.0 and this sort of gives us a point that is anchored to the current state of the code right and that's what a release is right it's sort of a snapshot of what the code is like right now nippodom asks my employer requires me to make command stuff with powershell are there so much different differences versus python except that power um yes i think well i'm not i'm not a power user of powershell so maybe i'm underestimating everything that powershell can do but my understanding is that powershell is kind of like a batch script like language right for very simple for a very simple operations whereas python is a full programming language that allows you basically to do everything and as morpheus is basically seconding that by saying that there are a massive number of libraries for python so but uh i'm saying that with some uh caution because maybe actually i'm underestimating what powershell can do but i think for real sort of first i would say for scripting type of things which are basically a few few commands that you want to execute in a row things like powershell or bash are fine for things that correspond to actual programming you don't want to use those kinds of things you want to use something like python i think not necessarily only python of course but something like python now with that what have we done today we've actually accomplished quite a bit i think again in 30 minutes we've taken our module turned it into a command line app the most important things to learn from this are basically that to create a command line app generally speaking you create you create a function that serves as an entry point sort of the thing that is called when you run it from the command line later when we're going to create a package you also see that this entry point will also be used in the packaging process in this entry point you parse the command line arguments generally speaking with the arc bars library but we've heard there's also dog opt and maybe a few others to do that and we've created the top level script that doesn't very little else except importing the app function checking whether we're executing this from the top level where rather we're executing this as a top level script by checking the name variable and then calling it and that's it that's everything that we did now if you're watching this back later this is where the episode episode ends so thank you very much for watching python live lessons if you are watching live then i would i'm happy to take a few more questions if there are any [Music] you