I'm kinda new to python, it really reminds me of Qbasic =\ ANYway lol.
I'm looking to do something extra in a class I'm taking. We were to make a budget program. That wasn't the hard part, what im looking to do is be able to save each entry of the budget as a unique entry in a file (text, CSV, etc) but i really dont know how to go about it.

an example would be:
loop = 0
while loop == 0:
expenseName = raw_input('What was the name of the expense? ')
expenseValue = int(raw_input('What was the value of the expense?')
choice = raw_input('Would you like to add another expense?')
if choice.....

now what i want to be able to do is save each of these as a single entry and then have the ability to edit them later. with a delete function. so it would end up being either in this script itself or exported to the said file. either way would be fine.

Im sure this is a newbie question but i don't know where to start with it. Any help would be amazing.

Member Avatar for iamthwee

What's the problem here? Writing to a file or writing a unique value?

Here's how I write to a file:

import tempfile

# The path for storing any files with randomly generated (temp) names.
path = 'data'
tempfile.tempdir = path

# Generates a random filename not already in use.
filename = tempfile.mktemp()

# Writes the given text to the file.
def write(text=""):
    fileHandle = open(filename, 'a')
    fileHandle.write(text)
    fileHandle.close()

Note that the 'a' stands for 'append' -- this means adding on to the bottom of the file, and can be replaced with 'w' if you want to overwrite whatever is there. Also, 'r' stands for 'read' (only).

Of course, if you want, you can name the file whatever you like instead of generating a random name for it. I personally don't know anything about deleting within a file once you've written to it, although I know it's possible.

Also, if you're looking to store something that you will later want to use or change, consider pickling. When you pickle a python object (like a list), it makes a specially coded file so that any other python program can then unpickle it and treat it as a list again.

import pickle

# Pickles a python object (e.g. a dictionary).
def p(obj):
    fileHandle = open(filename, 'a')
    pickle.dump(obj, fileHandle)
    fileHandle.close()

sourceFolder = 'data'

# Gets data out of a pickled file.
def unpickle(filename):
    file = sourceFolder + '/' + filename
    
    fileHandle = open(file, 'r')
    data = pickle.load(fileHandle)
    fileHandle.close()
    
    return data

What's the problem here? Writing to a file or writing a unique value?

Well the problem is either/or. I would like to write a unique variable for each answer, that seems to be the easiest way to manipulate the variables later.

Aot, im not sure that is the best way to go, i've used pickling b4 but couldnt seem to keep the data in order.

Well, if you want the hard part...

Coming from a financial background I can assure you, that saving entries into a csv file permanently is a a bad idea. Unless the only purpose for this file is to import it to something more robust.

Deleting transactions looks like a bad idea, too. In bigger systems (more than one account, or more than one user) this is considered hacking and comes into play only, when something got really wrong. Consider storno...

If this is a basic budgeting program, then I personally would use:
1. Datastore layer
2. A data access layer
3. A business logic layer
4. A user interface layer

Datastore layer can be an any sql database, for the begin sqlite(included in python) will suffice. All other layer can be written in the begin by hand, and later you can try something more appropriate, like sqlalchemy for data access, or wxpython for UI.
The layering is very good, because you can separate concerns and can develop them (almost) separately.

But everything depends on, what you trying to accomplish.

So my imaginary budgeting program would have the functions:

  • Set initial balance
  • Input expenses/incomes
  • Report balance/transactions

I will not go into more detail, because my post will end up as a novel. But more questions are to be answered, like users, authorization, authentication, error checking, database design, fine tuning of requirements and so on. And with more answers come more questions:)

For learning purposes in the beginning every layer(except datastore) is only a class. In time these classes get bigger, and become modules...

I have written a very limited version of that. You can put in expenses, and get the balance. No error checking, no input validation, full of lazy shortcuts.

import sqlite3
class DataAccess():
    my_database="budget.db"
    def __init__(self):
        self.connection=sqlite3.connect(self.my_database)
    def create_database(self):
        self.connection.execute("create table account(id integer primary key, balance number);")
        self.connection.execute("create table transact(id integer primary key, narrativ text, amount number);")
        self.connection.execute("insert into account(balance) values(0);")
        self.connection.commit()
    def input_transaction(self, amount, narrativ):
        sqlstr="insert into transact (narrativ, amount) values(\"%s\",%s); " % (narrativ,amount)
        self.connection.execute(sqlstr)
        self.connection.execute("update account set balance=balance+%s; " % (amount))
        self.connection.commit()
    def get_balance(self):
        cu=self.connection.cursor()
        cu.execute("select * from account;")
        return cu.fetchall()

