0

I have a code that reads an inventory txt file that is suppose to display a menu for the user when it is run. However, when it runs the quantity and pice columns are misaligned:

Select an item ID to purchase or return: 

ID  Item          Quantity   Price
244 Large Cake Pan     7.00  19.99
576 Assorted Sprinkles     3.00  12.89
212 Deluxe Icing Set       6.00  37.97
827 Yellow Cake Mix    3.00   1.99
194 Cupcake Display Board      2.00  27.99
285 Bakery Boxes       7.00   8.59
736 Mixer      5.00 136.94

Enter another item ID or 0 to stop

Here is my code:

import InventoryFile
def readFile ():
    #open the file and read the lines
    inventoryFile = open ('Inventory.txt', 'r')
    raw_data = inventoryFile.readlines ()

    #remove the new line characters
    clean_data = []
    for item in raw_data:
        clean_item = item.rstrip ('\n')
        clean_data.append (clean_item)

    #read lists into objects
    all_objects = []
    for i in range (0, len(clean_data), 4):
        ID = clean_data [i]
        item = clean_data [i+1]
        qty = float (clean_data [i+2])
        price = float (clean_data [i+3])

        inventory_object = InventoryFile.Inventory (ID, item, qty, price)

        all_objects.append (inventory_object)

    return all_objects

def printMenu (all_data):
    print ()
    print ('Select an item ID to purchase or return: ')
    print ()
    print ('ID\tItem\t\t  Quantity\t Price')

    for item in all_data:
        print (item)

    print ()

    print ('Enter another item ID or 0 to stop')

def main ():
    all_items = readFile ()
    printMenu (all_items)

main ()

How can I format the output so that the quantity and price columns are correctly aligned?

Here is the inventory class:

class Inventory:
    def __init__ (self, new_id, new_name, new_stock, new_price):
        self.__id = new_id
        self.__name = new_name
        self.__stock = new_stock
        self.__price = new_price

    def get_id (self):
        return self.__id
    def get_name (self):
        return self.__name
    def get_stock (self):
        return self.__stock
    def get_price (self):
        return self.__price

    def restock (self, new_stock):
        if new_stock < 0:
            print ('ERROR')
            return False
        else:
            self.__stock = self.__stock + new_stock
            return True

    def purchase (self, purch_qty):
        if (new_stock - purch_qty < 0):
            print ('ERROR')
            return False
        else:
            self.__stock = self.__stock + purch_qty
            return True

    def __str__ (self):
        return self.__id + '\t' + self.__name + '\t' + \
        format (self.__stock, '7.2f') + format (self.__price, '7.2f')
  • 2
    Read up about `str.format()`, e.g. `print('{:5}{:20}{:10}{:10}'.format('ID', 'Item', 'Quantity', 'Price'))` – AChampion May 08 '17 at 02:31
  • Possible duplicate of [Printing Lists as Tabular Data](http://stackoverflow.com/questions/9535954/printing-lists-as-tabular-data) – AChampion May 08 '17 at 02:33
  • As an aside, in Python you don't generally write getters and setters, and don't use double-underscore name-mangling, ie. `self.__stock` unless you actually want/need that behavior. Just use `self.stock` or `self._stock` if you want to follow the convention for "private" variables. – juanpa.arrivillaga May 08 '17 at 03:42

1 Answers1

0

Using your class Inventory's getters you can make a list and just join the output.

def printMenu (all_data):
    print ()
    print ('Select an item ID to purchase or return: ')
    print ()
    print ('ID\tItem\t\t  Quantity\t Price')

    for item in all_data:
        product_id = item.get_id()
        product_name = item.get_name()
        product_stock = item.get_stock()
        product_price = item.get_price()
        output = [product_id, product_name, product_stock, product_price]
        output = [str(item) for item in output]
        print('{:<5}\t{:<5}\t{:<5}\t{:<5}'.format(output))

    print ()

    print ('Enter another item ID or 0 to stop')
Mike Tung
  • 4,735
  • 1
  • 17
  • 24
  • I tried this, but I get 'TypeError: join() argument after * must be an iterable, not Inventory' – Jeremy Mosier May 08 '17 at 02:39
  • What is `Inventory`? From your answer I assumed you were using tuples – Mike Tung May 08 '17 at 02:40
  • Sorry I didn't specify, Inventory is a class. – Jeremy Mosier May 08 '17 at 02:42
  • This new solution should work, if it does mind picking my answer and callin it a night? – Mike Tung May 08 '17 at 03:05
  • I appreciate the time you're putting in, but I'm getting another error: TypeError: sequence item 2: expected str instance, float found – Jeremy Mosier May 08 '17 at 03:10
  • Added a snippet to fix it try now. – Mike Tung May 08 '17 at 03:10
  • No error, but the price and quantity columns are still not aligned correctly – Jeremy Mosier May 08 '17 at 03:12
  • How are you viewing it? Also they are all aligned by tab characters so depending on what you use it would affect it. For example try opening the output in Excel (set the delimiter to tabs). – Mike Tung May 08 '17 at 03:14
  • I'm viewing it in the Python Shell. For the purposes of my assignment it must be aligned in the Shell – Jeremy Mosier May 08 '17 at 03:15
  • You do realize that depending on the font size and family and the window size the way it looks will be different right? Also if you are aligning to the shell you'd have to add white space on a case by case basis which isn't even possible if your data is extremely large... Why can't you just say open it in excel? – Mike Tung May 08 '17 at 03:17
  • I do realize that but I also know that there is a method to be able to left align the output data to the titles of the table. – Jeremy Mosier May 08 '17 at 03:19
  • Tabs are only so wide. That's the issue here: data longer than the tab width. – Arya McCarthy May 08 '17 at 03:26
  • I've added some formatting changes to let you space the stuff as needed... Using this you should be able to do what you need to. – Mike Tung May 08 '17 at 03:26