#Python Command Line Calculator


Continuing from yesterday's post on the #python cmd command line library, I have written a more complete example.  The command line calculator is a simple program for performing simple calculations in the command line using only python standard libraries.

  • Calculations are entered into the accumulator in the form <operator> <operand>.  For example, to add 3.4 to the accumulator, type "add 3.4".  
  • Supports addition, subtraction, multiplication, division, floor division, modulo, exponential power and reciprocal operations.
  • You can store any value as a variable and use the variables in calculations.  
  • Chain multiple calculations at once.


import cmd
import datetime
import textwrap

class Calc(cmd.Cmd):
    """A Command line calculator"""
    def __init__(self):
        """Constructor"""
        cmd.Cmd.__init__(self)
        cmd.Cmd.prompt = ""
        self.__acc = 0 #the accumulator
        self.__version = "1.0.1.3"
        self.__vars = {}

    def initialise(self):
        self.__makePrompt()

    def __getVersion(self):
        return self.__version

    
    def __showKeyError(self, args):
        return ("There is a problem with that variable\n'"+args+"' is not stored.")


    def __showSyntaxError(self, args):
        return ("I'm sorry old boy, there is no such command or variable '"+args+"'!")


    def __showVariableError(self, args):
        return ("Bad variable name '"+args+"'!")
    

    def __makePrompt(self):
        cmd.Cmd.prompt = "--->"+str(self.getAcc())+"\nEnter command or 'help' : "

        
    def __setAcc(self, avalue):
        """Sets the accumulator to a value"""
        self.__acc = avalue


    def getAcc(self):
        """get method for the accumulator"""
        return (self.__acc)


    def __setVariable(self, key, value):
        """Add item to dictionary"""
        try:
            self.__vars[key] = str(value)
        except NameError:
            print(self.__showVariableError(key))


    def __getVariable(self, key):
        """Returns the value associated with the key"""
        return self.__vars[key]

    def __showAllVars(self):
        for key in self.__vars:
            print ("  "+key+" = "+self.__vars[key], end=", ")
        print ("\n")
        
    def do_version(self, args):
        """Displays the calculator version number"""
        print("Version: ", self.__getVersion(), end="\n")


    def do_clear(self, args):
        """Clears all variables and sets the accumulator to zero"""
        self.__vars.clear()
        self.__setAcc(0)

    def __evaluate(self, args, b, op ):
        try:
            #Try to add the value onto the accumulator
            a = float(args)
            self.__setAcc( eval(str(b) + op +str( a ) ) )
        except ValueError:
            try:
                #Now look for a key in the dictionary
                a = float( self.__getVariable(args) )
                self.__setAcc( eval(str(b))+ op + str( a ) )
            except KeyError:
                print( self.__showKeyError(args) )
            
        
    def do_add(self, args):
        """Adds the argument to the accumulator. Example, add 5.3"""
        self.__evaluate( args, self.getAcc(), "+" )


    def do_sub(self, args):
        """Subtracts the argument from the accumulator. Example, sub 5.3"""
        self.__evaluate( args, self.getAcc(), "-" )     


    def do_divide(self, args):
        """Divides the accumulator by the argument. Example, divide 5.3"""
        self.__evaluate( args, self.getAcc(), "/" )    


    def do_multiply(self, args):
        """Multiplies the accumulator by the argument. Example, multiply 5.3"""
        self.__evaluate( args, self.getAcc(), "*" )      


    def do_div(self, args):
        """Performs floor division between the accumulator and the argument.  Example, div 3"""
        self.__evaluate( args, self.getAcc(), "//" )      


    def do_mod(self, args):
        """Performs modulo operation between the accumulator and the argument.  Example, mod 3"""
        self.__evaluate( args, self.getAcc(), "%" )      


    def do_raise(self, args):
        """Raises the value in the accumulator to the power.  Example raise 2"""
        self.__evaluate( args, self.getAcc(), "**" )


    def do_recip(self, args):
        """Find the reciprocal of the vale in the accumulator"""
        self.__setAcc( 1/self.getAcc() )

      
    def do_store(self, args):
        """Store the value in the accumulator into a named variable.  Exmaple, store x"""
        self.__setVariable(args, str(self.getAcc()) )


    def do_load(self, args):
        """Load a value into the accumulator"""
        try:
            #Try to find a value and put it in the accumulator
            a = float(args)
            self.__setAcc( a )
        except ValueError:
            try:
                #Now look for a key in the dictionary
                a = float( self.__getVariable(args) )
                self.__setAcc(  a )
            except KeyError:
                print( self.__showKeyError(args) )


    def do_time(self, args):
        """Displays the current time."""
        print( datetime.datetime.strftime((datetime.datetime.now()), '%H:%M:%S') )

      
    def do_date(self, args):
        """Displays the current date."""
        print( datetime.datetime.strftime((datetime.datetime.now()), '%Y-%m-%d') )
   

    def help_me(self):
        msg = "Enter command line calculations (e.g.  add 3.2).  Perform multiple calculations with the 'chain' command (eg chain 4; add 4; div 2).  Assign to a variable with 'store <varname> (e.g. store x).  Clear the accumulator and all variables with 'clear'."
        for x in textwrap.wrap(msg, 50):
            print(x)


    def help_about(self):
        msg = "Command Line Calculator "+self.__getVersion()+" superdecade games. http://www.superdecadegames.com or http://www.superdecade.blogspot.com"
        for x in textwrap.wrap(msg, 50):
            print(x)


    def do_chain(self, args):
        """Execute a series of commands separated y semi colons.  Example: 8; add 3; sub 5"""
        for x in args.split(";"):
            self.onecmd(x)
        
           
    def emptyline(self):
        """deals __makePromptwith empty input line"""
        #print("\nThe accumulator is...", self.getAcc())


    def default(self, args):
        """Overides the default error message"""
        try:
            #user types a number so set accumulator to that number
            a = float(args)
            self.__setAcc( a )
        except ValueError:
            try:
                #user has types a variable so set accumulator to that number
                a = float( self.__getVariable(args) )
                self.__setAcc( a )
            except KeyError:
                print( self.__showSyntaxError(args) )

        
        
    def do_show(self, args):
        """See the value of a variable.  Example show x"""
        if args == "":
            self.__showAllVars()
        else:
            try:
                #user has types a variable so set accumulator to that number
                a = float( self.__getVariable(args) )
                print("  "+args+" = "+str(a))
            except KeyError:
                print( self.__showSyntaxError(args) )

        
    def postcmd(self, stop, line):
        """Script that runs when the current command has completed"""
        self.__makePrompt() # remake prompt so it includes the accumulator value
        
if __name__ == "__main__":
    mycalc = Calc()
    mycalc.initialise()
    mycalc.cmdloop("Command Line Calculator\n")