DEV Community

Cover image for My first CLI.
wormondeck
wormondeck

Posted on

My first CLI.

Opening Credits

The second it all clicks, consider the project fun. I built a client friendly CLI project to grasp how a class, methods, and properties work.

My directory structure was quite simple:

└── lib
├── models
│ ├── __init__.py
│ └── actor.py
| └── movie.py
├── cli.py
├── debug.py
└── helpers.py
├── Pipfile
├── Pipfile.lock
├── README.md

As you can see from the structure I built a one-to-many association where an actor has many movies. From this association my menu came into play.

  1. Current list of actors
  2. Add an Actor
  3. Delete an Actor
  4. Exit the program

My menu above was defined by a function called... menu() which was located in my cli.py file along with the main() which shows the user the CLI menu:

def main():
    while True:
        welcome()
        menu()
        choice = input("> ").strip()
        if choice == "1":
            actor_list()
        elif choice == "2":
            add_actor()
        elif choice == "3":
            delete_actor()
        elif choice == "4":
            exit_program()
            break
        else:
            print("Invalid choice. Try again.\n")
Enter fullscreen mode Exit fullscreen mode

This particular function was the first of many where a while loop along with if/elif/else statements were executed to give our user the ability to navigate our menus with ease.

The cli.py is then concluded with some important code block:

if __name__ == "__main__":
    main() 
Enter fullscreen mode Exit fullscreen mode

This code block tells our interpreter (Python) to only run our file if it is called from the command line.

Supporting Cast

There were also helper functions involved in this project which also used a while loop along with if/elif/else statements. One in particular stands out in showing ease of navigation when selecting for example our current list of actors:

def actor_list():

        actor_list = Actor.get_all()

        if actor_list:
            print("\n*** UPDATED LIST! ***")
            for i, actor in enumerate(actor_list, start=1):
                print(f"{i}. {actor.name}")  

            while True:
                choice = input("Press 'a' to add an actor\n"
                                "Press 'b' for actor profile\n"
                                "Press 'c' to return to the main menu.\n"
                                "Press 'd' delete an actor.\n").lower()
                if choice == 'a':
                    add_actor()
                    break
                elif choice == 'b':
                    actor_profile()
                    break
                elif choice == 'c':
                    return
                elif choice == 'd':
                    delete_actor()
                    break
                else:
                    print("Invalid choice. Please try again.") 
        else:
            print("List empty!")
            while True:
                choice = input("Press 'a' or to add an actor\n"
                        "Press 'b' for main menu.\n").lower()
                if choice == 'a':
                    add_actor()
                    break
                elif choice == 'b':
                    return
                else:
                    print("Invalid choice. Please try again.")
Enter fullscreen mode Exit fullscreen mode

Here not only did I became accustomed of the while loop and if statements but also reap the benefits of appearance and order by using enumerate() with a for loop to iterate with an index in python allowing all the lists thru out the project to be an ordered list.

Show Some Class

Our two main characters of course are the Classes Actor and Movie. Both consist of similar code in terms of class methods when creating, updating or deleting an instance of that particular class, but there are differences:

Let's take our Movie class for example:

class Movie:

    all_movies = {}

    def __init__(self, movie, genre, actor_id, id=None):
        self.id = id
        self.movie = movie
        self.genre = genre
        self.actor_id = actor_id
Enter fullscreen mode Exit fullscreen mode

Since we have our project setup where an actor has many movies, our movie class will have a unique actor_id parameter/attribute to establish a link between the movie instance and a specific actor, allowing easy reference to the actor's information.

Now look at this code block in our Actor class:

   def movies(self):
        from models.movie import Movie
        sql = """
            SELECT * FROM movie
            WHERE actor_id = ?
        """
        CURSOR.execute(sql, (self.id,),)

        rows = CURSOR.fetchall()
        return [
            Movie.instance_from_db(row) for row in rows
        ]
Enter fullscreen mode Exit fullscreen mode

Here we have our movies() method retrieve all the movies associated with the current Actor instance by querying the movie table using the actor's ID. This will then return a list of Movie objects, establishing a "has-many" relationship between Actor and Movie.

The code blocks discussed were the primary areas of the project where I focused on grasping more understanding. Overall this project served as a good exercise to enhance my skills in python.

Top comments (0)