Note that there are some explanatory texts on larger screens.

plurals
  1. POpython object AttributeError: type object 'Track' has no attribute 'title'
    primarykey
    data
    text
    <p>I apologize if this is a noob question, but I can't seem to figure this one out.</p> <p>I have defined an object that defines a music track (NOTE: originally had the just ATTRIBUTE vs self.ATTRIBUTE. I edited those values in to help remove confusion. They had no affect on the problem)</p> <pre><code>class Track(object): def __init__(self, title, artist, album, source, dest): """ Model of the Track Object Contains the followign attributes: 'Title', 'Artist', 'Album', 'Source', 'Dest' """ self.atrTitle = title self.atrArtist = artist self.atrAlbum = album self.atrSource = source self.atrDest = dest </code></pre> <p>I use ObjectListView to create a list of tracks in a specific directory</p> <pre><code>....other code.... self.aTrack = [Track(sTitle,sArtist,sAlbum,sSource, sDestDir)] self.TrackOlv.AddObjects(self.aTrack) ....other code.... </code></pre> <p>Now I want to iterate the list and print out a single value of each item</p> <pre><code>list = self.TrackOlv.GetObjects() for item in list: print item.atrTitle </code></pre> <p>This fails with the error</p> <pre><code>AttributeError: type object 'Track' has no attribute 'atrTitle' </code></pre> <p>What really confuses me is if I highlight a single item in the Object List View display and use the following code, it will correctly print out the single value for the highlighted item</p> <pre><code>list = self.TrackOlv.GetSelectedObject() print list.atrTitle </code></pre> <p>EDIT: Full source per request. To see error, browse to source dir w/ .mp3 files then click the print button.</p> <pre><code>#Boa:Frame:Frame1 import wx import os import glob import shutil import datetime from mutagen.mp3 import MP3 from mutagen.easyid3 import EasyID3 import mutagen.id3 import unicodedata from ObjectListView import ObjectListView, ColumnDefn ######################################################################## class Track(object): def __init__(self, title, artist, album, source, dest): """ Model of the Track Object Contains the followign attributes: 'Title', 'Artist', 'Album', 'Source', 'Dest' """ self.atrTitle = title self.atrArtist = artist self.atrAlbum = album self.atrSource = source self.atrDest = dest class Action(object): def __init__(self, timestamp, action, result): self.timestamp = timestamp self.action = action self.result = result ######################################################################## # Non GUI ######################################################################## def selectFolder(sMessage): print "Select Folder" dlg = wx.DirDialog(None, message = sMessage) if dlg.ShowModal() == wx.ID_OK: # User has selected something, get the path, set the window's title to the path filename = dlg.GetPath() else: filename = "None Selected" dlg.Destroy() return filename def getList(SourceDir): print "getList" listOfFiles = None print "-list set to none" listOfFiles = glob.glob(SourceDir + '/*.mp3') return listOfFiles def getListRecursive(SourceDir): print "getListRecursive" listOfFiles = None listOfFiles = [] print "-list set to none" for root, dirs, files in os.walk(SourceDir): for file in files: if file.endswith(".mp3"): listOfFiles.append(os.path.join(root,file)) #print listOfFiles return listOfFiles def strip_accents(s): print "strip_accents" return ''.join((c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn')) def replace_all(text): print "replace_all " + text dictionary = {'\\':"", '?':"", '/':"", '...':"", ':':"", '&amp;':"and"} print text print text.decode('utf-8') text = strip_accents(text.decode('utf-8')) for i, j in dictionary.iteritems(): text = text.replace(i,j) return text def getTitle(fileName): print "getTitle" audio = MP3(fileName) try: sTitle = str(audio["TIT2"]) except KeyError: sTitle = os.path.basename(fileName) frame.lvActions.Append([datetime.datetime.now(),fileName,"Title tag does not exist, set to filename"]) # TODO: Offer to set title to filename ## If fileName != filename then ## prompt user for action ## Offer Y/n/a sTitle = replace_all(sTitle) return sTitle def getArtist(fileName): print "get artist" audio = MP3(fileName) try: sArtist = str(audio["TPE1"]) except KeyError: sArtist = "unkown" frame.lvActions.Append([datetime.datetime.now(),fileName,"Artist tag does not exist, set to unkown"]) #Replace all special chars that cause dir path errors sArtist = replace_all(sArtist) #if name = 'The Beatles' change to 'Beatles, The' if sArtist.lower().find('the') == 0: sArtist = sArtist.replace('the ',"") sArtist = sArtist.replace('The ',"") sArtist = sArtist + ", The" return sArtist def getAblum(fileName): print "get album" audio = MP3(fileName) try: sAlbum = str(audio["TALB"]) except KeyError: sAlbum = "unkown" frame.lvActions.Append([datetime.datetime.now(),fileName,"Album tag does not exist, set to unkown"]) #Replace all special chars that cause dir path error sAlbum = replace_all(sAlbum) return sAlbum ######################################################################## # GUI ######################################################################## class MainPanel(wx.Panel): #---------------------------------------------------------------------- def __init__(self, parent): wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY) self.TrackOlv = ObjectListView(self, wx.ID_ANY, style=wx.LC_REPORT|wx.SUNKEN_BORDER) self.setTracks() # Allow the cell values to be edited when double-clicked self.TrackOlv.cellEditMode = ObjectListView.CELLEDIT_SINGLECLICK self.ActionsOlv = ObjectListView(self, wx.ID_ANY, style=wx.LC_REPORT|wx.SUNKEN_BORDER) self.setActions() # create browse to source button sourceBtn = wx.Button(self, wx.ID_ANY, "Browse Source") sourceBtn.Bind(wx.EVT_BUTTON, self.onBrowseSource) # create source txt box self.txSource = wx.TextCtrl(self, wx.ID_ANY, name=u'txSource', value=u'') # create browse dest button destBtn = wx.Button(self, wx.ID_ANY, "Browse Destination") destBtn.Bind(wx.EVT_BUTTON, self.onBrowseDest) # create dest txt box self.txDest = wx.TextCtrl(self, wx.ID_ANY, name=u'txDest', value=u'') # create Move Files button moveBtn = wx.Button(self, wx.ID_ANY, "Move Files") moveBtn.Bind(wx.EVT_BUTTON, self.onMoveFiles) # print list button - debug only printBtn = wx.Button(self, wx.ID_ANY, "Print List") printBtn.Bind(wx.EVT_BUTTON, self.onPrintBtn) # create check box to include all sub files self.cbSubfolders = wx.CheckBox(self, wx.ID_ANY, label=u'Include Subfolders', name=u'cbSubfolders', style=0) self.cbSubfolders.SetValue(True) self.cbSubfolders.Bind(wx.EVT_CHECKBOX, self.OnCbSubfoldersCheckbox) # create check box to repace file names self.cbReplaceFilename = wx.CheckBox(self, wx.ID_ANY, label=u'Replace Filename with Title Tag', name=u'cbReplaceFilename', style=0) self.cbReplaceFilename.SetValue(False) self.cbReplaceFilename.Bind(wx.EVT_CHECKBOX, self.OnCbReplaceFilenameCheckbox) # Create some sizers mainSizer = wx.BoxSizer(wx.VERTICAL) feedbackSizer = wx.BoxSizer(wx.VERTICAL) sourceSizer = wx.BoxSizer(wx.HORIZONTAL) btnSizer = wx.BoxSizer(wx.HORIZONTAL) feedbackSizer.Add(self.TrackOlv, 1, wx.ALL|wx.EXPAND, 2) feedbackSizer.Add(self.ActionsOlv, 1, wx.ALL|wx.EXPAND, 2) sourceSizer.Add(sourceBtn, 0, wx.ALL, 2) sourceSizer.Add(self.txSource, 1, wx.ALL|wx.EXPAND, 2) sourceSizer.Add(destBtn, 0, wx.ALL, 2) sourceSizer.Add(self.txDest, 1, wx.ALL|wx.EXPAND, 2) btnSizer.Add(printBtn) btnSizer.Add(moveBtn, 0, wx.ALL, 2) btnSizer.Add(self.cbSubfolders, 0, wx.ALL, 2) btnSizer.Add(self.cbReplaceFilename, 0, wx.ALL, 2) mainSizer.Add(feedbackSizer, 1 , wx.ALL|wx.EXPAND, 2) mainSizer.Add(sourceSizer, 0, wx.ALL|wx.EXPAND, 2) #mainSizer.Add(destSizer, 0, wx.ALL|wx.EXPAND, 2) #mainSizer.Add(destSizer, 0, wx.All|wx.Expand, 2) mainSizer.Add(btnSizer, 0, wx.ALL, 2) self.SetSizer(mainSizer) mainSizer.Fit(self) #---------------------------------------------------------------------- # Set the GUI column headers and width #---------------------------------------------------------------------- def setTracks(self, data=None): self.TrackOlv.SetColumns([ ColumnDefn("Title", "left", 100, "title"), ColumnDefn("Artist", "left", 100, "artist"), ColumnDefn("Album", "left", 100, "album"), ColumnDefn("Source", "left", 300, "source"), ColumnDefn("Destination", "left", 300, "dest"), ]) def setActions(self, data=None): self.ActionsOlv.SetColumns([ ColumnDefn("Time", "left", 100, "timestamp"), ColumnDefn("Action", "left", 450, "action"), ColumnDefn("Result", "left", 450, "result") ]) #---------------------------------------------------------------------- # GUI EVENTS #----------------------------------------------------------------------- EventList = [Action] #Select Source of files def onBrowseSource(self, event): print "OnBrowseSource" source = selectFolder("Select the Source Directory") print source self.txSource.SetValue(source) self.anEvent = [Action(datetime.datetime.now(),source,"Set as Source dir")] self.ActionsOlv.AddObjects(self.anEvent) self.populateList() #Select Source of files def onBrowseDest(self, event): print "OnBrowseDest" dest = selectFolder("Select the Destination Directory") print dest self.txDest.SetValue(dest) self.anEvent = [Action(datetime.datetime.now(),dest,"Set as Destination dir")] self.ActionsOlv.AddObjects(self.anEvent) self.populateList() def OnCbSubfoldersCheckbox(self, event): print "cbSubfolder" self.populateList() def OnCbReplaceFilenameCheckbox(self, event): print "cbReplaceFilename" self.populateList() def onMoveFiles(self, event): print "onMoveFiles" self.moveFiles() def onPrintBtn(self, event): print "onPrintBtn" #Why does this work #rowObj = self.dataOlv.GetSelectedObject() #print rowObj.author #print rowObj.title #debug - how many item in the list... why does it only print 1? test = self.TrackOlv.GetItemCount() print test print "aphex" print self.TrackOlv.GetObjects() for item in xrange(self.TrackOlv.GetItemCount()): stitle = self.TrackOlv.GetObjectAt(item) print stitle.atrTitle #------------- #Computations #------------- def defineDestFilename(self, sFullDestPath): print "define dest" iCopyX = 0 bExists = False sOrigName = sFullDestPath #If the file does not exist return original path/filename if os.path.isfile(sFullDestPath) == False: print "-" + sFullDestPath + " is valid" return sFullDestPath #Add .copyX.mp3 to the end of the file and retest until a new filename is found while bExists == False: sFullDestPath = sOrigName iCopyX += 1 sFullDestPath = sFullDestPath + ".copy" + str(iCopyX) + ".mp3" if os.path.isfile(sFullDestPath) == False: print "-" + sFullDestPath + " is valid" self.lvActions.Append([datetime.datetime.now(),"Desitnation filename changed since file exists",sFullDestPath]) bExists = True #return path/filename.copyX.mp3 return sFullDestPath def populateList(self): print "populateList" sSource = self.txSource.Value sDest = self.txDest.Value #Initalize list to reset all values on any option change self.initialList = [Track] self.TrackOlv.SetObjects(self.initialList) #Create list of files if self.cbSubfolders.Value == True: listOfFiles = getListRecursive(sSource) else: listOfFiles = getList(sSource) print listOfFiles #prompt if no files detected if listOfFiles == []: self.anEvent = [Action(datetime.datetime.now(),"Parse Source for .MP3 files","No .MP3 files in source directory")] self.ActionsOlv.AddObjects(self.anEvent) #Populate list after both Source and Dest are chosen if len(sDest) &gt; 1 and len(sDest) &gt; 1: print "-iterate listOfFiles" for file in listOfFiles: (sSource,sFilename) = os.path.split(file) print sSource print sFilename #sFilename = os.path.basename(file) sTitle = getTitle(file) try: sArtist = getArtist(file) except UnicodeDecodeError: print "unicode" sArtist = "unkown" sAlbum = getAblum(file) # Make path = sDest + Artist + Album sDestDir = os.path.join (sDest, sArtist) sDestDir = os.path.join (sDestDir, sAlbum) #If file exists change destination to *.copyX.mp3 if self.cbReplaceFilename.Value == True: sDestDir = self.defineDestFilename(os.path.join(sDestDir,sTitle)) else: sDestDir = self.defineDestFilename(os.path.join(sDestDir,sFilename)) # Populate listview with drive contents #sSource = self.txSource.Value sDest = self.txDest.Value # TODO: Make source = exact source of track, not parent source # TODO: Seperate dest and filename self.aTrack = Track(sTitle,sArtist,sAlbum,sSource, sDestDir) self.TrackOlv.AddObjects(self.aTrack) self.Update() #populate list to later use in move command #self.validatedMove.append([file,sDestDir]) print "-item added to SourceDest list" else: print "-list not iterated" def moveFiles (self): print "move files" #for track in self.TrackOlv: # print "-iterate SourceDest" # #create dir # (sDest,filename) = os.path.split(self.TrackOlv) # print "-check dest" # # if not os.path.exists(sDest): # print "-Created dest" # os.makedirs(sDest) # self.lvActions.Append([datetime.datetime.now(),sDest,"Created"]) # self.Update() # self.lvActions.EnsureVisible(self.lvActions.GetItemCount() -1) # # #Move File # print "-move file" # shutil.move(SourceDest[0],SourceDest[1]) # self.lvActions.Append([datetime.datetime.now(),filename,"Moved"]) # self.Update() # self.lvActions.EnsureVisible(self.lvActions.GetItemCount() -1) # #self.lvActions.Append([datetime.datetime.now(),"Move Complete","Success"]) #self.Update() #self.lvActions.EnsureVisible(self.lvActions.GetItemCount() -1) ######################################################################## class MainFrame(wx.Frame): #---------------------------------------------------------------------- def __init__(self): wx.Frame.__init__(self, parent=None, id=wx.ID_ANY, title="MP3 Manager", size=(1024,768)) #W by H panel = MainPanel(self) ######################################################################## class GenApp(wx.App): #---------------------------------------------------------------------- def __init__(self, redirect=False, filename=None): wx.App.__init__(self, redirect, filename) #---------------------------------------------------------------------- def OnInit(self): # create frame here frame = MainFrame() frame.Show() return True #---------------------------------------------------------------------- def main(): """ Run the demo """ app = GenApp() app.MainLoop() if __name__ == "__main__": main() </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload