Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Adding Items to the Database

00:00 In the last lesson, you set up the foundation for the functionalities to read and write to-do items to your database. And in this lesson, you’ll go ahead to code up the functionality to add to-do items to the database.

00:12 And to do that, you are going to be creating an add CLI command. You’ve already created the init command. Next is to create the add command and you’ll be using this to-do utility class to carry out the add operation.

00:26 First is to create a way to access this Todoer class from your CLI application. Head to your cli.py module and just below the init CLI app command, you create another helper function.

00:40 Create a function called def get_todoer

00:44 in your cli.py module. Remember to import the rptodo module,

00:50 and then back to the function. This function after operation would return an instance of rptodo .Todoer. This is a Todoer class you just created in the rptodo module.

01:04 Now to do this, you need to be able to accept certain information required to instantiate this Todoer class, which is the DB path. And if you recall, to get the DB path, you’d need to read the system’s configuration file.

01:18 And to do that, you’d use the config module to get the config file path. If referring to the config module and the variable config_file_path, this being a path object, pathlib will tell you if this file exists, giving you a true or false value.

01:38 And if the config file exists, what you want is the path to the DB read from that config file. And to do that, you’d use another helper function created from the database module you call the get_ database_path function.

01:51 This is the helper function, get_database_path. And what this requires is an instance of a config file, which is of the type path. So knowing that your config file path is a type of pathlib.Path, you can pass it to this function after confirming that it exists.

