AttributeError:'NoneType'对象没有属性'findSongBySize'

时间:2010-09-25 19:04:58

标签: python attributes

我是Ubuntu的新手(以及随之而来的Python脚本),我一直在使用iTunesToRhythm脚本来解决这个错误。

**Traceback (most recent call last):
  File "/home/amylee/iTunesToRhythm.py", line 220, in <module>
    main(sys.argv)
  File "/home/amylee/iTunesToRhythm.py", line 48, in main
    match = correlator.correlateSong( song, options.confirm, options.fastAndLoose,  options.promptForDisambiguate )
  File "/home/amylee/iTunesToRhythm.py", line 133, in correlateSong
    matches = self.parser.findSongBySize( song.size );
AttributeError: 'NoneType' object has no attribute 'findSongBySize'**

我理解修复问题背后的概念,但不知道如何去做。我已经看过类似问题的答案,但没有一个真正帮助我,特别是因为我不知道我在做什么。我已经在下面提供了完整的脚本。提前谢谢,那些比我更了解这些东西的人。

---- ---- iTunesToRhythm.py

import sys
import platform

if platform.system() == "Darwin":
    sys.path.append('/sw/lib/python2.5/site-packages/')
    from dumpitunesmac import iTunesMacParser, iTunesMacSong

import libxml2
import linecache
from optparse import OptionParser,  OptionGroup
from dumprhythm import RhythmLibraryParser, RhythmSong
from dumpitunes import iTunesLibraryParser, iTunesSong

def main(argv):
    # process command line
    options, args = processCommandLine(argv)
    print "Reading input from " + args[0]
    inputParser = getParser(args[0], options  )
    print "Writing to output " + args[1]
    destinationParser = getParser(args[1], options  )

    #retrieve destination songs
    allDestinationSongs = destinationParser.getSongs()

    # go through each song in destination library
    correlator = SongCorrelator(inputParser)
    for song in allDestinationSongs:
        print song.artist + " - " + song.album + " - " + song.title + " - " + str(song.size)
        if song.size != None and song.size != "Unknown":
            # find equivalent itunes song
            match = correlator.correlateSong( song, options.confirm, options.fastAndLoose,  options.promptForDisambiguate )
            # update database, if match
            if match != None and options.writeChanges == True:
                if options.noratings == False:
                    song.setRating( match.rating  )
                    print "\t\t\tRating changed to " + str( match.rating )
                if options.noplaycounts == False:
                    song.setPlaycount( match.playcount )
                    print "\t\t\tPlay count changed to " + str( match.playcount )

    # dump summary results
    print "\nSummary\n------------------------------------"
    print "manually resolved matches = " + str( correlator.manuallyResolvedMatches)
    print "full matches = " + str( correlator.fullMatches )
    print "partial matches = " + str( correlator.partialMatches)
    print "no matches = " + str( correlator.zeroMatches )
    print "unresolved ambiguous matches = " + str( correlator.ambiguousMatches )

    # save
    if options.writeChanges == True:
        destinationParser.save()
        print "Changes were written to destination"
    else:
        print "Changes were not written to destination \n\tuse -w to actually write changes to disk" 

def getParser(  file,  options ):
    if file == "mysql":
        print "\tassuming amarok database"
        return AmarokLibraryParser(options.servername, options.database, options.username,  options.password   )
    if file == "itunes":
        print "\tassuming itunes on the mac"
        return iTunesMacParser()

    desc = linecache.getline( file,  2)
    if desc.find("Apple Computer") != -1:
        #open itunes linbrary
        print "\tdetected Itunes library"
        return iTunesLibraryParser(file);
    if desc.find("rhythmdb") != -1:
        print "\tdetected Rhythm box library"
        return RhythmLibraryParser(file)