class BussinesLogic():
    def __init__(self):
        self.database=DataAccess()
    def report_balance(self):
        return self.database.get_balance()[0][1]
    def input_expense(self,expense, narrativ):
        self.database.input_transaction(-expense,narrativ)
    def create_database(self):
        self.database.create_database()


import sys
class UserInterface():
    def __init__(self, bl):
        self.bl=bl
        self.menu=dict()
        self.set_menu()
    def set_menu(self):
        self.menu[4]=("Report Balance",self.display_balance)
        self.menu[1]=("Input expense",self.get_expense)
        self.menu[2]=("Exit program",self.exit)
        self.menu[3]=("Create_database (budget.db)",self.bl.create_database)
    def display_balance(self):
        print ("your balance is: %s"%self.bl.report_balance())
    def get_expense(self):
        print("please input the data")
        amount=int(raw_input("amount:"))
        narrativ=raw_input("narrativ:")
        self.bl.input_expense(amount,narrativ)
    def exit(self):
        print ("Goodbye")
        sys.exit(0)
    def display_menu(self):
        print ("Personal Budgeting")
        print ("Please choose a function!")
        for k,v in self.menu.iteritems():
            print k,v[0]
    def main(self):
        choice=-1
        while True:
            self.display_menu()
            choice=int(raw_input("?:"))
            self.menu[choice][1]()
            
if __name__=="__main__":
    BL=BussinesLogic()
    UI=UserInterface(BL)
    UI.main()

As far as security or connections is concerned it doesn't matter really. i understand that this really isn't the way to design the code for a actual real world use. I guess my main question is how to do this...
addExpense():
nameExpense = raw_input('What is the name of the expense')
valueExpense = int(raw_input('What is the value of the expense')
entry = nameExpense, valueExpense

now what i want to be able to do is have each 'entry' as a indexed number, i.e. the first would be 001, Rent, $500 so in a text file or a CSV file i would be able to list 001 then have the option of deleting that option. such as:
def delExpense():
delE = int(raw_input('What expense would you like to delete? ')
del delE


is it possible to make a indexed variable like, user runs addExpense() each entry would be indexed in the same way without using a external file? this is a weird question i understand im just looking at options for this case really, not to say security doesn't matter to me but this is just for a 1 user program that wouldn't require access or save "real" budget information.

I am not sure I understand your "weird" question.

You either put the index into the csv file, or use some natural index, ie the line count.

In both cases you need to get the last index from the file.
This can be done, when the application is started and then internally keep track of it.

However deleting a line from a file without rewriting the data "under" the deleting line cannot be done, I think. That does not sound efficient. The other way is, to delete the line logically, and new entries can use this dead space. This is the beginning of database.

If the data is read into the memory, than practically everything is possible. Except using del:) Del is a language statement reserved for forcing garbage collection.

But you you can use a delEntry function, which does that, and uses your desired del statement;)

def delEntry(index):
    fname="budget.csv"
    entries=open(fname).readlines()
    del entries[index]
    fo=open("budget.csv","w")
    fo.writelines(entries)
    fo.close()

def delExpense():
    delE = int(raw_input('What expense would you like to delete? '))
    delEntry(delE)
delExpense()

Thanks Slate for the exercise, lot of fun for a new python student.
I added a menu item to add funds, that is fine.
I added a menu item to report all the transactions, I can not figure out how to pull the info from the database to display it correctly.

def get_transactions(self):
    ct=self.connection.cursor()
    ct.execute("select * from transact;")
    return ct.fetchall()

def report_transactions(self):
    return self.database.get_transactions()

def display_transactions(self):
    print "Your tranaction History is:",self.bl.report_transactions()

self.menu[5]=("Transaction History",self.display_transactions)

Forgot the results;

Your tranaction History is: [(1, u'Food', -100), (2, u'Deposit', -200), (3, u'Deposit', 500)]

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.