02:09 But if this config file doesn’t exist, it means that the users of the application probably have, haven’t initialized the application. And to do that, you let them know. The else block, se typer.secho`, let the users know that the configuration file does not exist and they most likely need to run the rp_init command to initialize this config file.

02:30 And seen as this is an error message, you can use secho for formatting to return this in a red text. And at this point, you’d like to exit from the operation. And to do that, you raise typer.Exit with an exit code of one.

02:45 But if things all go according to plan and you get the config file and you’ve read the DB path from that config file, you can run a second check because you know the DB is a JSON file, you can also check that that file exists for that using the same method.

03:01 You can say if db_path.exists() also as a Path object, you can check if this file exists and if that file exists from rptodo module, you return an instance of the to-do class instantiated with the DB path.

03:17 But if that file doesn’t exist, that is the rptodo database, also using typer.secho, you can let the user know that the database doesn’t exist.

03:27 Print a similar message saying `Database not found, please run rptodo init` to prompt the user to initialize the application again and create the database.

03:39 Also, as this is an error, you can use Typer secho style text and make it a color of red. Again, if this happens, this will be a good point to exit the operation.

03:51 And to do that, you raise typer.Exit with an exit code of one.

03:57 Great. You’ve just created a get to-do helper function to return an instance of the to-do utility class. And this class will help you communicate back and forth with the database and the CLI application.

04:10 Now that you have a means of getting this Todoer class, you can head over to that Todoer class to build it up a little bit more.

04:16 And for that, you head back to the rptodo module, and here you create the add functionality. You’ll define a method in your Todoer class called add and this method would require a few things.

04:29 First, you reference the class and then this add method would require a description. This will be received as a list of strings, then a priority value. This will be received as an integer value and you set a default as two.

04:46 Remember the to-do item will have a description of text value and then priority that is an integer value between the numbers one and three. But this priority will be a Typer option not always required by the user.

05:00 So you can set a default value of two. This method would return an instance of current to-do.

05:09 Now for the main method definitions, you can add a docstring that says this will add a new to-do to the database.

05:17 Here you’ll create the add functionality. A common convention when receiving an array of words from CLI applications is to collect them as a list but to get the description text, which is how we collect the description value of the to-do item, knowing that this is going to be a list, you create a single text out this using str.join() method, passing it the list of strings provided by the user and you can clean this description, text a little bit more confirming if it’s ended properly with a full stop. As a string, you have a method called .endswith() to check if a string ends with a certain character.

05:58 And in this case, you check if it ends with a full stop and if it doesn’t, you can append the full stop to the string or text.

06:08 Next, you construct a to-do object from the values received. And for this, you’d use a dictionary: key description, value formatted description, text, next priority and value of that the passed priority CLI option.

06:24 Next, done status by default always set to false.

06:29 Now having your database as a JSON file, the strategy to add a new to-do item will be first, read all the items in the file, append a new to-do item, and write the new updated list back to the file.

06:44 So to do that, first you read all the items already existent in the file if there are any. And for that, you call the DB handler. And this DB handler you already know has a read_todos method and you call that method here.

06:58 And this should read all the to-do items in the file if any exists. And assign that to this variable called read. Again, the items to be returned will be an instance of DB response which will contain a list of to-do if any exists and an error for the operation response code or error code.

07:18 Now you check if a read error occurred during the process of reading the to-dos from the file. And to do that first ensure you have that error for rptodo import DB_READ_ERROR

07:32 and then you check if that error occurred.

07:36 If it did, you’d simply return an instance of current to-do with the to-do you try to add and then the error received.

07:46 But if no error occurred, you append the new to-do to the list of to-dos already existing with the new to-do item.

07:55 Now after getting the updated to-do list, you’re gonna write that to the database also using the DB handler. This time call in the DB handlers write_todos method, and for this you pass the updated to-do list.

08:10 And if all things go as planned, you’d return an instance of current with did you do you try to write and the response code, whatever it might be.

08:20 With this add method now included in your utility class, it’s time to go and create the CLI add command. And for this remember to save all files and head of it to the cli.py module and just below the get to do a helper function, you create a new type of CLI command and you create a function def add.

08:42 This requires two arguments, description and priority,

08:48 and you annotate to specify that this returns None. And as you have seen before in the ini command, this is just a regular function until you have the add app command decorator.

09:00 So you can add the decorator on top of your add function using @app.command with a parenthesis, making this a type of CLI command. And without doing much, you could just put a pass you could head with your terminal to confirm that this add command is now registered in your command-line application.

09:21 While in your terminal you can run python3 -m rptodo --help. And you should see the add command now registered in your application.

09:33 This command has no description and to include that in your add function, you can add a docstring saying add a new to-do to the database. If you save this, and check the helper again,

09:50 you should now see the descriptive text. This is how you support Typer to build your CLI applications documentation.

09:59 Now you can proceed to implement the actual functionality for the add command. First you need to annotate these parameters to let Typer know what they are.

10:08 And just as you’ve seen before, starting with a description, using typing extensions annotated, you can add more metadata to this type. And this description will be of type list of strings.

10:22 And this list of strings are a type of type or arguments.

10:27 And then you can let Typer know that these are absolutely required using ellipsis. Then you can add a help text to further describe what this argument is.

10:38 There will be no default values because the user is required to pass this value and for the priority, the same method using typing extensions annotated. To get more metadata about this, first you specify that it’s going to be an integer value, then not just any integer value, it’s a type of Typer option.

10:59 But this being an option can have a default value and you can set that to two. Further in the Typer option you can specify the flags used to collect this option from the CLI first of which in quotes, double dash priority or alternatively single dash p.

11:22 Now with Typer you’d add more constraints to this option. So this doesn’t just accept any integer value. Rather, you’d have a minimum and a maximum value.

11:31 So you set that here saying the minimum value will be one and the maximum value would be three. So if users try to enter values that are outside of this range, Typer would raise an error. Alongside, you can add a help text describing what this option is.

11:47 And in help text you can say The to-do item priority value.

11:52 Next, you can move on to the actual implementation. The first thing you need is an instance of your todoer because the utility class that helps you interact with the database and you can assign that to a variable called to oer and call the function that gets you the todoer.

12:07 Next, after getting an instance of a Todoer class, you’ll call the add method to add the to-do item to the database. And you know the add method would return an instance of current to-do which will contain a to-do item and an error or response code.

12:23 And then you deconstruct that, get in the to-do value and the response code if all things go well or if there’s an error. And for that you call using the to-do instance, the add method, passing it the description value gotten from the user and the priority value.

12:41 Next you check if the operation was successful. But to do that you check if the error exists. If the error or response code is non-zero, it means that an error has occurred.

12:50 And if that happens you can let the user know with typer .secho and a message saying Adding to-do failed with.

13:00 Now you only have the error code but you need a human-readable error descriptive message and for that you’d refer back to the error dictionary when you pass it, the error received to get the human-readable descriptive message.

13:14 And as this is an error, you can style that to have a red text with secho,fg, and type of colors, red.

13:24 And if this happens, you can exit the operation at this point using `raise typer.Exit. Else, if all things go well, you can proceed to let the user know that the to-do item has been added to the database.

13:37 And for that also present into console using typer.secho, you can simply print the to-do item,

13:44 getting the description from the to-do dictionary

13:49 and letting them know that that was added,

13:53 and also what priority values was used.

13:58 And next, this is an expected operation. You can use green text.

14:04 Great, you’ve just completed the add CLI command and it should be ready for you to test. To do that, you can head to your terminal after saving the file. To add a new to-do item now that you have the add command, you’d run python 3 -m rptodo and using the add command with some description, say Get some milk with a priority value of say one.

14:32 This should add the to-do item to the database.

14:36 To confirm this, you can have a look at your rp_todo.json which is your database, and you should see that to-do item added with the description, priority and done value.

14:48 You’ve just completed the functionality to add to-do items to your database. In the next lesson, you focus on creating the feature to fetch and list to-do items.

Become a Member to join the conversation.