def processCommandLine( argv ):
    parser = OptionParser("iTunesToRhythm [options] <inputfile>|itunes|mysql <outputfile>|mysql|itunes")
    parser.add_option("-c", "--confirm", action="store_true", dest="confirm", default = False, help="confirm every match" )
    parser.add_option("-w", "--writechanges", action="store_true", dest="writeChanges", default = False, help="write changes to destination file" )
    parser.add_option("-a", "--disambiguate", action="store_true", dest="promptForDisambiguate", default = False, help="prompt user to resolve ambiguities" )
    parser.add_option("-l",  "--fastandloose", action="store_true", dest= "fastAndLoose",  default = False,  help = "ignore differences in files name when a file size match is made against  a single song.   Will not resolve multiple matches" )
    parser.add_option("--noplaycounts", action="store_true", dest= "noplaycounts",  default = False,  help = "do not update play counts" )
    parser.add_option("--noratings", action="store_true", dest= "noratings",  default = False,  help = "do not update ratings" )

    amarokGroup = OptionGroup(parser,  "Amarok options",  "Options for connecting to an Amarok MySQL remote database")
    amarokGroup.add_option("-s",  "--server",  dest="servername",  help = "host name of the MySQL database server")
    amarokGroup.add_option("-d",  "--database",  dest="database",  help = "database name of the amarok database")
    amarokGroup.add_option("-u",  "--username",  dest="username",  help = "login name of the amarok database")
    amarokGroup.add_option("-p",  "--password",  dest="password",  help = "password of the user")

    parser.add_option_group(amarokGroup)
    # parse options
    options, args = parser.parse_args()

    # check that files are specified
    if len(args) != 2:
            parser.print_help()
            parser.error( "you must supply 2 file names or 1 file name and the word mysql followed by database information.  Specyfing itunes will use a running instance of iTunes on the Mac" )

    # make surce source & destination are not the same
    if args[0] == args[1]:
        parser.error("source and destination cannot be the same")

    # we're ok
    return options, args

class SongCorrelator:
    def __init__(self, parser ):
        self.parser = parser
        self.zeroMatches = 0
        self.fullMatches = 0
        self.ambiguousMatches = 0;
        self.partialMatches = 0;
        self.manuallyResolvedMatches = 0;

    # attempt to find matching song in database
    def correlateSong( self, song, confirm, fastAndLoose,  promptForDisambiguate ):
        match = None
        matches = self.parser.findSongBySize( song.size );
        matchcount = len(matches)

        # no results
        if matchcount == 0:
            print "\t no matches found"
            self.zeroMatches = self.zeroMatches + 1
        # full match
        elif matchcount == 1:
            match = matches[0]
            if match.title == song.title:
                print "\t 100% match on " + self.dumpMatch( match )
                self.fullMatches = self.fullMatches + 1
            else:
                if fastAndLoose == False:
                    match = self.disambiguate( song, matches, promptForDisambiguate )
                else:
                    print "\t 50% match on " + self.dumpMatch( match )
                    self.partialMatches = self.partialMatches + 1
        # multiple matches
        else:
            print "\t multiple matches"
            for match in matches:
                print "\t\t " + self.dumpMatch( match )
            # attempt a resolution
            match = self.disambiguate( song, matches, promptForDisambiguate )

        #review
        if confirm == True:
            foo = raw_input( 'press <enter> to continue, Ctrl-C to cancel')

        #done
        return match

    def dumpMatch(  self, match ):
        return match.title + ", playcount = " + str(match.playcount) + ", rating = " + str(match.rating)

    def disambiguate(self,song,matches,prompt):
        # attempt to disambiguate by title
        print "\t looking for secondary match on title"
        titlematchcount = 0
        for match in matches:
            if match.title == song.title:
                titlematchcount = titlematchcount + 1
                latstitlematch = match

        if titlematchcount == 1:
            # we successfully disambiguated using the title
            print "\t\t disambiguated using title"
            self.fullMatches = self.fullMatches + 1
            return latstitlematch

        if prompt == True:
            print "\t\t cannot disambiguate.  Trying to match " + song.filePath
            print "Please select file or press <Enter> for no match:"
            numMatch = 0
            for match in matches:
                numMatch = numMatch + 1
                print "\t\t\t\t[" + str(numMatch) + "] " + self.dumpMatch(match) + ", " + match.filePath

            selection = self.inputNumber("\t\t\t\t? ", 1, len(matches) )
            if selection > 0:
                self.manuallyResolvedMatches = self.manuallyResolvedMatches + 1
                return matches[selection - 1]

        # user did not select, record ambiguity
        self.ambiguousMatches = self.ambiguousMatches + 1
        return None

    def inputNumber(self, msg, min, max):
        result = raw_input(msg)
        if len(result) == 0:
            return 0
        try:
            resultNum = int(result)

            if resultNum < min or resultNum > max:
                print "out of range"
                return self.inputNumber( msg, min, max )

            return resultNum
        except:
            print "invalid input"
            return self.inputNumber(msg, min, max)


if __name__ == "__main__":
    main(sys.argv)

2 个答案:

答案 0 :(得分:7)

我是原始开发者。如果文件格式无法识别,我更新了脚本以抛出异常(我认为这是你遇到的)。我还从其他用户那里收集了一些有用的补丁。

请再次下载文件,如果仍有问题,请发送电子邮件给我。

答案 1 :(得分:1)

您的问题似乎是getParser正在返回None,大概是因为所有if条件都失败了。

检查args[0]options是否是您期望的值。

如果参数无效,我建议在getParser方法的末尾引发异常,以便在问题的原因附近引发错误,而不是在一些不相关的代码中引发错误。