python2 Min Read

Implement a command line shell by using Command Dispatcher in Python

Gorav Singal

August 02, 2019

TL;DR

Build a scalable command shell in Python using a decorator-based command dispatcher pattern where new commands can be added without modifying the event loop.

Implement a command line shell by using Command Dispatcher in Python

Lets implement a command shell by using a command dispatcher. The objective is to have an event loop which is to dispatch input commands, and implement some handlers who are going to handle those commands. And, we dont want to change in event loop whenever some new command comes in future. So, our design should be scalble enough to support adding new commands without affecting the event loop.

Decorator in Python

I hope you have seen Timeit implementation using Decorator

Event loop (Command Dispatcher)


class CommandDispatch:
    def __init__(self):
        # list of commands
        self.commands = {}

    """
    For registering commands
    """
    def for_command(self, cmd):
        def wrap(fn):
            self.commands[cmd] = fn
        return wrap

    """
    For registering invalid command handler
    """
    def invalid(self, fn):
        self.invalidfn = fn

    """
    For registering input method
    """
    def input(self, fn):
        self.inputfn = fn

    """
    Main event loop
    """
    def run(self):
        while True:
            args = self.inputfn()
            self.commands.get(args[0], self.invalidfn)(*args)

Above class implements Decorator pattern, and provides an event loop. And, some methods to register method handlers.

Command Handlers

"""
     A command_dispatch module with class CommandDispatch
     such that the following example program that implements a
     rudimentary command-line shell works.
"""

from command_dispatch import CommandDispatch

shell = CommandDispatch()

@shell.for_command("list")
def list_directory(*args):
    from os import listdir
    if len(args) < 2:
        args += ".",
    for path in args[1:]:
        print("{}:".format(path))
        print("\n".join(listdir(path)))

@shell.for_command("whoami")
def show_user(*args):
    from getpass import getuser
    print(getuser())

@shell.for_command("date")
def print_date(*args):
    from time import ctime
    print(ctime())

@shell.for_command("pwd")
def show_curr_dir(*args):
    import os
    print(os.getcwd())

@shell.for_command("exit")
def exit_shell(*args):
    exit(0)

@shell.for_command("hostname")
def show_hostname(*args):
    from os import uname
    print(uname().nodename)

@shell.invalid
def invalid_command(*args):
    print("Invalid command - ", args[0])


@shell.input
def get_input():
    # import rlcompleter
    return input("PyShell> ").split()

if __name__ == '__main__':
    shell.run()

Here, we are instantiating our event loop. And, using that instance, registering different command handlers. For example:

@shell.for_command("exit")
def exit_shell(*args):
    exit(0)

We are registering a command handler for command: exit. It gets registered in our CommandDispatcher’s list: commands. After executing this file. The dictionary in CommandDispatcher looks like:

{
    'list': <function list_directory>, 
    'whoami': <function show_user>, 
    'date': <function print_date>, 
    'pwd': <function show_curr_dir>, 
    'exit': <function exit_shell>, 
    'hostname': <function show_hostname>}

So, when we ran our program. At first, it runs run method of CommandDispatcher’s class. And, in the infinite loop, it calls input function. And, whatever argument it returns. We are checking in the dictionary: commands. If it is found, we are calling that method by passing args, else calling invalidfn.

def run(self):
    while True:
        args = self.inputfn()
        self.commands.get(args[0], self.invalidfn)(*args)

Github

The code can be found at GyanByte Github repository

Let me know in comment section, if there is any confusion. Hope it helps.

Share

Related Posts

Python SMTP Email Code - How to Send HTML Email from Python Code with Authentication at SMTP Server

Python SMTP Email Code - How to Send HTML Email from Python Code with Authentication at SMTP Server

Introduction This post has the complete code to send email through smtp server…

Python - How to Maintain Quality Build Process Using Pylint and Unittest Coverage With Minimum Threshold Values

Python - How to Maintain Quality Build Process Using Pylint and Unittest Coverage With Minimum Threshold Values

Introduction It is very important to introduce few process so that your code and…

Python - How to Implement Timed-Function which gets Timeout After Specified Max Timeout Value

Python - How to Implement Timed-Function which gets Timeout After Specified Max Timeout Value

Introduction We often require to execute in timed manner, i.e. to specify a max…

How to Solve Circular Import Error in Python

How to Solve Circular Import Error in Python

Introduction To give some context, I have two python files. (Both in same folder…

Python Code - How To Read CSV with Headers into an Array of Dictionary

Python Code - How To Read CSV with Headers into an Array of Dictionary

Introduction Lets assume we have a csv something similar to following: Python…

Python Code - How To Read CSV into an Array of Arrays

Python Code - How To Read CSV into an Array of Arrays

Introduction In last post, we saw How to read CSV with Headers into Dictionary…

Latest Posts

AI Video Generation in 2025 — Models, Costs, and How to Build a Cost-Effective Pipeline

AI Video Generation in 2025 — Models, Costs, and How to Build a Cost-Effective Pipeline

AI video generation went from “cool demo” to “usable in production” in 2024-202…

AI Models in 2025 — Cost, Capabilities, and Which One to Use

AI Models in 2025 — Cost, Capabilities, and Which One to Use

Choosing the right AI model is one of the most impactful decisions you’ll make…

AI Image Generation in 2025 — Models, Costs, and How to Optimize Spend

AI Image Generation in 2025 — Models, Costs, and How to Optimize Spend

Generating one image with AI costs between $0.002 and $0.12. That might sound…

AI Coding Assistants in 2025 — Every Tool Compared, and Which One to Actually Use

AI Coding Assistants in 2025 — Every Tool Compared, and Which One to Actually Use

Two years ago, AI coding meant one thing: GitHub Copilot autocompleting your…

AI Agents Demystified — It's Just Automation With a Better Brain

AI Agents Demystified — It's Just Automation With a Better Brain

Let’s cut through the noise. If you read Twitter or LinkedIn, you’d think “AI…

Supply Chain Security — Protecting Your Software Pipeline

Supply Chain Security — Protecting Your Software Pipeline

In 2024, a single malicious contributor nearly compromised every Linux system on…