python 对象 AttributeError: 类型对象 'Track'没有属性“标题”;

发布于 2024-10-19 04:33:15 字数 16804 浏览 3 评论 0原文

如果这是一个菜鸟问题,我很抱歉,但我似乎无法弄清楚这个问题。

我定义了一个定义音乐曲目的对象 (注意:最初只有 ATTRIBUTE 与 self.ATTRIBUTE。我编辑了这些值以帮助消除混乱。它们对问题没有影响)

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

我使用 ObjectListView 在特定目录中创建曲目列表

....other code....
self.aTrack = [Track(sTitle,sArtist,sAlbum,sSource, sDestDir)]
self.TrackOlv.AddObjects(self.aTrack)
....other code....

现在我想迭代列出并打印出每个项目的单个值

list = self.TrackOlv.GetObjects()

for item in list:
    print item.atrTitle

这会失败并出现错误

AttributeError: type object 'Track' has no attribute 'atrTitle'

真正让我困惑的是,如果我在对象列表视图显示中突出显示单个项目并使用以下代码,它将正确打印出突出显示项目的单个值

list = self.TrackOlv.GetSelectedObject()
print list.atrTitle

编辑:每个请求的完整源代码。要查看错误,请浏览到包含 .mp3 文件的源目录,然后单击打印按钮。

#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 = {'\\':"", '?':"", '/':"", '...':"", ':':"", '&':"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) > 1 and len(sDest) > 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()

I apologize if this is a noob question, but I can't seem to figure this one out.

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)

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

I use ObjectListView to create a list of tracks in a specific directory

....other code....
self.aTrack = [Track(sTitle,sArtist,sAlbum,sSource, sDestDir)]
self.TrackOlv.AddObjects(self.aTrack)
....other code....

Now I want to iterate the list and print out a single value of each item

list = self.TrackOlv.GetObjects()

for item in list:
    print item.atrTitle

This fails with the error

AttributeError: type object 'Track' has no attribute 'atrTitle'

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

list = self.TrackOlv.GetSelectedObject()
print list.atrTitle

EDIT: Full source per request. To see error, browse to source dir w/ .mp3 files then click the print button.

#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 = {'\\':"", '?':"", '/':"", '...':"", ':':"", '&':"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) > 1 and len(sDest) > 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()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

浊酒尽余欢 2024-10-26 04:33:15

您没有包含该错误:

....other code....
self.aTrack = [Track(sTitle,sArtist,sAlbum,sSource, sDestDir)]
self.TrackOlv.AddObjects(self.aTrack)
....other code....

它位于第一个“...其他代码...”中的某个位置,可能位于您首次创建 self.TrackOlv 的行上。

查看您的错误消息:

AttributeError: type object 'Track' has no attribute 'atrTitle'

它说实际的类(“类型对象'Track'”)缺少该属性。也就是说,您已将实际的 Track 类而不是该类的实例添加到列表中。它可能是列表中的第一项,或者您的循环在抛出错误之前会打印一些标题。

请注意以下不同的错误消息:

>>> class Foo(object): pass
...
>>> Foo.cat
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: type object 'Foo' has no attribute 'cat'
>>> Foo().cat
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'cat'

You didn't include the bug:

....other code....
self.aTrack = [Track(sTitle,sArtist,sAlbum,sSource, sDestDir)]
self.TrackOlv.AddObjects(self.aTrack)
....other code....

It's somewhere in the first "....other code....", probably on the line where you first create the self.TrackOlv.

Look at your error message:

AttributeError: type object 'Track' has no attribute 'atrTitle'

It's saying the actual class ("type object 'Track'") is lacking the attribute. That is, you've added the actual class Track to your list instead of an instance of that class. It's probably the first item in the list, or your loop would have printed some titles before throwing the error.

Note the different error messages below:

>>> class Foo(object): pass
...
>>> Foo.cat
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: type object 'Foo' has no attribute 'cat'
>>> Foo().cat
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'cat'
如此安好 2024-10-26 04:33:15

为什么要在单成员列表中实例化 Track 对象?更改以下代码,看看是否有帮助。

self.aTrack = [Track(sTitle,sArtist,sAlbum,sSource, sDestDir)]
self.TrackOlv.AddObjects(self.aTrack)

更改为:

self.aTrack = Track(sTitle,sArtist,sAlbum,sSource, sDestDir)
self.TrackOlv.AddObjects(self.aTrack)

顺便说一句,我在解释器中运行了您的代码,它工作正常:

IronPython 2.7 Beta 1 (2.7.0.10) on .NET 4.0.30319.1
Type "help", "copyright", "credits" or "license" for more information.
>>> 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
...
>>> list = [Track('good','h','g','1','d:')]
>>> for item in list:
...     print item.atrTitle
...
good
>>>

更新 @ccwhite:根据您的第二条评论:

>>> list = [Track('1','2','3','4','5'), Track('a','b','c','d','e')]
>>> for item in list:
...     print item.atrTitle
...
1
a
>>>

Why are you instantiating your Track objects inside single-member lists? Change the following code and see if that helps.

self.aTrack = [Track(sTitle,sArtist,sAlbum,sSource, sDestDir)]
self.TrackOlv.AddObjects(self.aTrack)

Change to:

self.aTrack = Track(sTitle,sArtist,sAlbum,sSource, sDestDir)
self.TrackOlv.AddObjects(self.aTrack)

By the way, I ran your code in my interpreter and it works fine:

IronPython 2.7 Beta 1 (2.7.0.10) on .NET 4.0.30319.1
Type "help", "copyright", "credits" or "license" for more information.
>>> 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
...
>>> list = [Track('good','h','g','1','d:')]
>>> for item in list:
...     print item.atrTitle
...
good
>>>

Update @ccwhite: Per your 2nd comment:

>>> list = [Track('1','2','3','4','5'), Track('a','b','c','d','e')]
>>> for item in list:
...     print item.atrTitle
...
1
a
>>>
我不在是我 2024-10-26 04:33:15

您实际上并没有在对象中创建属性,而是创建局部变量。您需要通过以下方式执行此操作:

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

You haven' really created attributes in an object, but rather local variables. You need to do that in following way:

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
梦太阳 2024-10-26 04:33:15

您需要将该属性附加到传递到 Track 的 init 方法中的 self 对象。像这样:

class Track(object):
  def __init__(self, title, artist, album, source, dest):
    """
    Add the properties to the self (aka this) object.
    """
    self.atrTitle = title
    self.atrArtist = artist
    self.atrAlbum = album
    self.atrSource = source
    self.atrDest = dest

You need to attach the property to the self object passed into Track's init method. Like this:

class Track(object):
  def __init__(self, title, artist, album, source, dest):
    """
    Add the properties to the self (aka this) object.
    """
    self.atrTitle = title
    self.atrArtist = artist
    self.atrAlbum = album
    self.atrSource = source
    self.atrDest = dest
星軌x 2024-10-26 04:33:15

不要将 atrTitle 和其他属性声明为

atrTitle = title
atrArtist = artist
atrAlbum = album
atrSource = source
atrDest = dest

您应该在每次赋值之前添加 self. ,如下所示:

self.atrTitle = title
self.atrArtist = artist
self.atrAlbum = album
self.atrSource = source
self.atrDest = dest

Instead of declaring atrTitle and other attributes as

atrTitle = title
atrArtist = artist
atrAlbum = album
atrSource = source
atrDest = dest

You should add self. before each assignment, like this:

self.atrTitle = title
self.atrArtist = artist
self.atrAlbum = album
self.atrSource = source
self.atrDest = dest
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文