0

My aim is to take the data from 3 different CSV file and create a nested dictionary, I realize my error, but I fail to fix it.

Shall I create 3 different methods for each file to iterate the data and then create the nested dictionary, or it is something else that I have to do?

Code:

class STproject:

    def __init__(self,app): #1
        self.mlb=LabelFrame(app, text='Movie Recommendation Engine')
        self.mlb.grid()
        self.lframe3=LabelFrame(self.mlb,text="Movies/Users",background='purple')
        self.lframe3.grid(row=0,column=1)
        self.framebutton=Frame(self.mlb,background='pink',height=50,width=50)
        self.framebutton.grid(row=0,column=0)
        self.buttonsnlabels()

    def buttonsnlabels(self):
        self.ratingbutton=Button(self.framebutton,text='Upload movies',command=lambda :self.file1())
        self.ratingbutton.grid()
        self.ratingbutton=Button(self.framebutton,text='Upload ratings',command=lambda :self.file2())
        self.ratingbutton.grid()
        self.ratingbutton=Button(self.framebutton,text='Upload links',command=lambda :self.file3())
        self.ratingbutton.grid()

    def file1(self):
        umovies=tkFileDialog.askopenfilename()
        f=open(umovies)
        self.csv_file1 = csv.reader(f)
        self.dictionary()

    def file2(self):
        uratings=tkFileDialog.askopenfilename()
        f=open(uratings)
        self.csv_file2 = csv.reader(f)
        self.dictionary()

    def file3(self):
        links=tkFileDialog.askopenfilename()
        f=open(links)
        self.csv_file3 = csv.reader(f)
        self.dictionary()

    def dictionary(self):
        for line1,line2,line3 in zip(self.csv_file1,self.csv_file2,self.csv_file3):
            dict={}
            dict[line1]={[line2]:[line3]}

root=Tk()
root.title()
application=STproject(root)
root.mainloop()

and this is the error given:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python27\Lib\lib-tk\Tkinter.py", line 1547, in __call__
    return self.func(*args)
  File "C:/Users/Umer Selmani/Desktop/voluntarily/Voluntiraly.py", line 825, in <lambda>
    self.ratingbutton=Button(self.framebutton,text='Upload movies',command=lambda :self.file1())
  File "C:/Users/Umer Selmani/Desktop/voluntarily/Voluntiraly.py", line 836, in file1
    self.dictionary()
  File "C:/Users/Umer Selmani/Desktop/voluntarily/Voluntiraly.py", line 858, in dictionary
    for line1,line2,line3 in zip(self.csv_file1,self.csv_file2,self.csv_file3):
AttributeError: STproject instance has no attribute 'csv_file2'
halfer
  • 19,824
  • 17
  • 99
  • 186
umer selmani
  • 182
  • 9
  • 2
    You should only call the `dictionary` method after all 3 files are read. Calling them prematurely will result in the `AttributeError` since it has not been defined yet. – Henry Yik Jul 23 '19 at 13:47
  • Also, you don't close your CSV files anywhere. Consider 1) keeping only the paths as attributes and open and close them inside the `dictionary` function or 2) store the contents as attributes and close the files after inside the `file` functions. You also keep instantiating your `dict` inside the for loop in the `dictionary` method, meaning you'll only store the last line in the files. – absolutelydevastated Jul 23 '19 at 13:52
  • @HenryYik, so i have to call the **dictionary**, in the first (**__init__**) method, or shall i, shrink all three **file** method in to one and assign it to each **button** – umer selmani Jul 23 '19 at 14:21

1 Answers1

1

I would suggest to first store the selected results at a place, and process them later by another button. In the below sample i'm using StringVar to store the file paths.

class STproject:

    def __init__(self, app):
        self.mlb=LabelFrame(app, text='Movie Recommendation Engine')
        self.mlb.grid()
        self.lframe3=LabelFrame(self.mlb,text="Movies/Users",background='purple')
        self.lframe3.grid(row=0,column=1)
        self.framebutton=Frame(self.mlb,background='pink',height=50,width=50)
        self.framebutton.grid(row=0,column=0)
        self.buttonsnlabels()
        self.all_vars = [StringVar() for _ in range(3)]

    def buttonsnlabels(self):
        self.ratingbutton=Button(self.framebutton,text='Upload movies',command=lambda:self.file(self.all_vars[0]))
        self.ratingbutton.grid(row=0,column=0)
        self.ratingbutton=Button(self.framebutton,text='Upload ratings',command=lambda:self.file(self.all_vars[1]))
        self.ratingbutton.grid(row=1,column=0)
        self.ratingbutton=Button(self.framebutton,text='Upload links',command=lambda:self.file(self.all_vars[2]))
        self.ratingbutton.grid(row=2,column=0)
        self.process = Button(self.framebutton,text='Process',command=self.dictionary)
        self.process.grid(row=1,column=1)

    def file(self, v):
        result = tkFileDialog.askopenfilename()
        if result:
            v.set(result)

    def dictionary(self):
        if all(i.get() for i in self.all_vars): #process only if all 3 files are selected
            with open(self.all_vars[0].get(),"r") as a, open(self.all_vars[1].get(),"r") as b, open(self.all_vars[2].get(),"r") as c:
                d = {}
                for line1,line2,line3 in zip(csv.reader(a),csv.reader(b),csv.reader(c)):
                    d[line1]={line2:line3}

root=Tk()
root.title()
application=STproject(root)
root.mainloop()

Note that I also moved the location and the name of the dict in your original code. In your code, not other it shadows the built in method dict, it also overwrites itself during each iteration of the for loop, which i think would not be what you looking for.

Henry Yik
  • 22,275
  • 4
  • 18
  • 40