diff --git a/misc/offsets.py b/misc/offsets.py index 3e22168..d325bd1 100644 --- a/misc/offsets.py +++ b/misc/offsets.py @@ -14,7 +14,7 @@ doc = handle.read() soup = BeautifulSoup.BeautifulSoup(doc) -offsets = {} # offset -> total count +offsets = {} # offset -> total count rows = soup.findAll('tr') for row in rows: diff --git a/whipper/command/accurip.py b/whipper/command/accurip.py index 56ea470..29b473d 100644 --- a/whipper/command/accurip.py +++ b/whipper/command/accurip.py @@ -26,6 +26,7 @@ from whipper.common import accurip import logging logger = logging.getLogger(__name__) + class Show(BaseCommand): summary = "show accuraterip data" description = """ @@ -52,7 +53,6 @@ retrieves and display accuraterip data from the given URL "Warning: response %d has %d tracks instead of %d\n" % ( i, r.trackCount, count)) - # checksum and confidence by track for track in range(count): sys.stdout.write("Track %d:\n" % (track + 1)) diff --git a/whipper/command/basecommand.py b/whipper/command/basecommand.py index 86c419f..e33aa64 100644 --- a/whipper/command/basecommand.py +++ b/whipper/command/basecommand.py @@ -24,6 +24,7 @@ logger = logging.getLogger(__name__) # A: The prefix matching prevents passing '-h' (and possibly other # options) to the child command. + class BaseCommand(): """ A base command class for whipper commands. diff --git a/whipper/command/cd.py b/whipper/command/cd.py index 9980bc2..eb61ef2 100644 --- a/whipper/command/cd.py +++ b/whipper/command/cd.py @@ -24,10 +24,8 @@ import glob import urllib2 import socket import sys - +import logging import gobject -gobject.threads_init() - from whipper.command.basecommand import BaseCommand from whipper.common import ( accurip, common, config, drive, program, task @@ -35,7 +33,8 @@ from whipper.common import ( from whipper.program import cdrdao, cdparanoia, utils from whipper.result import result -import logging +gobject.threads_init() + logger = logging.getLogger(__name__) @@ -81,24 +80,26 @@ class _CD(BaseCommand): def add_arguments(parser): # FIXME: have a cache of these pickles somewhere parser.add_argument('-T', '--toc-pickle', - action="store", dest="toc_pickle", - help="pickle to use for reading and writing the TOC") + action="store", dest="toc_pickle", + help="pickle to use for reading and " + "writing the TOC") parser.add_argument('-R', '--release-id', - action="store", dest="release_id", - help="MusicBrainz release id to match to (if there are multiple)") + action="store", dest="release_id", + help="MusicBrainz release id to match to " + "(if there are multiple)") parser.add_argument('-p', '--prompt', - action="store_true", dest="prompt", - help="Prompt if there are multiple matching releases") + action="store_true", dest="prompt", + help="Prompt if there are multiple " + "matching releases") parser.add_argument('-c', '--country', - action="store", dest="country", - help="Filter releases by country") - + action="store", dest="country", + help="Filter releases by country") def do(self): self.config = config.Config() self.program = program.Program(self.config, - record=self.options.record, - stdout=sys.stdout) + record=self.options.record, + stdout=sys.stdout) self.runner = task.SyncRunner() # if the device is mounted (data session), unmount it @@ -110,8 +111,8 @@ class _CD(BaseCommand): # first, read the normal TOC, which is fast self.ittoc = self.program.getFastToc(self.runner, - self.options.toc_pickle, - self.device) + self.options.toc_pickle, + self.device) # already show us some info based on this self.program.getRipResult(self.ittoc.getCDDBDiscId()) @@ -120,13 +121,14 @@ class _CD(BaseCommand): sys.stdout.write("MusicBrainz disc id %s\n" % self.mbdiscid) sys.stdout.write("MusicBrainz lookup URL %s\n" % - self.ittoc.getMusicBrainzSubmitURL()) + self.ittoc.getMusicBrainzSubmitURL()) - self.program.metadata = self.program.getMusicBrainz(self.ittoc, - self.mbdiscid, - release=self.options.release_id, - country=self.options.country, - prompt=self.options.prompt) + self.program.metadata = ( + self.program.getMusicBrainz(self.ittoc, self.mbdiscid, + release=self.options.release_id, + country=self.options.country, + prompt=self.options.prompt) + ) if not self.program.metadata: # fall back to FreeDB for lookup @@ -153,8 +155,9 @@ class _CD(BaseCommand): # now, read the complete index table, which is slower self.itable = self.program.getTable(self.runner, - self.ittoc.getCDDBDiscId(), - self.ittoc.getMusicBrainzDiscId(), self.device, offset) + self.ittoc.getCDDBDiscId(), + self.ittoc.getMusicBrainzDiscId(), + self.device, offset) assert self.itable.getCDDBDiscId() == self.ittoc.getCDDBDiscId(), \ "full table's id %s differs from toc id %s" % ( @@ -220,6 +223,7 @@ class Info(_CD): def add_arguments(self): _CD.add_arguments(self.parser) + class Rip(_CD): summary = "rip CD" # see whipper.common.program.Program.getPath for expansion @@ -247,49 +251,62 @@ Log files will log the path to tracks relative to this directory. try: default_offset = config.Config().getReadOffset(*info) sys.stdout.write("Using configured read offset %d\n" % - default_offset) + default_offset) except KeyError: pass _CD.add_arguments(self.parser) self.parser.add_argument('-L', '--logger', - action="store", dest="logger", default='whipper', - help="logger to use (choose from '" + "', '".join(loggers) + "')") + action="store", dest="logger", + default='whipper', + help="logger to use (choose from '" + "', '".join(loggers) + "')") # FIXME: get from config self.parser.add_argument('-o', '--offset', - action="store", dest="offset", default=default_offset, - help="sample read offset") + action="store", dest="offset", + default=default_offset, + help="sample read offset") self.parser.add_argument('-x', '--force-overread', - action="store_true", dest="overread", default=False, - help="Force overreading into the lead-out portion of the disc. " - "Works only if the patched cdparanoia package is installed " - "and the drive supports this feature. ") + action="store_true", dest="overread", + default=False, + help="Force overreading into the " + "lead-out portion of the disc. Works only " + "if the patched cdparanoia package is " + "installed and the drive " + "supports this feature. ") self.parser.add_argument('-O', '--output-directory', - action="store", dest="output_directory", - default=os.path.relpath(os.getcwd()), - help="output directory; will be included in file paths in log") + action="store", dest="output_directory", + default=os.path.relpath(os.getcwd()), + help="output directory; will be included " + "in file paths in log") self.parser.add_argument('-W', '--working-directory', - action="store", dest="working_directory", - help="working directory; whipper will change to this directory " - "and files will be created relative to it when not absolute") + action="store", dest="working_directory", + help="working directory; whipper will " + "change to this directory " + "and files will be created relative to " + "it when not absolute") self.parser.add_argument('--track-template', - action="store", dest="track_template", - default=DEFAULT_TRACK_TEMPLATE, - help="template for track file naming (default default)") + action="store", dest="track_template", + default=DEFAULT_TRACK_TEMPLATE, + help="template for track file naming " + "(default default)") self.parser.add_argument('--disc-template', - action="store", dest="disc_template", - default=DEFAULT_DISC_TEMPLATE, - help="template for disc file naming (default default)") + action="store", dest="disc_template", + default=DEFAULT_DISC_TEMPLATE, + help="template for disc file naming " + "(default default)") self.parser.add_argument('-U', '--unknown', - action="store_true", dest="unknown", - help="whether to continue ripping if the CD is unknown", - default=False) + action="store_true", dest="unknown", + help="whether to continue ripping if " + "the CD is unknown", default=False) def handle_arguments(self): - self.options.output_directory = os.path.expanduser(self.options.output_directory) + self.options.output_directory = os.path.expanduser( + self.options.output_directory) - self.options.track_template = self.options.track_template.decode('utf-8') + self.options.track_template = self.options.track_template.decode( + 'utf-8') self.options.disc_template = self.options.disc_template.decode('utf-8') if self.options.offset is None: @@ -300,9 +317,9 @@ Log files will log the path to tracks relative to this directory. "also be specified at runtime using the " "'--offset=value' argument") - if self.options.working_directory is not None: - self.options.working_directory = os.path.expanduser(self.options.working_directory) + self.options.working_directory = os.path.expanduser( + self.options.working_directory) if self.options.logger: try: @@ -312,7 +329,6 @@ Log files will log the path to tracks relative to this directory. logger.critical(msg) raise ValueError(msg) - def doCommand(self): self.program.setWorkingDirectory(self.options.working_directory) self.program.outdir = self.options.output_directory.decode('utf-8') @@ -320,16 +336,17 @@ Log files will log the path to tracks relative to this directory. self.program.result.overread = self.options.overread self.program.result.logger = self.options.logger - ### write disc files + # write disc files disambiguate = False while True: discName = self.program.getPath(self.program.outdir, - self.options.disc_template, self.mbdiscid, 0, - disambiguate=disambiguate) + self.options.disc_template, + self.mbdiscid, 0, + disambiguate=disambiguate) dirname = os.path.dirname(discName) if os.path.exists(dirname): sys.stdout.write("Output directory %s already exists\n" % - dirname.encode('utf-8')) + dirname.encode('utf-8')) logs = glob.glob(os.path.join(dirname, '*.log')) if logs: sys.stdout.write( @@ -344,14 +361,13 @@ Log files will log the path to tracks relative to this directory. else: sys.stdout.write("Creating output directory %s\n" % - dirname.encode('utf-8')) + dirname.encode('utf-8')) os.makedirs(dirname) break # FIXME: say when we're continuing a rip # FIXME: disambiguate if the pre-existing rip is different - # FIXME: turn this into a method def ripIfNotRipped(number): @@ -363,12 +379,12 @@ Log files will log the path to tracks relative to this directory. self.program.result.tracks.append(trackResult) else: logger.debug('ripIfNotRipped have trackresult, path %r' % - trackResult.filename) + trackResult.filename) path = self.program.getPath(self.program.outdir, - self.options.track_template, - self.mbdiscid, number, - disambiguate=disambiguate) \ + self.options.track_template, + self.mbdiscid, number, + disambiguate=disambiguate) \ + '.' + 'flac' logger.debug('ripIfNotRipped: path %r' % path) trackResult.number = number @@ -378,7 +394,9 @@ Log files will log the path to tracks relative to this directory. if number > 0: trackResult.pregap = self.itable.tracks[number - 1].getPregap() - trackResult.pre_emphasis = self.itable.tracks[number - 1].pre_emphasis + trackResult.pre_emphasis = ( + self.itable.tracks[number - 1].pre_emphasis + ) # FIXME: optionally allow overriding reripping if os.path.exists(path): @@ -411,19 +429,21 @@ Log files will log the path to tracks relative to this directory. os.path.basename(path).encode('utf-8'))) try: logger.debug('ripIfNotRipped: track %d, try %d', - number, tries) + number, tries) self.program.ripTrack(self.runner, trackResult, - offset=int(self.options.offset), - device=self.device, - taglist=self.program.getTagList(number), - overread=self.options.overread, - what='track %d of %d%s' % ( - number, len(self.itable.tracks), extra)) + offset=int(self.options.offset), + device=self.device, + taglist=self.program.getTagList( + number), + overread=self.options.overread, + what='track %d of %d%s' % ( + number, + len(self.itable.tracks), + extra)) break except Exception, e: logger.debug('Got exception %r on try %d', - e, tries) - + e, tries) if tries == MAX_TRIES: logger.critical('Giving up on track %d after %d times' % ( @@ -433,39 +453,43 @@ Log files will log the path to tracks relative to this directory. "Rip attempts number is equal to 'MAX_TRIES'") if trackResult.testcrc == trackResult.copycrc: sys.stdout.write('Checksums match for track %d\n' % - number) + number) else: sys.stdout.write( 'ERROR: checksums did not match for track %d\n' % number) raise - sys.stdout.write('Peak level: {:.2%} \n'.format(trackResult.peak)) + sys.stdout.write( + 'Peak level: {:.2%} \n'.format(trackResult.peak)) - sys.stdout.write('Rip quality: {:.2%}\n'.format(trackResult.quality)) + sys.stdout.write( + 'Rip quality: {:.2%}\n'.format(trackResult.quality)) # overlay this rip onto the Table if number == 0: # HTOA goes on index 0 of track 1 # ignore silence in PREGAP if trackResult.peak <= SILENT: - logger.debug('HTOA peak %r is below SILENT threshold, disregarding', trackResult.peak) + logger.debug( + 'HTOA peak %r is below SILENT ' + 'threshold, disregarding', trackResult.peak) self.itable.setFile(1, 0, None, - self.ittoc.getTrackStart(1), number) + self.ittoc.getTrackStart(1), number) logger.debug('Unlinking %r', trackResult.filename) os.unlink(trackResult.filename) trackResult.filename = None - sys.stdout.write('HTOA discarded, contains digital silence\n') + sys.stdout.write( + 'HTOA discarded, contains digital silence\n') else: self.itable.setFile(1, 0, trackResult.filename, - self.ittoc.getTrackStart(1), number) + self.ittoc.getTrackStart(1), number) else: self.itable.setFile(number, 1, trackResult.filename, - self.ittoc.getTrackLength(number), number) + self.ittoc.getTrackLength(number), number) self.program.saveRipResult() - # check for hidden track one audio htoapath = None htoa = self.program.getHTOA() @@ -473,7 +497,7 @@ Log files will log the path to tracks relative to this directory. start, stop = htoa sys.stdout.write( 'Found Hidden Track One Audio from frame %d to %d\n' % ( - start, stop)) + start, stop)) # rip it ripIfNotRipped(0) @@ -484,17 +508,18 @@ Log files will log the path to tracks relative to this directory. if not track.audio: sys.stdout.write( 'WARNING: skipping data track %d, not implemented\n' % ( - i + 1, )) + i + 1, )) # FIXME: make it work for now track.indexes[1].relative = 0 continue ripIfNotRipped(i + 1) - ### write disc files + # write disc files discName = self.program.getPath(self.program.outdir, - self.options.disc_template, self.mbdiscid, 0, - disambiguate=disambiguate) + self.options.disc_template, + self.mbdiscid, 0, + disambiguate=disambiguate) dirname = os.path.dirname(discName) if not os.path.exists(dirname): os.makedirs(dirname) @@ -516,20 +541,22 @@ Log files will log the path to tracks relative to this directory. u = '%s\n' % targetPath handle.write(u.encode('utf-8')) - if htoapath: writeFile(handle, htoapath, - self.itable.getTrackStart(1) / common.FRAMES_PER_SECOND) + self.itable.getTrackStart(1) / common.FRAMES_PER_SECOND) for i, track in enumerate(self.itable.tracks): if not track.audio: continue path = self.program.getPath(self.program.outdir, - self.options.track_template, self.mbdiscid, i + 1, - disambiguate=disambiguate) + '.' + 'flac' + self.options.track_template, + self.mbdiscid, i + 1, + disambiguate=disambiguate + ) + '.' + 'flac' writeFile(handle, path, - self.itable.getTrackLength(i + 1) / common.FRAMES_PER_SECOND) + (self.itable.getTrackLength(i + 1) / + common.FRAMES_PER_SECOND)) handle.close() @@ -556,14 +583,13 @@ Log files will log the path to tracks relative to this directory. if responses: sys.stdout.write('%d AccurateRip reponses found\n' % - len(responses)) + len(responses)) if responses[0].cddbDiscId != self.itable.getCDDBDiscId(): sys.stdout.write( "AccurateRip response discid different: %s\n" % responses[0].cddbDiscId) - self.program.verifyImage(self.runner, responses) sys.stdout.write("\n".join( diff --git a/whipper/command/debug.py b/whipper/command/debug.py index 28d99df..f5970dd 100644 --- a/whipper/command/debug.py +++ b/whipper/command/debug.py @@ -28,6 +28,7 @@ from whipper.result import result import logging logger = logging.getLogger(__name__) + class RCCue(BaseCommand): summary = "write a cue file for the cached result" description = summary @@ -148,9 +149,6 @@ class Encode(BaseCommand): description = summary def add_arguments(self): - # here to avoid import gst eating our options - from whipper.common import encode - self.parser.add_argument('input', action='store', help="audio file to encode") self.parser.add_argument('output', nargs='?', action='store', @@ -174,8 +172,8 @@ class Encode(BaseCommand): runner = task.SyncRunner() logger.debug('Encoding %s to %s', - fromPath.encode('utf-8'), - toPath.encode('utf-8')) + fromPath.encode('utf-8'), + toPath.encode('utf-8')) encodetask = encode.FlacEncodeTask(fromPath, toPath) runner.run(encodetask) @@ -244,7 +242,7 @@ Example disc id: KnpGsLhvH.lPrNc1PBL21lb9Bg4-""" sys.stdout.write('- Release %d:\n' % (i + 1, )) sys.stdout.write(' Artist: %s\n' % md.artist.encode('utf-8')) sys.stdout.write(' Title: %s\n' % md.title.encode('utf-8')) - sys.stdout.write(' Type: %s\n' % md.releaseType.encode('utf-8')) + sys.stdout.write(' Type: %s\n' % md.releaseType.encode('utf-8')) # noqa: E501 sys.stdout.write(' URL: %s\n' % md.url) sys.stdout.write(' Tracks: %d\n' % len(md.tracks)) if md.catalogNumber: diff --git a/whipper/command/drive.py b/whipper/command/drive.py index 3af5cbf..0046034 100644 --- a/whipper/command/drive.py +++ b/whipper/command/drive.py @@ -28,9 +28,10 @@ from whipper.program import cdparanoia import logging logger = logging.getLogger(__name__) + class Analyze(BaseCommand): summary = "analyze caching behaviour of drive" - description = """Determine whether cdparanoia can defeat the audio cache of the drive.""" + description = """Determine whether cdparanoia can defeat the audio cache of the drive.""" # noqa: E501 device_option = True def do(self): @@ -51,14 +52,15 @@ class Analyze(BaseCommand): info = drive.getDeviceInfo(self.options.device) if not info: - sys.stdout.write('Drive caching behaviour not saved: could not get device info (requires pycdio).\n') + sys.stdout.write('Drive caching behaviour not saved:' + 'could not get device info (requires pycdio).\n') return sys.stdout.write( 'Adding drive cache behaviour to configuration file.\n') - config.Config().setDefeatsCache(info[0], info[1], info[2], - t.defeatsCache) + config.Config().setDefeatsCache( + info[0], info[1], info[2], t.defeatsCache) class List(BaseCommand): @@ -77,7 +79,7 @@ class List(BaseCommand): return try: - import cdio as _ + import cdio as _ # noqa: F401 (TODO: fix it in a separate PR?) except ImportError: sys.stdout.write( 'Install pycdio for vendor/model/release detection.\n') @@ -87,7 +89,7 @@ class List(BaseCommand): vendor, model, release = drive.getDeviceInfo(path) sys.stdout.write( "drive: %s, vendor: %s, model: %s, release: %s\n" % ( - path, vendor, model, release)) + path, vendor, model, release)) try: offset = self.config.getReadOffset( @@ -95,8 +97,10 @@ class List(BaseCommand): sys.stdout.write( " Configured read offset: %d\n" % offset) except KeyError: - sys.stdout.write( - " No read offset found. Run 'whipper offset find'\n") + # Note spaces at the beginning for pretty terminal output + sys.stdout.write(" " + "No read offset found. " + "Run 'whipper offset find'\n") try: defeats = self.config.getDefeatsCache( @@ -108,7 +112,6 @@ class List(BaseCommand): " Unknown whether audio cache can be defeated. " "Run 'whipper drive analyze'\n") - if not paths: sys.stdout.write('No drives found.\n') diff --git a/whipper/command/image.py b/whipper/command/image.py index 94c12c3..510a56b 100644 --- a/whipper/command/image.py +++ b/whipper/command/image.py @@ -72,11 +72,11 @@ Retags the image from the given .cue files with tags obtained from MusicBrainz. sys.stdout.write('MusicBrainz disc id is %s\n' % mbdiscid) sys.stdout.write("MusicBrainz lookup URL %s\n" % - cueImage.table.getMusicBrainzSubmitURL()) + cueImage.table.getMusicBrainzSubmitURL()) prog.metadata = prog.getMusicBrainz(cueImage.table, mbdiscid, - release=self.options.release_id, - country=self.options.country, - prompt=self.options.prompt) + release=self.options.release_id, # noqa: E501 + country=self.options.country, + prompt=self.options.prompt) if not prog.metadata: print 'Not in MusicBrainz database, skipping' diff --git a/whipper/command/main.py b/whipper/command/main.py index 0219591..553f7c8 100644 --- a/whipper/command/main.py +++ b/whipper/command/main.py @@ -17,6 +17,7 @@ from whipper.program.utils import eject_device import logging logger = logging.getLogger(__name__) + def main(): # set user agent musicbrainzngs.set_useragent("whipper", whipper.__version__, @@ -47,7 +48,7 @@ def main(): if isinstance(e.exception, common.EmptyError): logger.debug("EmptyError: %r", str(e.exception)) - sys.stderr.write('whipper: error: Could not create encoded file.\n') + sys.stderr.write('whipper: error: Could not create encoded file.\n') # noqa: E501 return 255 # in python3 we can instead do `raise e.exception` as that would show @@ -56,6 +57,7 @@ def main(): return 255 return ret if ret else 0 + class Whipper(BaseCommand): description = """whipper is a CD ripping utility focusing on accuracy over speed. @@ -74,18 +76,20 @@ You can get help on subcommands by using the -h option to the subcommand. def add_arguments(self): self.parser.add_argument('-R', '--record', - action='store_true', dest='record', - help="record API requests for playback") + action='store_true', dest='record', + help="record API requests for playback") self.parser.add_argument('-v', '--version', - action="store_true", dest="version", - help="show version information") + action="store_true", dest="version", + help="show version information") self.parser.add_argument('-h', '--help', - action="store_true", dest="help", - help="show this help message and exit") + action="store_true", dest="help", + help="show this help message and exit") self.parser.add_argument('-e', '--eject', - action="store", dest="eject", default="always", - choices=('never', 'failure', 'success', 'always'), - help="when to eject disc (default: always)") + action="store", dest="eject", + default="always", + choices=('never', 'failure', + 'success', 'always'), + help="when to eject disc (default: always)") def handle_arguments(self): if self.options.help: diff --git a/whipper/command/offset.py b/whipper/command/offset.py index b4223ed..7520757 100644 --- a/whipper/command/offset.py +++ b/whipper/command/offset.py @@ -22,19 +22,17 @@ import argparse import os import sys import tempfile - +import logging import gobject -gobject.threads_init() - from whipper.command.basecommand import BaseCommand -from whipper.common import accurip, common, config, drive, program +from whipper.common import accurip, common, config, drive from whipper.common import task as ctask from whipper.program import cdrdao, cdparanoia, utils from whipper.common import checksum - from whipper.extern.task import task -import logging +gobject.threads_init() + logger = logging.getLogger(__name__) # see http://www.accuraterip.com/driveoffsets.htm @@ -117,7 +115,7 @@ CD in the AccurateRip database.""" if responses[0].cddbDiscId != table.getCDDBDiscId(): logger.warning("AccurateRip response discid different: %s", - responses[0].cddbDiscId) + responses[0].cddbDiscId) # now rip the first track at various offsets, calculating AccurateRip # CRC, and matching it against the retrieved ones @@ -137,7 +135,7 @@ CD in the AccurateRip database.""" # let MissingDependency fall through if isinstance(e.exception, - common.MissingDependencyException): + common.MissingDependencyException): raise e if isinstance(e.exception, cdparanoia.FileSizeError): @@ -159,7 +157,7 @@ CD in the AccurateRip database.""" logger.debug('MATCHED against response %d' % i) sys.stdout.write( 'Offset of device is likely %d, confirming ...\n' % - offset) + offset) # now try and rip all other tracks as well, except for the # last one (to avoid readers that can't do overread @@ -185,7 +183,7 @@ CD in the AccurateRip database.""" else: sys.stdout.write( 'Only %d of %d tracks matched, continuing ...\n' % ( - count, len(table.tracks))) + count, len(table.tracks))) sys.stdout.write('No matching offset found.\n') sys.stdout.write('Consider trying again with a different disc.\n') @@ -201,16 +199,19 @@ CD in the AccurateRip database.""" os.close(fd) t = cdparanoia.ReadTrackTask(path, table, - table.getTrackStart(track), table.getTrackEnd(track), - overread=False, offset=offset, device=self.options.device) + table.getTrackStart( + track), table.getTrackEnd(track), + overread=False, offset=offset, + device=self.options.device) t.description = 'Ripping track %d with read offset %d' % ( track, offset) runner.run(t) - # TODO MW: Update this to also use the v2 checksum(s) - t = checksum.FastAccurateRipChecksumTask(path, trackNumber=track, - trackCount=len(table.tracks), wave=True, v2=False) + t = checksum.FastAccurateRipChecksumTask(path, + trackNumber=track, + trackCount=len(table.tracks), + wave=True, v2=False) runner.run(t) os.unlink(path) @@ -218,17 +219,19 @@ CD in the AccurateRip database.""" def _foundOffset(self, device, offset): sys.stdout.write('\nRead offset of device is: %d.\n' % - offset) + offset) info = drive.getDeviceInfo(device) if not info: - sys.stdout.write('Offset not saved: could not get device info (requires pycdio).\n') + sys.stdout.write( + 'Offset not saved: could not get ' + 'device info (requires pycdio).\n') return sys.stdout.write('Adding read offset to configuration file.\n') config.Config().setReadOffset(info[0], info[1], info[2], - offset) + offset) class Offset(BaseCommand): diff --git a/whipper/common/cache.py b/whipper/common/cache.py index 6e5e4e6..0c5743c 100644 --- a/whipper/common/cache.py +++ b/whipper/common/cache.py @@ -30,6 +30,7 @@ from whipper.common import directory import logging logger = logging.getLogger(__name__) + class Persister: """ I wrap an optional pickle to persist an object to disk. @@ -125,7 +126,7 @@ class PersistedCache: try: os.makedirs(self.path) except OSError, e: - if e.errno != 17: # FIXME + if e.errno != 17: # FIXME raise def _getPath(self, key): @@ -176,7 +177,7 @@ class ResultCache: presult.persist(presult.object) else: logger.debug('result for cddbdiscid %r found in cache, reusing', - cddbdiscid) + cddbdiscid) return presult @@ -218,7 +219,7 @@ class TableCache: ptable.object = None else: logger.debug('no valid cached table found for %r' % - cddbdiscid) + cddbdiscid) if not ptable.object: # get an empty persistable from the writable location diff --git a/whipper/common/checksum.py b/whipper/common/checksum.py index 17dd898..790d737 100644 --- a/whipper/common/checksum.py +++ b/whipper/common/checksum.py @@ -67,8 +67,9 @@ class FastAccurateRipChecksumTask(etask.Task): self.schedule(0.0, self._arc) def _arc(self): - arc = accuraterip_checksum(self.path, self.trackNumber, self.trackCount, - self._wave, self._v2) + arc = accuraterip_checksum(self.path, self.trackNumber, + self.trackCount, + self._wave, self._v2) self.checksum = arc self.stop() diff --git a/whipper/common/common.py b/whipper/common/common.py index 1fe563f..51181c1 100644 --- a/whipper/common/common.py +++ b/whipper/common/common.py @@ -21,7 +21,6 @@ import os import os.path -import commands import math import subprocess @@ -32,7 +31,7 @@ logger = logging.getLogger(__name__) FRAMES_PER_SECOND = 75 -SAMPLES_PER_FRAME = 588 # a sample is 2 16-bit values, left and right channel +SAMPLES_PER_FRAME = 588 # a sample is 2 16-bit values, left and right channel WORDS_PER_FRAME = SAMPLES_PER_FRAME * 2 BYTES_PER_FRAME = SAMPLES_PER_FRAME * 4 @@ -41,6 +40,7 @@ class EjectError(SystemError): """ Possibly ejects the drive in command.main. """ + def __init__(self, device, *args): """ args is a tuple used by BaseException.__str__ @@ -60,7 +60,7 @@ def msfToFrames(msf): @rtype: int @returns: number of frames """ - if not ':' in msf: + if ':' not in msf: return int(msf) m, s, f = msf.split(':') @@ -133,6 +133,7 @@ def formatTime(seconds, fractional=3): return " ".join(chunks) + class MissingDependencyException(Exception): dependency = None @@ -144,6 +145,7 @@ class MissingDependencyException(Exception): class EmptyError(Exception): pass + class MissingFrames(Exception): """ Less frames decoded than expected. @@ -289,8 +291,8 @@ class VersionGetter(object): try: p = asyncsub.Popen(self._args, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, close_fds=True) + stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, close_fds=True) p.wait() output = asyncsub.recv_some(p, e=0, stderr=1) vre = self._regexp.search(output) diff --git a/whipper/common/config.py b/whipper/common/config.py index 9c75d28..30cdbea 100644 --- a/whipper/common/config.py +++ b/whipper/common/config.py @@ -30,6 +30,7 @@ from whipper.common import directory import logging logger = logging.getLogger(__name__) + class Config: def __init__(self, path=None): @@ -46,7 +47,7 @@ class Config: self._parser.readfp(f) logger.info('Loaded %d sections from config file' % - len(self._parser.sections())) + len(self._parser.sections())) def write(self): fd, path = tempfile.mkstemp(suffix=u'.whipperrc') @@ -55,8 +56,7 @@ class Config: handle.close() shutil.move(path, self._path) - - ### any section + # any section def _getter(self, suffix, section, option): methodName = 'get' + suffix @@ -72,7 +72,7 @@ class Config: def getboolean(self, section, option): return self._getter('boolean', section, option) - ### drive sections + # drive sections def setReadOffset(self, vendor, model, release, offset): """ @@ -96,7 +96,6 @@ class Config: raise KeyError("Could not find read_offset for %s/%s/%s" % ( vendor, model, release)) - def setDefeatsCache(self, vendor, model, release, defeat): """ Set whether the drive defeats the cache. @@ -139,7 +138,7 @@ class Config: return name raise KeyError("Could not find configuration section for %s/%s/%s" % ( - vendor, model, release)) + vendor, model, release)) def _findOrCreateDriveSection(self, vendor, model, release): try: diff --git a/whipper/common/directory.py b/whipper/common/directory.py index 42942d6..f351c02 100644 --- a/whipper/common/directory.py +++ b/whipper/common/directory.py @@ -21,6 +21,7 @@ from os import getenv, makedirs from os.path import join, expanduser, exists + def config_path(): path = join(getenv('XDG_CONFIG_HOME') or join(expanduser('~'), u'.config'), u'whipper') @@ -28,6 +29,7 @@ def config_path(): makedirs(path) return join(path, u'whipper.conf') + def cache_path(name=None): path = join(getenv('XDG_CACHE_HOME') or join(expanduser('~'), u'.cache'), u'whipper') @@ -37,9 +39,10 @@ def cache_path(name=None): makedirs(path) return path + def data_path(name=None): - path = join(getenv('XDG_DATA_HOME') - or join(expanduser('~'), u'.local/share'), + path = join(getenv('XDG_DATA_HOME') or + join(expanduser('~'), u'.local/share'), u'whipper') if name: path = join(path, name) diff --git a/whipper/common/drive.py b/whipper/common/drive.py index b20642a..ccab884 100644 --- a/whipper/common/drive.py +++ b/whipper/common/drive.py @@ -23,6 +23,7 @@ import os import logging logger = logging.getLogger(__name__) + def _listify(listOrString): if type(listOrString) == str: return [listOrString, ] @@ -64,7 +65,6 @@ def getDeviceInfo(path): import cdio except ImportError: return None - device = cdio.Device(path) ok, vendor, model, release = device.get_hwinfo() diff --git a/whipper/common/encode.py b/whipper/common/encode.py index 309c581..2fb12f1 100644 --- a/whipper/common/encode.py +++ b/whipper/common/encode.py @@ -29,6 +29,7 @@ from whipper.program import flac import logging logger = logging.getLogger(__name__) + class SoxPeakTask(task.Task): description = 'Calculating peak level' @@ -44,6 +45,7 @@ class SoxPeakTask(task.Task): self.peak = sox.peak_level(self.track_path) self.stop() + class FlacEncodeTask(task.Task): description = 'Encoding to FLAC' @@ -61,11 +63,13 @@ class FlacEncodeTask(task.Task): self.new_path = flac.encode(self.track_path, self.track_out_path) self.stop() -# TODO: Wizzup: Do we really want this as 'Task'...? -# I only made it a task for now because that it's easier to integrate in -# program/cdparanoia.py - where whipper currently does the tagging. -# We should just move the tagging to a more sensible place. + class TaggingTask(task.Task): + # TODO: Wizzup: Do we really want this as 'Task'...? + # I only made it a task for now because that it's easier to integrate in + # program/cdparanoia.py - where whipper currently does the tagging. + # We should just move the tagging to a more sensible place. + description = 'Writing tags to FLAC' def __init__(self, track_path, tags): diff --git a/whipper/common/mbngs.py b/whipper/common/mbngs.py index ffdc96f..cff56e7 100644 --- a/whipper/common/mbngs.py +++ b/whipper/common/mbngs.py @@ -28,7 +28,7 @@ import logging logger = logging.getLogger(__name__) -VA_ID = "89ad4ac3-39f7-470e-963a-56509c546377" # Various Artists +VA_ID = "89ad4ac3-39f7-470e-963a-56509c546377" # Various Artists class MusicBrainzException(Exception): @@ -47,7 +47,7 @@ class NotFoundException(MusicBrainzException): class TrackMetadata(object): artist = None title = None - duration = None # in ms + duration = None # in ms mbid = None sortName = None mbidArtist = None @@ -131,7 +131,6 @@ class _Credit(list): return "".join(res) - def getSortName(self): return self.joiner(lambda i: i.get('artist').get('sort-name', None)) @@ -140,7 +139,7 @@ class _Credit(list): def getIds(self): return self.joiner(lambda i: i.get('artist').get('id', None), - joinString=";") + joinString=";") def _getMetadata(releaseShort, release, discid, country=None): @@ -152,7 +151,7 @@ def _getMetadata(releaseShort, release, discid, country=None): @rtype: L{DiscMetadata} or None """ logger.debug('getMetadata for release id %r', - release['id']) + release['id']) if not release['id']: logger.warning('No id for release %r', release) return None @@ -173,7 +172,6 @@ def _getMetadata(releaseShort, release, discid, country=None): if discCredit[0]['artist']['id'] == VA_ID: discMD.various = True - if len(discCredit) > 1: logger.debug('artist-credit more than 1: %r', discCredit) @@ -233,8 +231,9 @@ def _getMetadata(releaseShort, release, discid, country=None): # FIXME: unit of duration ? track.duration = int(t['recording'].get('length', 0)) if not track.duration: - logger.warning('track %r (%r) does not have duration' % ( - track.title, track.mbid)) + logger.warning( + 'track %r (%r) does not have duration' % + (track.title, track.mbid)) tainted = True else: duration += track.duration @@ -270,8 +269,8 @@ def musicbrainz(discid, country=None, record=False): ret = [] try: - result = musicbrainzngs.get_releases_by_discid(discid, - includes=["artists", "recordings", "release-groups"]) + result = musicbrainzngs.get_releases_by_discid( + discid, includes=["artists", "recordings", "release-groups"]) except musicbrainzngs.ResponseError, e: if isinstance(e.cause, urllib2.HTTPError): if e.cause.code == 404: @@ -284,7 +283,7 @@ def musicbrainz(discid, country=None, record=False): # The result can either be a "disc" or a "cdstub" if result.get('disc'): logger.debug('found %d releases for discid %r', - len(result['disc']['release-list']), discid) + len(result['disc']['release-list']), discid) _record(record, 'releases', discid, result) # Display the returned results to the user. diff --git a/whipper/common/path.py b/whipper/common/path.py index 6b1ff51..a5d0eb4 100644 --- a/whipper/common/path.py +++ b/whipper/common/path.py @@ -51,12 +51,13 @@ class PathFilter(object): # change all fancy single/double quotes to normal quotes if self._quotes: path = re.sub(ur'[\xc2\xb4\u2018\u2019\u201b]', "'", path, - re.UNICODE) + re.UNICODE) path = re.sub(ur'[\u201c\u201d\u201f]', '"', path, re.UNICODE) if self._special: path = separators(path) - path = re.sub(r'[\*\?&!\'\"\$\(\)`{}\[\]<>]', '_', path, re.UNICODE) + path = re.sub(r'[\*\?&!\'\"\$\(\)`{}\[\]<>]', + '_', path, re.UNICODE) if self._fat: path = separators(path) diff --git a/whipper/common/program.py b/whipper/common/program.py index 113365f..5f084b8 100644 --- a/whipper/common/program.py +++ b/whipper/common/program.py @@ -76,7 +76,7 @@ class Program: 'special': False }.items(): value = None - value = self._config.getboolean('main', 'path_filter_'+ key) + value = self._config.getboolean('main', 'path_filter_' + key) if value is None: value = default @@ -105,9 +105,8 @@ class Program: version = cdrdao.getCDRDAOVersion() if V(version) < V('1.2.3rc2'): sys.stdout.write('Warning: cdrdao older than 1.2.3 has a ' - 'pre-gap length bug.\n' - 'See http://sourceforge.net/tracker/?func=detail' - '&aid=604751&group_id=2171&atid=102171\n') + 'pre-gap length bug.\n' + 'See http://sourceforge.net/tracker/?func=detail&aid=604751&group_id=2171&atid=102171\n') # noqa: E501 t = cdrdao.ReadTOCTask(device) ptoc.persist(t.table) toc = ptoc.object @@ -133,17 +132,17 @@ class Program: itable = tdict[offset] if not itable: - logger.debug('getTable: cddbdiscid %s, mbdiscid %s not in cache for offset %s, ' - 'reading table' % ( - cddbdiscid, mbdiscid, offset)) + logger.debug('getTable: cddbdiscid %s, mbdiscid %s not ' + 'in cache for offset %s, reading table' % ( + cddbdiscid, mbdiscid, offset)) t = cdrdao.ReadTableTask(device) itable = t.table tdict[offset] = itable ptable.persist(tdict) logger.debug('getTable: read table %r' % itable) else: - logger.debug('getTable: cddbdiscid %s, mbdiscid %s in cache for offset %s' % ( - cddbdiscid, mbdiscid, offset)) + logger.debug('getTable: cddbdiscid %s, mbdiscid %s in cache ' + 'for offset %s' % (cddbdiscid, mbdiscid, offset)) logger.debug('getTable: loaded table %r' % itable) assert itable.hasTOC() @@ -151,7 +150,7 @@ class Program: self.result.table = itable logger.debug('getTable: returning table with mb id %s' % - itable.getMusicBrainzDiscId()) + itable.getMusicBrainzDiscId()) return itable def getRipResult(self, cddbdiscid): @@ -200,11 +199,11 @@ class Program: # default values v['A'] = 'Unknown Artist' - v['d'] = mbdiscid # fallback for title + v['d'] = mbdiscid # fallback for title v['r'] = 'unknown' v['R'] = 'Unknown' - v['B'] = '' # barcode - v['C'] = '' # catalog number + v['B'] = '' # barcode + v['C'] = '' # catalog number v['x'] = 'flac' v['X'] = v['x'].upper() v['y'] = '0000' @@ -215,7 +214,6 @@ class Program: else: v['n'] = 'Unknown Track %d' % i - if self.metadata: release = self.metadata.release or '0000' v['y'] = release[:4] @@ -229,10 +227,12 @@ class Program: v['r'] = self.metadata.releaseType.lower() if i > 0: try: - v['a'] = self._filter.filter(self.metadata.tracks[i - 1].artist) + v['a'] = self._filter.filter( + self.metadata.tracks[i - 1].artist) v['s'] = self._filter.filter( self.metadata.tracks[i - 1].sortName) - v['n'] = self._filter.filter(self.metadata.tracks[i - 1].title) + v['n'] = self._filter.filter( + self.metadata.tracks[i - 1].title) except IndexError, e: print 'ERROR: no track %d found, %r' % (i, e) raise @@ -255,8 +255,6 @@ class Program: ret = os.path.join(outdir, template % v) - - return ret def getCDDB(self, cddbdiscid): @@ -282,7 +280,8 @@ class Program: return None - def getMusicBrainz(self, ittoc, mbdiscid, release=None, country=None, prompt=False): + def getMusicBrainz(self, ittoc, mbdiscid, release=None, country=None, + prompt=False): """ @type ittoc: L{whipper.image.table.Table} """ @@ -291,7 +290,7 @@ class Program: common.formatTime(ittoc.duration() / 1000.0), ittoc.getAudioTracks())) logger.debug('MusicBrainz submit url: %r', - ittoc.getMusicBrainzSubmitURL()) + ittoc.getMusicBrainzSubmitURL()) ret = None metadatas = None @@ -300,8 +299,8 @@ class Program: for _ in range(0, 4): try: metadatas = mbngs.musicbrainz(mbdiscid, - country=country, - record=self._record) + country=country, + record=self._record) break except mbngs.NotFoundException, e: break @@ -326,21 +325,23 @@ class Program: for metadata in metadatas: self._stdout.write('\n') self._stdout.write('Artist : %s\n' % - metadata.artist.encode('utf-8')) + metadata.artist.encode('utf-8')) self._stdout.write('Title : %s\n' % - metadata.title.encode('utf-8')) + metadata.title.encode('utf-8')) self._stdout.write('Duration: %s\n' % - common.formatTime(metadata.duration / 1000.0)) + common.formatTime(metadata.duration / + 1000.0)) self._stdout.write('URL : %s\n' % metadata.url) self._stdout.write('Release : %s\n' % metadata.mbid) self._stdout.write('Type : %s\n' % metadata.releaseType) if metadata.barcode: self._stdout.write("Barcode : %s\n" % metadata.barcode) if metadata.catalogNumber: - self._stdout.write("Cat no : %s\n" % metadata.catalogNumber) + self._stdout.write("Cat no : %s\n" % + metadata.catalogNumber) delta = abs(metadata.duration - ittoc.duration()) - if not delta in deltas: + if delta not in deltas: deltas[delta] = [] deltas[delta].append(metadata) @@ -352,7 +353,8 @@ class Program: if prompt: guess = (deltas[lowest])[0].mbid - release = raw_input("\nPlease select a release [%s]: " % guess) + release = raw_input( + "\nPlease select a release [%s]: " % guess) if not release: release = guess @@ -360,15 +362,15 @@ class Program: if release: metadatas = [m for m in metadatas if m.url.endswith(release)] logger.debug('Asked for release %r, only kept %r', - release, metadatas) + release, metadatas) if len(metadatas) == 1: self._stdout.write('\n') self._stdout.write('Picked requested release id %s\n' % - release) + release) self._stdout.write('Artist : %s\n' % - metadatas[0].artist.encode('utf-8')) + metadatas[0].artist.encode('utf-8')) self._stdout.write('Title : %s\n' % - metadatas[0].title.encode('utf-8')) + metadatas[0].title.encode('utf-8')) elif not metadatas: self._stdout.write( "Requested release id '%s', " @@ -385,22 +387,23 @@ class Program: for i, metadata in enumerate(metadatas): if not artist == metadata.artist: logger.warning("artist 0: %r and artist %d: %r " - "are not the same" % ( - artist, i, metadata.artist)) + "are not the same" % ( + artist, i, metadata.artist)) if not releaseTitle == metadata.releaseTitle: logger.warning("title 0: %r and title %d: %r " - "are not the same" % ( - releaseTitle, i, metadata.releaseTitle)) + "are not the same" % ( + releaseTitle, i, + metadata.releaseTitle)) if (not release and len(deltas.keys()) > 1): self._stdout.write('\n') self._stdout.write('Picked closest match in duration.\n') self._stdout.write('Others may be wrong in MusicBrainz, ' - 'please correct.\n') + 'please correct.\n') self._stdout.write('Artist : %s\n' % - artist.encode('utf-8')) + artist.encode('utf-8')) self._stdout.write('Title : %s\n' % - metadatas[0].title.encode('utf-8')) + metadatas[0].title.encode('utf-8')) # Select one of the returned releases. We just pick the first one. ret = metadatas[0] @@ -503,12 +506,13 @@ class Program: raise ret = trackResult.testcrc == t.checksum - logger.debug('verifyTrack: track result crc %r, file crc %r, result %r', + logger.debug('verifyTrack: track result crc %r, ' + 'file crc %r, result %r', trackResult.testcrc, t.checksum, ret) return ret def ripTrack(self, runner, trackResult, offset, device, taglist, - overread, what=None): + overread, what=None): """ Ripping the track may change the track's filename as stored in trackResult. @@ -527,14 +531,15 @@ class Program: os.makedirs(dirname) if not what: - what='track %d' % (trackResult.number, ) + what = 'track %d' % (trackResult.number, ) t = cdparanoia.ReadVerifyTrackTask(trackResult.filename, - self.result.table, start, stop, overread, - offset=offset, - device=device, - taglist=taglist, - what=what) + self.result.table, start, + stop, overread, + offset=offset, + device=device, + taglist=taglist, + what=what) runner.run(t) @@ -571,7 +576,7 @@ class Program: """ logger.debug('verifying Image against %d AccurateRip responses', - len(responses or [])) + len(responses or [])) cueImage = image.Image(self.cuePath) verifytask = image.ImageVerifyTask(cueImage) @@ -587,7 +592,6 @@ class Program: trackResult = self.result.getTrackResult(i + 1) trackResult.ARCRC = csum - if not responses: logger.warning('No AccurateRip responses, cannot verify.') return @@ -615,8 +619,8 @@ class Program: trackResult.ARDBConfidence = confidence if not trackResult.accurip: - logger.warning("Track %02d: not matched in AccurateRip database", - i + 1) + logger.warning("Track %02d: not matched in " + "AccurateRip database", i + 1) # I have seen AccurateRip responses with 0 as confidence # for example, Best of Luke Haines, disc 1, track 1 @@ -632,7 +636,7 @@ class Program: trackResult.ARDBMaxConfidence = maxConfidence if not response: logger.warning('Track %02d: none of the responses matched.', - i + 1) + i + 1) trackResult.ARDBCRC = int( maxResponse.checksums[i], 16) else: @@ -650,7 +654,7 @@ class Program: status = 'rip NOT accurate' if trackResult.accurip: - status = 'rip accurate ' + status = 'rip accurate ' c = "(not found) " ar = ", DB [notfound]" @@ -668,7 +672,7 @@ class Program: if trackResult.ARCRC is None: assert trackResult.number == 0, \ 'no trackResult.ARCRC on non-HTOA track %d' % \ - trackResult.number + trackResult.number res.append("Track 0: unknown (not tracked)") else: res.append("Track %2d: %s %s [%08x]%s" % ( diff --git a/whipper/common/renamer.py b/whipper/common/renamer.py index c71a136..8db09a4 100644 --- a/whipper/common/renamer.py +++ b/whipper/common/renamer.py @@ -56,7 +56,6 @@ class Operator(object): operation = cls.deserialize(data) self._todo.append(operation) - done = os.path.join(self._statePath, self._key + '.done') if os.path.exists(done): with open(done, 'r') as handle: diff --git a/whipper/common/task.py b/whipper/common/task.py index 8312a08..50766b0 100644 --- a/whipper/common/task.py +++ b/whipper/common/task.py @@ -39,9 +39,11 @@ class PopenTask(task.Task): try: self._popen = asyncsub.Popen(self.command, - bufsize=self.bufsize, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, close_fds=True, cwd=self.cwd) + bufsize=self.bufsize, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True, cwd=self.cwd) except OSError, e: import errno if e.errno == errno.ENOENT: @@ -50,7 +52,7 @@ class PopenTask(task.Task): raise logger.debug('Started %r with pid %d', self.command, - self._popen.pid) + self._popen.pid) self.schedule(1.0, self._read, runner) @@ -92,23 +94,23 @@ class PopenTask(task.Task): self.stop() def _done(self): - assert self._popen.returncode is not None, "No returncode" + assert self._popen.returncode is not None, "No returncode" - if self._popen.returncode >= 0: - logger.debug('Return code was %d', self._popen.returncode) - else: - logger.debug('Terminated with signal %d', - -self._popen.returncode) + if self._popen.returncode >= 0: + logger.debug('Return code was %d', self._popen.returncode) + else: + logger.debug('Terminated with signal %d', + -self._popen.returncode) - self.setProgress(1.0) + self.setProgress(1.0) - if self._popen.returncode != 0: - self.failed() - else: - self.done() + if self._popen.returncode != 0: + self.failed() + else: + self.done() - self.stop() - return + self.stop() + return def abort(self): logger.debug('Aborting, sending SIGTERM to %d', self._popen.pid) @@ -139,7 +141,6 @@ class PopenTask(task.Task): """ pass - def commandMissing(self): """ Called when the command is missing. diff --git a/whipper/extern/asyncsub.py b/whipper/extern/asyncsub.py index bb7f372..6587f54 100644 --- a/whipper/extern/asyncsub.py +++ b/whipper/extern/asyncsub.py @@ -95,7 +95,7 @@ class Popen(subprocess.Popen): try: written = os.write(self.stdin.fileno(), input) except OSError, why: - if why[0] == errno.EPIPE: #broken pipe + if why[0] == errno.EPIPE: # broken pipe return self._close('stdin') raise @@ -108,7 +108,7 @@ class Popen(subprocess.Popen): flags = fcntl.fcntl(conn, fcntl.F_GETFL) if not conn.closed: - fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK) + fcntl.fcntl(conn, fcntl.F_SETFL, flags | os.O_NONBLOCK) try: if not select.select([conn], [], [], 0)[0]: @@ -125,13 +125,14 @@ class Popen(subprocess.Popen): if not conn.closed: fcntl.fcntl(conn, fcntl.F_SETFL, flags) + message = "Other end disconnected!" def recv_some(p, t=.1, e=1, tr=5, stderr=0): if tr < 1: tr = 1 - x = time.time()+t + x = time.time() + t y = [] r = '' pr = p.recv @@ -147,7 +148,7 @@ def recv_some(p, t=.1, e=1, tr=5, stderr=0): elif r: y.append(r) else: - time.sleep(max((x-time.time())/tr, 0)) + time.sleep(max((x - time.time()) / tr, 0)) return ''.join(y) @@ -158,6 +159,7 @@ def send_all(p, data): raise Exception(message) data = buffer(data, sent) + if __name__ == '__main__': if sys.platform == 'win32': shell, commands, tail = ('cmd', ('dir /w', 'echo HELLO WORLD'), '\r\n') diff --git a/whipper/extern/task/task.py b/whipper/extern/task/task.py index 10bbac5..9c40dd5 100644 --- a/whipper/extern/task/task.py +++ b/whipper/extern/task/task.py @@ -22,12 +22,13 @@ import sys import gobject + class TaskException(Exception): """ I wrap an exception that happened during task execution. """ - exception = None # original exception + exception = None # original exception def __init__(self, exception, message=None): self.exception = exception @@ -35,6 +36,8 @@ class TaskException(Exception): self.args = (exception, message, ) # lifted from flumotion log module + + def _getExceptionMessage(exception, frame=-1, filename=None): """ Return a short message based on an exception, useful for debugging. @@ -67,7 +70,7 @@ class LogStub(object): I am a stub for a log interface. """ - ### log stubs + # log stubs def log(self, message, *args): pass @@ -112,8 +115,7 @@ class Task(LogStub): _listeners = None - - ### subclass methods + # subclass methods def start(self, runner): """ Start the task. @@ -149,18 +151,20 @@ class Task(LogStub): self.running = False if not self.runner: print 'ERROR: stopping task which is already stopped' - import traceback; traceback.print_stack() + import traceback + traceback.print_stack() self.runner = None self.debug('reset runner to None') self._notifyListeners('stopped') - ### base class methods + # base class methods def setProgress(self, value): """ Notify about progress changes bigger than the increment. Called by subclass implementations as the task progresses. """ - if value - self.progress > self.increment or value >= 1.0 or value == 0.0: + if (value - self.progress > self.increment or + value >= 1.0 or value == 0.0): self.progress = value self._notifyListeners('progressed', value) self.log('notifying progress: %r on %r', value, self.description) @@ -186,8 +190,8 @@ class Task(LogStub): # for now if str(exception): msg = ": %s" % str(exception) - line = "exception %(exc)s at %(filename)s:%(line)s: %(func)s()%(msg)s" \ - % locals() + line = "exception %(exc)s at %(filename)s:%(line)s: " + "%(func)s()%(msg)s" % locals() self.exception = exception self.exceptionMessage = line @@ -211,11 +215,11 @@ class Task(LogStub): def schedule(self, delta, callable, *args, **kwargs): if not self.runner: print "ERROR: scheduling on a task that's altready stopped" - import traceback; traceback.print_stack() + import traceback + traceback.print_stack() return self.runner.schedule(self, delta, callable, *args, **kwargs) - def addListener(self, listener): """ Add a listener for task status changes. @@ -236,12 +240,14 @@ class Task(LogStub): except Exception, e: self.setException(e) + # FIXME: should this become a real interface, like in zope ? class ITaskListener(object): """ I am an interface for objects listening to tasks. """ - ### listener callbacks + # listener callbacks + def progressed(self, task, value): """ Implement me to be informed about progress. @@ -270,7 +276,6 @@ class ITaskListener(object): """ - # this is a Dummy task that can be used to test if this works at all class DummyTask(Task): def start(self, runner): @@ -286,6 +291,7 @@ class DummyTask(Task): self.schedule(1.0, self._wind) + class BaseMultiTask(Task, ITaskListener): """ I perform multiple tasks. @@ -336,20 +342,20 @@ class BaseMultiTask(Task, ITaskListener): task = self.tasks[self._task] self._task += 1 self.debug('BaseMultiTask.next(): starting task %d of %d: %r', - self._task, len(self.tasks), task) + self._task, len(self.tasks), task) self.setDescription("%s (%d of %d) ..." % ( task.description, self._task, len(self.tasks))) task.addListener(self) task.start(self.runner) self.debug('BaseMultiTask.next(): started task %d of %d: %r', - self._task, len(self.tasks), task) + self._task, len(self.tasks), task) except Exception, e: self.setException(e) self.debug('Got exception during next: %r', self.exceptionMessage) self.stop() return - ### ITaskListener methods + # ITaskListener methods def started(self, task): pass @@ -362,10 +368,10 @@ class BaseMultiTask(Task, ITaskListener): They should fall through to chaining up if there is an exception. """ self.log('BaseMultiTask.stopped: task %r (%d of %d)', - task, self.tasks.index(task) + 1, len(self.tasks)) + task, self.tasks.index(task) + 1, len(self.tasks)) if task.exception: self.log('BaseMultiTask.stopped: exception %r', - task.exceptionMessage) + task.exceptionMessage) self.exception = task.exception self.exceptionMessage = task.exceptionMessage self.stop() @@ -395,10 +401,10 @@ class MultiSeparateTask(BaseMultiTask): def next(self): self.debug('MultiSeparateTask.next()') # start next task - self.progress = 0.0 # reset progress for each task + self.progress = 0.0 # reset progress for each task BaseMultiTask.next(self) - ### ITaskListener methods + # ITaskListener methods def progressed(self, task, value): self.setProgress(value) @@ -406,6 +412,7 @@ class MultiSeparateTask(BaseMultiTask): self.setDescription("%s (%d of %d) ..." % ( description, self._task, len(self.tasks))) + class MultiCombinedTask(BaseMultiTask): """ I perform multiple tasks. @@ -415,7 +422,7 @@ class MultiCombinedTask(BaseMultiTask): description = 'Doing various tasks combined' _stopped = 0 - ### ITaskListener methods + # ITaskListener methods def progressed(self, task, value): self.setProgress(float(self._stopped + value) / len(self.tasks)) @@ -424,6 +431,7 @@ class MultiCombinedTask(BaseMultiTask): self.setProgress(float(self._stopped) / len(self.tasks)) BaseMultiTask.stopped(self, task) + class TaskRunner(LogStub): """ I am a base class for task runners. @@ -439,7 +447,7 @@ class TaskRunner(LogStub): """ raise NotImplementedError - ### methods for tasks to call + # methods for tasks to call def schedule(self, delta, callable, *args, **kwargs): """ Schedule a single future call. @@ -456,9 +464,10 @@ class SyncRunner(TaskRunner, ITaskListener): """ I run the task synchronously in a gobject MainLoop. """ + def __init__(self, verbose=True): self._verbose = verbose - self._longest = 0 # longest string shown; for clearing + self._longest = 0 # longest string shown; for clearing def run(self, task, verbose=None, skip=False): self.debug('run task %r', task) @@ -500,26 +509,25 @@ class SyncRunner(TaskRunner, ITaskListener): self.debug('exception during start: %r', task.exceptionMessage) self.stopped(task) - def schedule(self, task, delta, callable, *args, **kwargs): def c(): try: self.log('schedule: calling %r(*args=%r, **kwargs=%r)', - callable, args, kwargs) + callable, args, kwargs) callable(*args, **kwargs) return False except Exception, e: self.debug('exception when calling scheduled callable %r', - callable) + callable) task.setException(e) self.stopped(task) raise self.log('schedule: scheduling %r(*args=%r, **kwargs=%r)', - callable, args, kwargs) + callable, args, kwargs) gobject.timeout_add(int(delta * 1000L), c) - ### ITaskListener methods + # ITaskListener methods def progressed(self, task, value): if not self._verboseRun: return @@ -558,6 +566,7 @@ class SyncRunner(TaskRunner, ITaskListener): self._output('%s %3d %%' % ( self._task.description, self._task.progress * 100.0)) + if __name__ == '__main__': task = DummyTask() runner = SyncRunner() diff --git a/whipper/image/cue.py b/whipper/image/cue.py index 31fd0ec..24a1e52 100644 --- a/whipper/image/cue.py +++ b/whipper/image/cue.py @@ -142,11 +142,12 @@ class CueFile(object): + minutes * common.FRAMES_PER_SECOND * 60 logger.debug('found index %d of track %r in %r:%d', - indexNumber, currentTrack, currentFile.path, frameOffset) + indexNumber, currentTrack, currentFile.path, + frameOffset) # FIXME: what do we do about File's FORMAT ? currentTrack.index(indexNumber, - path=currentFile.path, relative=frameOffset, - counter=counter) + path=currentFile.path, relative=frameOffset, + counter=counter) continue def message(self, number, message): @@ -166,8 +167,8 @@ class CueFile(object): # last track, so no length known return -1 - thisIndex = track.indexes[1] # FIXME: could be more - nextIndex = self.table.tracks[i + 1].indexes[1] # FIXME: could be 0 + thisIndex = track.indexes[1] # FIXME: could be more + nextIndex = self.table.tracks[i + 1].indexes[1] # FIXME: could be 0 c = thisIndex.counter if c is not None and c == nextIndex.counter: diff --git a/whipper/image/image.py b/whipper/image/image.py index 815d69f..dfa7d66 100644 --- a/whipper/image/image.py +++ b/whipper/image/image.py @@ -52,8 +52,8 @@ class Image(object): self._path = path self.cue = cue.CueFile(path) self.cue.parse() - self._offsets = [] # 0 .. trackCount - 1 - self._lengths = [] # 0 .. trackCount - 1 + self._offsets = [] # 0 .. trackCount - 1 + self._lengths = [] # 0 .. trackCount - 1 self.table = None @@ -98,8 +98,8 @@ class Image(object): # FIXME: this probably only works for non-compliant .CUE files # where pregap is put at end of previous file t.index(1, absolute=offset, - path=self.cue.table.tracks[i].getIndex(1).path, - relative=0) + path=self.cue.table.tracks[i].getIndex(1).path, + relative=0) offset += length @@ -128,17 +128,19 @@ class AccurateRipChecksumTask(task.MultiSeparateTask): index = track.indexes[1] length = cue.getTrackLength(track) if length < 0: - logger.debug('track %d has unknown length' % (trackIndex + 1, )) + logger.debug('track %d has unknown length' % + (trackIndex + 1, )) else: logger.debug('track %d is %d samples long' % ( trackIndex + 1, length)) path = image.getRealPath(index.path) - - checksumTask = checksum.FastAccurateRipChecksumTask(path, - trackNumber=trackIndex + 1, trackCount=len(cue.table.tracks), - wave=True, v2=False) + checksumTask = checksum.FastAccurateRipChecksumTask( + path, + trackNumber=trackIndex + 1, + trackCount=len(cue.table.tracks), + wave=True, v2=False) self.addTask(checksumTask) @@ -201,8 +203,9 @@ class ImageVerifyTask(task.MultiSeparateTask): break if taskk.length is None: - raise ValueError("Track length was not found; look for " - "earlier errors in debug log (set RIP_DEBUG=4)") + raise ValueError("Track length was not found; " + "look for earlier errors " + "in debug log (set RIP_DEBUG=4)") index = track.indexes[1] assert taskk.length % common.SAMPLES_PER_FRAME == 0 end = taskk.length / common.SAMPLES_PER_FRAME @@ -234,8 +237,9 @@ class ImageEncodeTask(task.MultiSeparateTask): root, ext = os.path.splitext(os.path.basename(path)) outpath = os.path.join(outdir, root + '.' + 'flac') logger.debug('schedule encode to %r', outpath) - taskk = encode.FlacEncodeTask(path, os.path.join(outdir, - root + '.' + 'flac')) + taskk = encode.FlacEncodeTask(path, + os.path.join(outdir, + root + '.' + 'flac')) self.addTask(taskk) try: diff --git a/whipper/image/table.py b/whipper/image/table.py index 2a2bfbb..3c8cd4f 100644 --- a/whipper/image/table.py +++ b/whipper/image/table.py @@ -169,9 +169,9 @@ class Table(object): @type cdtext: dict of str -> str """ - tracks = None # list of Track - leadout = None # offset where the leadout starts - catalog = None # catalog number; FIXME: is this UPC ? + tracks = None # list of Track + leadout = None # offset where the leadout starts + catalog = None # catalog number; FIXME: is this UPC ? cdtext = None mbdiscid = None @@ -305,7 +305,7 @@ class Table(object): # duration = durationFrames / common.FRAMES_PER_SECOND # assert t == duration, "%r != %r" % (t, duration) - debug.append(str(leadoutSeconds + 2)) # 2 is the 150 frame cddb offset + debug.append(str(leadoutSeconds + 2)) # 2 is the 150 frame cddb offset result.append(leadoutSeconds) value = (n % 0xff) << 24 | t << 8 | len(self.tracks) @@ -315,7 +315,7 @@ class Table(object): logger.debug('cddb values: %r', result) logger.debug('cddb disc id debug: %s', - " ".join(["%08x" % value, ] + debug)) + " ".join(["%08x" % value, ] + debug)) return result @@ -472,7 +472,6 @@ class Table(object): except IndexError: pass - logger.debug('MusicBrainz values: %r', result) return result @@ -545,8 +544,8 @@ class Table(object): main = ['PERFORMER', 'TITLE'] for key in CDTEXT_FIELDS: - if key not in main and key in self.cdtext: - lines.append(" %s %s" % (key, self.cdtext[key])) + if key not in main and key in self.cdtext: + lines.append(" %s %s" % (key, self.cdtext[key])) assert self.hasTOC(), "Table does not represent a full CD TOC" lines.append('REM DISCID %s' % self.getCDDBDiscId().upper()) @@ -607,7 +606,7 @@ class Table(object): logger.debug('counter %d, writeFile' % counter) writeFile(index.path) logger.debug('setting counter to index.counter %r' % - index.counter) + index.counter) counter = index.counter # any time we hit the first index, write a TRACK statement @@ -636,23 +635,25 @@ class Table(object): if not index00.path: length = indexOne.absolute - index00.absolute lines.append(" PREGAP %s" % - common.framesToMSF(length)) + common.framesToMSF(length)) continue # handle any other INDEX 00 after its TRACK - lines.append(" INDEX %02d %s" % (0, - common.framesToMSF(index00.relative))) + lines.append(" INDEX " + "%02d %s" % (0, common.framesToMSF( + index00.relative))) if number > 0: # index 00 is output after TRACK up above lines.append(" INDEX %02d %s" % (number, - common.framesToMSF(index.relative))) + common.framesToMSF( + index.relative))) lines.append("") return "\n".join(lines) - ### methods that modify the table + # methods that modify the table def clearFiles(self): """ @@ -689,13 +690,14 @@ class Table(object): @type index: C{int} """ logger.debug('setFile: track %d, index %d, path %r, ' - 'length %r, counter %r', track, index, path, length, counter) + 'length %r, counter %r', track, index, path, length, + counter) t = self.tracks[track - 1] i = t.indexes[index] start = i.absolute assert start is not None, "index %r is missing absolute offset" % i - end = start + length - 1 # last sector that should come from this file + end = start + length - 1 # last sector that should come from this file # FIXME: check border conditions here, esp. wrt. toc's off-by-one bug while i.absolute <= end: @@ -703,8 +705,8 @@ class Table(object): i.relative = i.absolute - start i.counter = counter logger.debug('Setting path %r, relative %r on ' - 'track %d, index %d, counter %r', - path, i.relative, track, index, counter) + 'track %d, index %d, counter %r', + path, i.relative, track, index, counter) try: track, index = self.getNextTrackIndex(track, index) t = self.tracks[track - 1] @@ -733,10 +735,11 @@ class Table(object): logger.debug('Track %d, index %d has no counter', t, i) break if index.counter != counter: - logger.debug('Track %d, index %d has a different counter', t, i) + logger.debug( + 'Track %d, index %d has a different counter', t, i) break logger.debug('Setting absolute offset %d on track %d, index %d', - index.relative, t, i) + index.relative, t, i) if index.absolute is not None: if index.absolute != index.relative: msg = 'Track %d, index %d had absolute %d,' \ @@ -769,15 +772,17 @@ class Table(object): for i in t.indexes.values(): if i.absolute is not None: i.absolute += self.leadout + gap - logger.debug('Fixing track %02d, index %02d, absolute %d' % ( - t.number, i.number, i.absolute)) + logger.debug('Fixing track %02d, index %02d, ' + 'absolute %d' % ( + t.number, i.number, i.absolute)) if i.counter is not None: i.counter += sourceCounter - logger.debug('Fixing track %02d, index %02d, counter %d' % ( - t.number, i.number, i.counter)) + logger.debug('Fixing track %02d, index %02d, ' + 'counter %d' % ( + t.number, i.number, i.counter)) self.tracks.append(t) - self.leadout += other.leadout + gap # FIXME + self.leadout += other.leadout + gap # FIXME logger.debug('Fixing leadout, now %d', self.leadout) def _getSessionGap(self, session): @@ -795,7 +800,7 @@ class Table(object): gap = 6900 return gap - ### lookups + # lookups def getNextTrackIndex(self, track, index): """ @@ -857,8 +862,8 @@ class Table(object): for t in self.tracks: for i in t.indexes.values(): if i.relative is None: - logger.debug('Track %02d, Index %02d does not have relative', - t.number, i.number) + logger.debug('Track %02d, Index %02d does not ' + 'have relative', t.number, i.number) return False return True diff --git a/whipper/image/toc.py b/whipper/image/toc.py index 9411a21..aaf77ba 100644 --- a/whipper/image/toc.py +++ b/whipper/image/toc.py @@ -109,8 +109,8 @@ class Sources: @type counter: int @param offset: the absolute disc offset where this source starts """ - logger.debug('Appending source, counter %d, abs offset %d, source %r' % ( - counter, offset, source)) + logger.debug('Appending source, counter %d, abs offset %d, ' + 'source %r' % (counter, offset, source)) self._sources.append((counter, offset, source)) def get(self, offset): @@ -158,33 +158,34 @@ class TocFile(object): relative = absolute - counterStart currentTrack.index(i, path=s.path, - absolute=absolute, - relative=relative, - counter=c) + absolute=absolute, + relative=relative, + counter=c) logger.debug( '[track %02d index %02d] trackOffset %r, added %r', - currentTrack.number, i, trackOffset, - currentTrack.getIndex(i)) - + currentTrack.number, i, trackOffset, + currentTrack.getIndex(i)) def parse(self): - # these two objects start as None then get set as real objects, - # so no need to complain about them here - __pychecker__ = 'no-objattrs' currentFile = None currentTrack = None state = 'HEADER' - counter = 0 # counts sources for audio data; SILENCE/ZERO/FILE + # counts sources for audio data; SILENCE/ZERO/FILE + counter = 0 trackNumber = 0 indexNumber = 0 - absoluteOffset = 0 # running absolute offset of where each track starts - relativeOffset = 0 # running relative offset, relative to counter src - currentLength = 0 # accrued during TRACK record parsing; - # length of current track as parsed so far; - # reset on each TRACK statement - totalLength = 0 # accrued during TRACK record parsing, total disc - pregapLength = 0 # length of the pre-gap, current track in for loop + # running absolute offset: where each track starts + absoluteOffset = 0 + # running relative offset, relative to counter src + relativeOffset = 0 + # currentLength is accrued during TRACK record parsing length + # of current track as parsed so far reset on each TRACK statement + currentLength = 0 + # accrued during TRACK record parsing, total disc + totalLength = 0 + # length of the pre-gap, current track in for loop + pregapLength = 0 # the first track's INDEX 1 can only be gotten from the .toc # file once the first pregap is calculated; so we add INDEX 1 @@ -211,9 +212,9 @@ class TocFile(object): logger.debug('Found disc CD-Text %s: %r', key, value) elif state == 'TRACK': if key != 'ISRC' or not currentTrack \ - or currentTrack.isrc is not None: + or currentTrack.isrc is not None: logger.debug('Found track CD-Text %s: %r', - key, value) + key, value) currentTrack.cdtext[key] = value # look for header elements @@ -246,7 +247,7 @@ class TocFile(object): # FIXME: track mode logger.debug('found track %d, mode %s, at absoluteOffset %d', - trackNumber, trackMode, absoluteOffset) + trackNumber, trackMode, absoluteOffset) # reset counters relative to a track currentLength = 0 @@ -299,18 +300,18 @@ class TocFile(object): start = m.group('start') length = m.group('length') logger.debug('FILE %s, start %r, length %r', - filePath, common.msfToFrames(start), - common.msfToFrames(length)) + filePath, common.msfToFrames(start), + common.msfToFrames(length)) if not currentFile or filePath != currentFile.path: counter += 1 relativeOffset = 0 logger.debug('track %d, switched to new FILE, ' - 'increased counter to %d', - trackNumber, counter) + 'increased counter to %d', + trackNumber, counter) currentFile = File(filePath, common.msfToFrames(start), - common.msfToFrames(length)) + common.msfToFrames(length)) self._sources.append(counter, absoluteOffset + currentLength, - currentFile) + currentFile) currentLength += common.msfToFrames(length) # look for DATAFILE lines @@ -319,20 +320,19 @@ class TocFile(object): filePath = m.group('name') length = m.group('length') logger.debug('FILE %s, length %r', - filePath, common.msfToFrames(length)) + filePath, common.msfToFrames(length)) if not currentFile or filePath != currentFile.path: counter += 1 relativeOffset = 0 logger.debug('track %d, switched to new FILE, ' - 'increased counter to %d', - trackNumber, counter) + 'increased counter to %d', + trackNumber, counter) # FIXME: assume that a MODE2_FORM_MIX track always starts at 0 currentFile = File(filePath, 0, common.msfToFrames(length)) self._sources.append(counter, absoluteOffset + currentLength, - currentFile) + currentFile) currentLength += common.msfToFrames(length) - # look for START lines m = _START_RE.search(line) if m: @@ -349,10 +349,10 @@ class TocFile(object): relativeOffset = absoluteOffset - counterStart currentTrack.index(0, path=s and s.path or None, - absolute=absoluteOffset, - relative=relativeOffset, counter=c) + absolute=absoluteOffset, + relative=relativeOffset, counter=c) logger.debug('[track %02d index 00] added %r', - currentTrack.number, currentTrack.getIndex(0)) + currentTrack.number, currentTrack.getIndex(0)) # store the pregapLength to add it when we index 1 for this # track on the next iteration pregapLength = length @@ -398,8 +398,8 @@ class TocFile(object): # last track, so no length known return -1 - thisIndex = track.indexes[1] # FIXME: could be more - nextIndex = self.table.tracks[i + 1].indexes[1] # FIXME: could be 0 + thisIndex = track.indexes[1] # FIXME: could be more + nextIndex = self.table.tracks[i + 1].indexes[1] # FIXME: could be 0 c = thisIndex.counter if c is not None and c == nextIndex.counter: diff --git a/whipper/program/arc.py b/whipper/program/arc.py index 1473fd2..02ba866 100644 --- a/whipper/program/arc.py +++ b/whipper/program/arc.py @@ -1,4 +1,3 @@ -from os.path import exists from subprocess import Popen, PIPE import logging @@ -7,6 +6,7 @@ logger = logging.getLogger(__name__) ARB = 'accuraterip-checksum' FLAC = 'flac' + def accuraterip_checksum(f, track, tracks, wave=False, v2=False): v = '--accuraterip-v1' if v2: diff --git a/whipper/program/cdparanoia.py b/whipper/program/cdparanoia.py index 6fabefb..1be6bcb 100644 --- a/whipper/program/cdparanoia.py +++ b/whipper/program/cdparanoia.py @@ -79,12 +79,12 @@ _ERROR_RE = re.compile("^scsi_read error:") class ProgressParser: - read = 0 # last [read] frame - wrote = 0 # last [wrote] frame - errors = 0 # count of number of scsi errors - _nframes = None # number of frames read on each [read] - _firstFrames = None # number of frames read on first [read] - reads = 0 # total number of reads + read = 0 # last [read] frame + wrote = 0 # last [wrote] frame + errors = 0 # count of number of scsi errors + _nframes = None # number of frames read on each [read] + _firstFrames = None # number of frames read on first [read] + reads = 0 # total number of reads def __init__(self, start, stop): """ @@ -99,7 +99,7 @@ class ProgressParser: # FIXME: privatize self.read = start - self._reads = {} # read count for each sector + self._reads = {} # read count for each sector def parse(self, line): """ @@ -121,8 +121,7 @@ class ProgressParser: def _parse_read(self, wordOffset): if wordOffset % common.WORDS_PER_FRAME != 0: - logger.debug( - 'THOMAS: not a multiple of %d: %d' % ( + logger.debug('THOMAS: not a multiple of %d: %d' % ( common.WORDS_PER_FRAME, wordOffset)) return @@ -139,7 +138,7 @@ class ProgressParser: logger.debug('set firstFrames to %r', self._firstFrames) markStart = None - markEnd = None # the next unread frame (half-inclusive) + markEnd = None # the next unread frame (half-inclusive) # verify it either read nframes more or went back for verify if frameOffset > self.read: @@ -156,13 +155,13 @@ class ProgressParser: # we could use firstFrames as an estimate on how many frames this # read, but this lowers our track quality needlessly where # EAC still reports 100% track quality - markStart = frameOffset # - self._firstFrames + markStart = frameOffset # - self._firstFrames markEnd = frameOffset # FIXME: doing this is way too slow even for a testcase, so disable if False: for frame in range(markStart, markEnd): - if not frame in self._reads.keys(): + if frame not in self._reads.keys(): self._reads[frame] = 0 self._reads[frame] += 1 @@ -189,7 +188,7 @@ class ProgressParser: Each frame gets read twice. More than two reads for a frame reduce track quality. """ - frames = self.stop - self.start + 1 # + 1 since stop is inclusive + frames = self.stop - self.start + 1 # + 1 since stop is inclusive reads = self.reads logger.debug('getTrackQuality: frames %d, reads %d' % (frames, reads)) @@ -209,14 +208,14 @@ class ReadTrackTask(task.Task): """ description = "Reading track" - quality = None # set at end of reading + quality = None # set at end of reading speed = None - duration = None # in seconds + duration = None # in seconds - _MAXERROR = 100 # number of errors detected by parser + _MAXERROR = 100 # number of errors detected by parser def __init__(self, path, table, start, stop, overread, offset=0, - device=None, action="Reading", what="track"): + device=None, action="Reading", what="track"): """ Read the given track. @@ -249,7 +248,7 @@ class ReadTrackTask(task.Task): self._start_time = None self._overread = overread - self._buffer = "" # accumulate characters + self._buffer = "" # accumulate characters self._errors = [] self.description = "%s %s" % (action, what) @@ -271,31 +270,33 @@ class ReadTrackTask(task.Task): stopOffset = self._stop - self._table.getTrackStart(i + 1) logger.debug('Ripping from %d to %d (inclusive)', - self._start, self._stop) + self._start, self._stop) logger.debug('Starting at track %d, offset %d', - startTrack, startOffset) + startTrack, startOffset) logger.debug('Stopping at track %d, offset %d', - stopTrack, stopOffset) + stopTrack, stopOffset) bufsize = 1024 if self._overread: argv = ["cdparanoia", "--stderr-progress", - "--sample-offset=%d" % self._offset, "--force-overread", ] + "--sample-offset=%d" % self._offset, "--force-overread", ] else: argv = ["cdparanoia", "--stderr-progress", - "--sample-offset=%d" % self._offset, ] + "--sample-offset=%d" % self._offset, ] if self._device: argv.extend(["--force-cdrom-device", self._device, ]) argv.extend(["%d[%s]-%d[%s]" % ( - startTrack, common.framesToHMSF(startOffset), - stopTrack, common.framesToHMSF(stopOffset)), + startTrack, common.framesToHMSF(startOffset), + stopTrack, common.framesToHMSF(stopOffset)), self.path]) logger.debug('Running %s' % (" ".join(argv), )) try: self._popen = asyncsub.Popen(argv, - bufsize=bufsize, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, close_fds=True) + bufsize=bufsize, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True) except OSError, e: import errno if e.errno == errno.ENOENT: @@ -366,7 +367,7 @@ class ReadTrackTask(task.Task): if size != expected: # FIXME: handle errors better logger.warning('file size %d did not match expected size %d', - size, expected) + size, expected) if (size - expected) % common.BYTES_PER_FRAME == 0: logger.warning('%d frames difference' % ( (size - expected) / common.BYTES_PER_FRAME)) @@ -374,8 +375,10 @@ class ReadTrackTask(task.Task): logger.warning('non-integral amount of frames difference') self.setAndRaiseException(FileSizeError(self.path, - "File size %d did not match expected size %d" % ( - size, expected))) + "File size %d did not " + "match expected " + "size %d" % ( + size, expected))) if not self.exception and self._popen.returncode != 0: if self._errors: @@ -461,10 +464,11 @@ class ReadVerifyTrackTask(task.MultiSeparateTask): self.tasks = [] self.tasks.append( ReadTrackTask(tmppath, table, start, stop, overread, - offset=offset, device=device, what=what)) + offset=offset, device=device, what=what)) self.tasks.append(checksum.CRC32Task(tmppath)) t = ReadTrackTask(tmppath, table, start, stop, overread, - offset=offset, device=device, action="Verifying", what=what) + offset=offset, device=device, action="Verifying", + what=what) self.tasks.append(t) self.tasks.append(checksum.CRC32Task(tmppath)) @@ -503,7 +507,7 @@ class ReadVerifyTrackTask(task.MultiSeparateTask): try: if not self.exception: self.quality = max(self.tasks[0].quality, - self.tasks[2].quality) + self.tasks[2].quality) self.peak = self.tasks[6].peak logger.debug('peak: %r', self.peak) self.testspeed = self.tasks[0].speed @@ -535,9 +539,8 @@ class ReadVerifyTrackTask(task.MultiSeparateTask): logger.debug('Moving to final path %r', self.path) os.rename(self._tmppath, self.path) except Exception, e: - logger.debug('Exception while moving to final path %r: ' - '%r', - self.path, str(e)) + logger.debug('Exception while moving to final ' + 'path %r: %r', self.path, str(e)) self.exception = e else: os.unlink(self._tmppath) @@ -548,15 +551,16 @@ class ReadVerifyTrackTask(task.MultiSeparateTask): task.MultiSeparateTask.stop(self) + _VERSION_RE = re.compile( "^cdparanoia (?P.+) release (?P.+) \(.*\)") def getCdParanoiaVersion(): getter = common.VersionGetter('cdparanoia', - ["cdparanoia", "-V"], - _VERSION_RE, - "%(version)s %(release)s") + ["cdparanoia", "-V"], + _VERSION_RE, + "%(version)s %(release)s") return getter.get() diff --git a/whipper/program/cdrdao.py b/whipper/program/cdrdao.py index 037588f..ffab516 100644 --- a/whipper/program/cdrdao.py +++ b/whipper/program/cdrdao.py @@ -11,6 +11,7 @@ logger = logging.getLogger(__name__) CDRDAO = 'cdrdao' + def read_toc(device, fast_toc=False): """ Return cdrdao-generated table of contents for 'device'. @@ -26,7 +27,7 @@ def read_toc(device, fast_toc=False): os.unlink(tocfile) cmd = [CDRDAO, 'read-toc'] + (['--fast-toc'] if fast_toc else []) + [ - '--device', device, tocfile] + '--device', device, tocfile] # PIPE is the closest to >/dev/null we can get logger.debug("executing %r", cmd) p = Popen(cmd, stdout=PIPE, stderr=PIPE) @@ -45,6 +46,7 @@ def read_toc(device, fast_toc=False): os.unlink(tocfile) return toc + def version(): """ Return cdrdao version as a string. @@ -56,25 +58,28 @@ def version(): "return code is " + str(cdrdao.returncode)) return None m = re.compile(r'^Cdrdao version (?P.*) - \(C\)').search( - err.decode('utf-8')) + err.decode('utf-8')) if not m: logger.warning("cdrdao version detection failed: " "could not find version") return None return m.group('version') + def ReadTOCTask(device): """ stopgap morituri-insanity compatibility layer """ return read_toc(device, fast_toc=True) + def ReadTableTask(device): """ stopgap morituri-insanity compatibility layer """ return read_toc(device) + def getCDRDAOVersion(): """ stopgap morituri-insanity compatibility layer diff --git a/whipper/program/flac.py b/whipper/program/flac.py index 1db961d..0f38839 100644 --- a/whipper/program/flac.py +++ b/whipper/program/flac.py @@ -3,6 +3,7 @@ from subprocess import check_call, CalledProcessError import logging logger = logging.getLogger(__name__) + def encode(infile, outfile): """ Encodes infile to outfile, with flac. diff --git a/whipper/program/sox.py b/whipper/program/sox.py index c8efa28..3956ec3 100644 --- a/whipper/program/sox.py +++ b/whipper/program/sox.py @@ -6,6 +6,7 @@ logger = logging.getLogger(__name__) SOX = 'sox' + def peak_level(track_path): """ Accepts a path to a sox-decodable audio file. diff --git a/whipper/program/soxi.py b/whipper/program/soxi.py index 650e144..567b266 100644 --- a/whipper/program/soxi.py +++ b/whipper/program/soxi.py @@ -8,6 +8,7 @@ logger = logging.getLogger(__name__) SOXI = 'soxi' + class AudioLengthTask(ctask.PopenTask): """ I calculate the length of a track in audio samples. @@ -41,7 +42,7 @@ class AudioLengthTask(ctask.PopenTask): self._error.append(bytes) def failed(self): - self.setException(Exception("soxi failed: %s"%"".join(self._error))) + self.setException(Exception("soxi failed: %s" % "".join(self._error))) def done(self): if self._error: diff --git a/whipper/result/logger.py b/whipper/result/logger.py index 9adfebf..6ab9f55 100644 --- a/whipper/result/logger.py +++ b/whipper/result/logger.py @@ -131,7 +131,7 @@ class WhipperLogger(result.Logger): accurateTracks = nonHTOA - self._accuratelyRipped lines.append("%s Some tracks could not be verified as " "accurate (%d/%d got no match)" % ( - arHeading, accurateTracks, nonHTOA)) + arHeading, accurateTracks, nonHTOA)) else: lines.append("%s All tracks accurately ripped" % arHeading) diff --git a/whipper/result/result.py b/whipper/result/result.py index 0c12874..2bae046 100644 --- a/whipper/result/result.py +++ b/whipper/result/result.py @@ -54,7 +54,7 @@ class TrackResult: """ number = None filename = None - pregap = 0 # in frames + pregap = 0 # in frames pre_emphasis = None peak = 0.0 @@ -65,7 +65,7 @@ class TrackResult: copyduration = 0.0 testcrc = None copycrc = None - accurip = False # whether it's in the database + accurip = False # whether it's in the database ARCRC = None ARDBCRC = None ARDBConfidence = None diff --git a/whipper/test/common.py b/whipper/test/common.py index fb0833f..1c3ef20 100644 --- a/whipper/test/common.py +++ b/whipper/test/common.py @@ -53,12 +53,12 @@ class TestCase(unittest.TestCase): return inst except exception, e: raise Exception('%s raised instead of %s:\n %s' % - (sys.exec_info()[0], exception.__name__, str(e)) - ) + (sys.exec_info()[0], exception.__name__, str(e)) + ) else: raise Exception('%s not raised (%r returned)' % - (exception.__name__, result) - ) + (exception.__name__, result) + ) assertRaises = failUnlessRaises @@ -67,8 +67,8 @@ class TestCase(unittest.TestCase): Read a .cue file, and replace the version comment with the current version so we can use it in comparisons. """ - ret = open(os.path.join(os.path.dirname(__file__), name)).read( - ).decode('utf-8') + cuefile = os.path.join(os.path.dirname(__file__), name) + ret = open(cuefile).read().decode('utf-8') ret = re.sub( 'REM COMMENT "whipper.*', 'REM COMMENT "whipper %s"' % (whipper.__version__), @@ -76,6 +76,7 @@ class TestCase(unittest.TestCase): return ret + class UnicodeTestMixin: # A helper mixin to skip tests if we're not in a UTF-8 locale diff --git a/whipper/test/test_common_accurip.py b/whipper/test/test_common_accurip.py index a61daae..9affb5b 100644 --- a/whipper/test/test_common_accurip.py +++ b/whipper/test/test_common_accurip.py @@ -12,13 +12,12 @@ class AccurateRipResponseTestCase(tcommon.TestCase): def testResponse(self): path = os.path.join(os.path.dirname(__file__), - 'dBAR-011-0010e284-009228a3-9809ff0b.bin') + 'dBAR-011-0010e284-009228a3-9809ff0b.bin') data = open(path, "rb").read() responses = accurip.getAccurateRipResponses(data) self.assertEquals(len(responses), 3) - response = responses[0] self.assertEquals(response.trackCount, 11) diff --git a/whipper/test/test_common_common.py b/whipper/test/test_common_common.py index 91fc668..a74443d 100644 --- a/whipper/test/test_common_common.py +++ b/whipper/test/test_common_common.py @@ -13,12 +13,12 @@ class ShrinkTestCase(tcommon.TestCase): def testSufjan(self): path = (u'whipper/Sufjan Stevens - Illinois/02. Sufjan Stevens - ' - 'The Black Hawk War, or, How to Demolish an Entire ' - 'Civilization and Still Feel Good About Yourself in the ' - 'Morning, or, We Apologize for the Inconvenience but ' - 'You\'re Going to Have to Leave Now, or, "I Have Fought ' - 'the Big Knives and Will Continue to Fight Them Until They ' - 'Are Off Our Lands!".flac') + 'The Black Hawk War, or, How to Demolish an Entire ' + 'Civilization and Still Feel Good About Yourself in the ' + 'Morning, or, We Apologize for the Inconvenience but ' + 'You\'re Going to Have to Leave Now, or, "I Have Fought ' + 'the Big Knives and Will Continue to Fight Them Until They ' + 'Are Off Our Lands!".flac') shorter = common.shrinkPath(path) self.failUnless(os.path.splitext(path)[0].startswith( @@ -46,7 +46,7 @@ class GetRelativePathTestCase(tcommon.TestCase): track = './' + directory + '/01. Placebo - Taste in Men.flac' self.assertEquals(common.getRelativePath(track, cue), - '01. Placebo - Taste in Men.flac') + '01. Placebo - Taste in Men.flac') class GetRealPathTestCase(tcommon.TestCase): @@ -56,12 +56,12 @@ class GetRealPathTestCase(tcommon.TestCase): refPath = os.path.join(os.path.dirname(path), 'fake.cue') self.assertEquals(common.getRealPath(refPath, path), - path) + path) # same path, but with wav extension, will point to flac file wavPath = path[:-4] + 'wav' self.assertEquals(common.getRealPath(refPath, wavPath), - path) + path) os.close(fd) os.unlink(path) diff --git a/whipper/test/test_common_config.py b/whipper/test/test_common_config.py index 0a0d384..26035fb 100644 --- a/whipper/test/test_common_config.py +++ b/whipper/test/test_common_config.py @@ -20,24 +20,24 @@ class ConfigTestCase(tcommon.TestCase): os.unlink(self._path) def testAddReadOffset(self): - self.assertRaises(KeyError, - self._config.getReadOffset, 'PLEXTOR ', 'DVDR PX-L890SA', '1.05') + self.assertRaises(KeyError, self._config.getReadOffset, + 'PLEXTOR ', 'DVDR PX-L890SA', '1.05') self._config.setReadOffset('PLEXTOR ', 'DVDR PX-L890SA', '1.05', 6) # getting it from memory should work - offset = self._config.getReadOffset('PLEXTOR ', 'DVDR PX-L890SA', - '1.05') + offset = self._config.getReadOffset( + 'PLEXTOR ', 'DVDR PX-L890SA', '1.05') self.assertEquals(offset, 6) # and so should getting it after reading it again self._config.open() - offset = self._config.getReadOffset('PLEXTOR ', 'DVDR PX-L890SA', - '1.05') + offset = self._config.getReadOffset( + 'PLEXTOR ', 'DVDR PX-L890SA', '1.05') self.assertEquals(offset, 6) def testAddReadOffsetSpaced(self): - self.assertRaises(KeyError, - self._config.getReadOffset, 'Slimtype', 'eSAU208 2 ', 'ML03') + self.assertRaises(KeyError, self._config.getReadOffset, + 'Slimtype', 'eSAU208 2 ', 'ML03') self._config.setReadOffset('Slimtype', 'eSAU208 2 ', 'ML03', 6) # getting it from memory should work @@ -53,7 +53,7 @@ class ConfigTestCase(tcommon.TestCase): def testDefeatsCache(self): self.assertRaises(KeyError, self._config.getDefeatsCache, - 'PLEXTOR ', 'DVDR PX-L890SA', '1.05') + 'PLEXTOR ', 'DVDR PX-L890SA', '1.05') self._config.setDefeatsCache( 'PLEXTOR ', 'DVDR PX-L890SA', '1.05', False) diff --git a/whipper/test/test_common_mbngs.py b/whipper/test/test_common_mbngs.py index fd1959e..78879e2 100644 --- a/whipper/test/test_common_mbngs.py +++ b/whipper/test/test_common_mbngs.py @@ -13,8 +13,8 @@ class MetadataTestCase(unittest.TestCase): # Generated with rip -R cd info def testJeffEverybodySingle(self): - path = os.path.join(os.path.dirname(__file__), - 'whipper.release.3451f29c-9bb8-4cc5-bfcc-bd50104b94f8.json') + filename = 'whipper.release.3451f29c-9bb8-4cc5-bfcc-bd50104b94f8.json' + path = os.path.join(os.path.dirname(__file__), filename) handle = open(path, "rb") response = json.loads(handle.read()) handle.close() @@ -26,8 +26,8 @@ class MetadataTestCase(unittest.TestCase): def test2MeterSessies10(self): # various artists, multiple artists per track - path = os.path.join(os.path.dirname(__file__), - 'whipper.release.a76714e0-32b1-4ed4-b28e-f86d99642193.json') + filename = 'whipper.release.a76714e0-32b1-4ed4-b28e-f86d99642193.json' + path = os.path.join(os.path.dirname(__file__), filename) handle = open(path, "rb") response = json.loads(handle.read()) handle.close() @@ -38,7 +38,7 @@ class MetadataTestCase(unittest.TestCase): self.assertEquals(metadata.artist, u'Various Artists') self.assertEquals(metadata.release, u'2001-10-15') self.assertEquals(metadata.mbidArtist, - u'89ad4ac3-39f7-470e-963a-56509c546377') + u'89ad4ac3-39f7-470e-963a-56509c546377') self.assertEquals(len(metadata.tracks), 18) @@ -46,16 +46,16 @@ class MetadataTestCase(unittest.TestCase): self.assertEquals(track16.artist, 'Tom Jones & Stereophonics') self.assertEquals(track16.mbidArtist, - u'57c6f649-6cde-48a7-8114-2a200247601a' - ';0bfba3d3-6a04-4779-bb0a-df07df5b0558' - ) + u'57c6f649-6cde-48a7-8114-2a200247601a' + ';0bfba3d3-6a04-4779-bb0a-df07df5b0558' + ) self.assertEquals(track16.sortName, - u'Jones, Tom & Stereophonics') + u'Jones, Tom & Stereophonics') def testBalladOfTheBrokenSeas(self): # various artists disc - path = os.path.join(os.path.dirname(__file__), - 'whipper.release.e32ae79a-336e-4d33-945c-8c5e8206dbd3.json') + filename = 'whipper.release.e32ae79a-336e-4d33-945c-8c5e8206dbd3.json' + path = os.path.join(os.path.dirname(__file__), filename) handle = open(path, "rb") response = json.loads(handle.read()) handle.close() @@ -65,11 +65,11 @@ class MetadataTestCase(unittest.TestCase): self.assertEquals(metadata.artist, u'Isobel Campbell & Mark Lanegan') self.assertEquals(metadata.sortName, - u'Campbell, Isobel & Lanegan, Mark') + u'Campbell, Isobel & Lanegan, Mark') self.assertEquals(metadata.release, u'2006-01-30') self.assertEquals(metadata.mbidArtist, - u'd51f3a15-12a2-41a0-acfa-33b5eae71164;' - 'a9126556-f555-4920-9617-6e013f8228a7') + u'd51f3a15-12a2-41a0-acfa-33b5eae71164;' + 'a9126556-f555-4920-9617-6e013f8228a7') self.assertEquals(len(metadata.tracks), 12) @@ -77,18 +77,18 @@ class MetadataTestCase(unittest.TestCase): self.assertEquals(track12.artist, u'Isobel Campbell & Mark Lanegan') self.assertEquals(track12.sortName, - u'Campbell, Isobel' - ' & Lanegan, Mark' - ) + u'Campbell, Isobel' + ' & Lanegan, Mark' + ) self.assertEquals(track12.mbidArtist, - u'd51f3a15-12a2-41a0-acfa-33b5eae71164;' - 'a9126556-f555-4920-9617-6e013f8228a7') + u'd51f3a15-12a2-41a0-acfa-33b5eae71164;' + 'a9126556-f555-4920-9617-6e013f8228a7') def testMalaInCuba(self): # single artist disc, but with multiple artists tracks # see https://github.com/thomasvs/morituri/issues/19 - path = os.path.join(os.path.dirname(__file__), - 'whipper.release.61c6fd9b-18f8-4a45-963a-ba3c5d990cae.json') + filename = 'whipper.release.61c6fd9b-18f8-4a45-963a-ba3c5d990cae.json' + path = os.path.join(os.path.dirname(__file__), filename) handle = open(path, "rb") response = json.loads(handle.read()) handle.close() @@ -100,7 +100,7 @@ class MetadataTestCase(unittest.TestCase): self.assertEquals(metadata.sortName, u'Mala') self.assertEquals(metadata.release, u'2012-09-17') self.assertEquals(metadata.mbidArtist, - u'09f221eb-c97e-4da5-ac22-d7ab7c555bbb') + u'09f221eb-c97e-4da5-ac22-d7ab7c555bbb') self.assertEquals(len(metadata.tracks), 14) @@ -108,9 +108,9 @@ class MetadataTestCase(unittest.TestCase): self.assertEquals(track6.artist, u'Mala feat. Dreiser & Sexto Sentido') self.assertEquals(track6.sortName, - u'Mala feat. Dreiser & Sexto Sentido') + u'Mala feat. Dreiser & Sexto Sentido') self.assertEquals(track6.mbidArtist, - u'09f221eb-c97e-4da5-ac22-d7ab7c555bbb' - ';ec07a209-55ff-4084-bc41-9d4d1764e075' - ';f626b92e-07b1-4a19-ad13-c09d690db66c' - ) + u'09f221eb-c97e-4da5-ac22-d7ab7c555bbb' + ';ec07a209-55ff-4084-bc41-9d4d1764e075' + ';f626b92e-07b1-4a19-ad13-c09d690db66c' + ) diff --git a/whipper/test/test_common_path.py b/whipper/test/test_common_path.py index bf7a552..a7e1638 100644 --- a/whipper/test/test_common_path.py +++ b/whipper/test/test_common_path.py @@ -22,9 +22,9 @@ class FilterTestCase(common.TestCase): def testSpecial(self): part = u'<<< $&*!\' "()`{}[]spaceship>>>' self.assertEquals(self._filter.filter(part), - u'___ _____ ________spaceship___') + u'___ _____ ________spaceship___') def testGreatest(self): part = u'Greatest Ever! Soul: The Definitive Collection' self.assertEquals(self._filter.filter(part), - u'Greatest Ever_ Soul - The Definitive Collection') + u'Greatest Ever_ Soul - The Definitive Collection') diff --git a/whipper/test/test_common_program.py b/whipper/test/test_common_program.py index fd2eef1..170bbcc 100644 --- a/whipper/test/test_common_program.py +++ b/whipper/test/test_common_program.py @@ -19,15 +19,16 @@ class TrackImageVerifyTestCase(unittest.TestCase): def testVerify(self): path = os.path.join(os.path.dirname(__file__), - 'dBAR-020-002e5023-029d8e49-040eaa14.bin') + 'dBAR-020-002e5023-029d8e49-040eaa14.bin') data = open(path, "rb").read() responses = accurip.getAccurateRipResponses(data) # these crc's were calculated from an actual rip checksums = [1644890007, 2945205445, 3983436658, 1528082495, - 1203704270, 1163423644, 3649097244, 100524219, 1583356174, 373652058, - 1842579359, 2850056507, 1329730252, 2526965856, 2525886806, 209743350, - 3184062337, 2099956663, 2943874164, 2321637196] + 1203704270, 1163423644, 3649097244, 100524219, + 1583356174, 373652058, 1842579359, 2850056507, + 1329730252, 2526965856, 2525886806, 209743350, + 3184062337, 2099956663, 2943874164, 2321637196] prog = program.Program(config.Config()) prog.result = result.RipResult() @@ -59,21 +60,21 @@ class TrackImageVerifyTestCase(unittest.TestCase): res = prog.getAccurateRipResults() self.assertEquals(res[1 - 1], - "Track 1: rip NOT accurate (not found) " - "[620b0797], DB [notfound]") + "Track 1: rip NOT accurate (not found) " + "[620b0797], DB [notfound]") self.assertEquals(res[2 - 1], - "Track 2: rip accurate (max confidence 2) " - "[af8c44c5], DB [af8c44c5]") + "Track 2: rip accurate (max confidence 2) " + "[af8c44c5], DB [af8c44c5]") self.assertEquals(res[10 - 1], - "Track 10: rip NOT accurate (max confidence 2) " - "[16457a5a], DB [eb6e55b4]") + "Track 10: rip NOT accurate (max confidence 2) " + "[16457a5a], DB [eb6e55b4]") class HTOATestCase(unittest.TestCase): def setUp(self): path = os.path.join(os.path.dirname(__file__), - 'silentalarm.result.pickle') + 'silentalarm.result.pickle') self._tracks = pickle.load(open(path, 'rb')) def testGetAccurateRipResults(self): @@ -90,9 +91,10 @@ class PathTestCase(unittest.TestCase): prog = program.Program(config.Config()) path = prog.getPath(u'/tmp', DEFAULT_DISC_TEMPLATE, - 'mbdiscid', 0) + 'mbdiscid', 0) self.assertEquals(path, - u'/tmp/unknown/Unknown Artist - mbdiscid/Unknown Artist - mbdiscid') + unicode('/tmp/unknown/Unknown Artist - mbdiscid/' + 'Unknown Artist - mbdiscid')) def testStandardTemplateFilled(self): prog = program.Program(config.Config()) @@ -102,9 +104,10 @@ class PathTestCase(unittest.TestCase): prog.metadata = md path = prog.getPath(u'/tmp', DEFAULT_DISC_TEMPLATE, - 'mbdiscid', 0) + 'mbdiscid', 0) self.assertEquals(path, - u'/tmp/unknown/Jeff Buckley - Grace/Jeff Buckley - Grace') + unicode('/tmp/unknown/Jeff Buckley - Grace/' + 'Jeff Buckley - Grace')) def testIssue66TemplateFilled(self): prog = program.Program(config.Config()) @@ -115,4 +118,4 @@ class PathTestCase(unittest.TestCase): path = prog.getPath(u'/tmp', u'%A/%d', 'mbdiscid', 0) self.assertEquals(path, - u'/tmp/Jeff Buckley/Grace') + u'/tmp/Jeff Buckley/Grace') diff --git a/whipper/test/test_image_cue.py b/whipper/test/test_image_cue.py index b30b2c5..eedffa8 100644 --- a/whipper/test/test_image_cue.py +++ b/whipper/test/test_image_cue.py @@ -11,11 +11,12 @@ from whipper.image import table, cue from whipper.test import common + class KingsSingleTestCase(unittest.TestCase): def setUp(self): self.cue = cue.CueFile(os.path.join(os.path.dirname(__file__), - u'kings-single.cue')) + u'kings-single.cue')) self.cue.parse() self.assertEquals(len(self.cue.table.tracks), 11) @@ -31,7 +32,7 @@ class KingsSeparateTestCase(unittest.TestCase): def setUp(self): self.cue = cue.CueFile(os.path.join(os.path.dirname(__file__), - u'kings-separate.cue')) + u'kings-separate.cue')) self.cue.parse() self.assertEquals(len(self.cue.table.tracks), 11) @@ -47,7 +48,7 @@ class KanyeMixedTestCase(unittest.TestCase): def setUp(self): self.cue = cue.CueFile(os.path.join(os.path.dirname(__file__), - u'kanye.cue')) + u'kanye.cue')) self.cue.parse() self.assertEquals(len(self.cue.table.tracks), 13) @@ -70,7 +71,7 @@ class WriteCueFileTestCase(unittest.TestCase): t = table.Track(2) t.index(0, absolute=1000, path=u'track01.wav', - relative=1000, counter=1) + relative=1000, counter=1) t.index(1, absolute=2000, path=u'track02.wav', relative=0, counter=2) it.tracks.append(t) it.absolutize() diff --git a/whipper/test/test_image_table.py b/whipper/test/test_image_table.py index 0b54360..68455c2 100644 --- a/whipper/test/test_image_table.py +++ b/whipper/test/test_image_table.py @@ -36,7 +36,7 @@ class LadyhawkeTestCase(tcommon.TestCase): self.table.tracks.append(table.Track(13, audio=False)) offsets = [0, 15537, 31691, 50866, 66466, 81202, 99409, - 115920, 133093, 149847, 161560, 177682, 207106] + 115920, 133093, 149847, 161560, 177682, 207106] t = self.table.tracks for i, offset in enumerate(offsets): t[i].index(1, absolute=offset) @@ -59,14 +59,14 @@ class LadyhawkeTestCase(tcommon.TestCase): # however, not (yet) in MusicBrainz database self.assertEquals(self.table.getMusicBrainzDiscId(), - "KnpGsLhvH.lPrNc1PBL21lb9Bg4-") + "KnpGsLhvH.lPrNc1PBL21lb9Bg4-") def testAccurateRip(self): self.assertEquals(self.table.getAccurateRipIds(), ( "0013bd5a", "00b8d489")) self.assertEquals(self.table.getAccurateRipURL(), - "http://www.accuraterip.com/accuraterip/a/5/d/" - "dBAR-012-0013bd5a-00b8d489-c60af50d.bin") + "http://www.accuraterip.com/accuraterip/a/5/d/" + "dBAR-012-0013bd5a-00b8d489-c60af50d.bin") def testDuration(self): self.assertEquals(self.table.duration(), 2761413) @@ -95,7 +95,7 @@ class MusicBrainzTestCase(tcommon.TestCase): def testMusicBrainz(self): self.assertEquals(self.table.getMusicBrainzDiscId(), - '49HHV7Eb8UKF3aQiNmu1GR8vKTY-') + '49HHV7Eb8UKF3aQiNmu1GR8vKTY-') class PregapTestCase(tcommon.TestCase): diff --git a/whipper/test/test_image_toc.py b/whipper/test/test_image_toc.py index 177c5ed..926b7f8 100644 --- a/whipper/test/test_image_toc.py +++ b/whipper/test/test_image_toc.py @@ -14,8 +14,7 @@ from whipper.test import common class CureTestCase(common.TestCase): def setUp(self): - self.path = os.path.join(os.path.dirname(__file__), - u'cure.toc') + self.path = os.path.join(os.path.dirname(__file__), u'cure.toc') self.toc = toc.TocFile(self.path) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 13) @@ -26,7 +25,7 @@ class CureTestCase(common.TestCase): # its length is all of track 1 from .toc, plus the INDEX 00 length # of track 2 self.assertEquals(self.toc.getTrackLength(t), - (((6 * 60) + 16) * 75 + 45) + ((1 * 75) + 4)) + (((6 * 60) + 16) * 75 + 45) + ((1 * 75) + 4)) # last track has unknown length t = self.toc.table.tracks[-1] self.assertEquals(self.toc.getTrackLength(t), -1) @@ -91,8 +90,7 @@ class CureTestCase(common.TestCase): # we verify it because it has failed in readdisc in the past self.assertEquals(self.toc.table.getAccurateRipURL(), - 'http://www.accuraterip.com/accuraterip/' - '3/c/4/dBAR-013-0019d4c3-00fe8924-b90c650d.bin') + 'http://www.accuraterip.com/accuraterip/3/c/4/dBAR-013-0019d4c3-00fe8924-b90c650d.bin') # noqa: E501 def testGetRealPath(self): self.assertRaises(KeyError, self.toc.getRealPath, u'track01.wav') @@ -110,8 +108,7 @@ class CureTestCase(common.TestCase): class BlocTestCase(common.TestCase): def setUp(self): - self.path = os.path.join(os.path.dirname(__file__), - u'bloc.toc') + self.path = os.path.join(os.path.dirname(__file__), u'bloc.toc') self.toc = toc.TocFile(self.path) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 13) @@ -168,8 +165,7 @@ class BlocTestCase(common.TestCase): def testAccurateRip(self): # we verify it because it has failed in readdisc in the past self.assertEquals(self.toc.table.getAccurateRipURL(), - 'http://www.accuraterip.com/accuraterip/' - 'e/d/2/dBAR-013-001af2de-0105994e-ad0be00d.bin') + 'http://www.accuraterip.com/accuraterip/e/d/2/dBAR-013-001af2de-0105994e-ad0be00d.bin') # noqa: E501 # The Breeders - Mountain Battles has CDText @@ -177,8 +173,7 @@ class BlocTestCase(common.TestCase): class BreedersTestCase(common.TestCase): def setUp(self): - self.path = os.path.join(os.path.dirname(__file__), - u'breeders.toc') + self.path = os.path.join(os.path.dirname(__file__), u'breeders.toc') self.toc = toc.TocFile(self.path) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 13) @@ -194,7 +189,6 @@ class BreedersTestCase(common.TestCase): self.assertEquals(cdt['TITLE'], 'OVERGLAZED') def testConvertCue(self): - # self.toc.table.absolutize() self.failUnless(self.toc.table.hasTOC()) cue = self.toc.table.cue() ref = self.readCue('breeders.cue') @@ -206,8 +200,7 @@ class BreedersTestCase(common.TestCase): class LadyhawkeTestCase(common.TestCase): def setUp(self): - self.path = os.path.join(os.path.dirname(__file__), - u'ladyhawke.toc') + self.path = os.path.join(os.path.dirname(__file__), u'ladyhawke.toc') self.toc = toc.TocFile(self.path) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 13) @@ -221,12 +214,9 @@ class LadyhawkeTestCase(common.TestCase): def testMusicBrainz(self): self.assertEquals(self.toc.table.getMusicBrainzDiscId(), - "KnpGsLhvH.lPrNc1PBL21lb9Bg4-") + "KnpGsLhvH.lPrNc1PBL21lb9Bg4-") self.assertEquals(self.toc.table.getMusicBrainzSubmitURL(), - "https://musicbrainz.org/cdtoc/attach?toc=" - "1+12+195856+150+15687+31841+51016+66616+81352+99559+" - "116070+133243+149997+161710+177832&" - "tracks=12&id=KnpGsLhvH.lPrNc1PBL21lb9Bg4-") + "https://musicbrainz.org/cdtoc/attach?toc=1+12+195856+150+15687+31841+51016+66616+81352+99559+116070+133243+149997+161710+177832&tracks=12&id=KnpGsLhvH.lPrNc1PBL21lb9Bg4-") # noqa: E501 # FIXME: I don't trust this toc, but I can't find the CD anymore @@ -247,13 +237,13 @@ class CapitalMergeTestCase(common.TestCase): def setUp(self): self.toc1 = toc.TocFile(os.path.join(os.path.dirname(__file__), - u'capital.1.toc')) + u'capital.1.toc')) self.toc1.parse() self.assertEquals(len(self.toc1.table.tracks), 11) self.failUnless(self.toc1.table.tracks[-1].audio) self.toc2 = toc.TocFile(os.path.join(os.path.dirname(__file__), - u'capital.2.toc')) + u'capital.2.toc')) self.toc2.parse() self.assertEquals(len(self.toc2.table.tracks), 1) self.failIf(self.toc2.table.tracks[-1].audio) @@ -272,7 +262,7 @@ class CapitalMergeTestCase(common.TestCase): # 197850+24320+44855+64090+77885+88095+104020+118245+129255+141765+ # 164487+181780&tracks=11&id=MAj3xXf6QMy7G.BIFOyHyq4MySE- self.assertEquals(self.table.getMusicBrainzDiscId(), - "MAj3xXf6QMy7G.BIFOyHyq4MySE-") + "MAj3xXf6QMy7G.BIFOyHyq4MySE-") def testDuration(self): # this matches track 11 end sector - track 1 start sector on @@ -321,8 +311,7 @@ class UnicodeTestCase(common.TestCase, common.UnicodeTestMixin): class TOTBLTestCase(common.TestCase): def setUp(self): - self.path = os.path.join(os.path.dirname(__file__), - u'totbl.fast.toc') + self.path = os.path.join(os.path.dirname(__file__), u'totbl.fast.toc') self.toc = toc.TocFile(self.path) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 11) @@ -338,7 +327,7 @@ class StrokesTestCase(common.TestCase): def setUp(self): self.path = os.path.join(os.path.dirname(__file__), - u'strokes-someday.toc') + u'strokes-someday.toc') self.toc = toc.TocFile(self.path) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 1) @@ -358,14 +347,16 @@ class StrokesTestCase(common.TestCase): self.assertEquals(i1.path, u'data.wav') cue = self._filterCue(self.toc.table.cue()) - ref = self._filterCue(open(os.path.join(os.path.dirname(__file__), - 'strokes-someday.eac.cue')).read()).decode('utf-8') + ref = self._filterCue( + open(os.path.join( + os.path.dirname(__file__), + 'strokes-someday.eac.cue')).read()).decode('utf-8') common.diffStrings(ref, cue) def _filterCue(self, output): # helper to be able to compare our generated .cue with the # EAC-extracted one - discard = [ 'TITLE', 'PERFORMER', 'FLAGS', 'REM' ] + discard = ['TITLE', 'PERFORMER', 'FLAGS', 'REM'] lines = output.split('\n') res = [] @@ -385,21 +376,16 @@ class StrokesTestCase(common.TestCase): return '\n'.join(res) - - # Surfer Rosa has # track 00 consisting of 32 frames of SILENCE # track 11 Vamos with an INDEX 02 # compared to an EAC single .cue file, all our offsets are 32 frames off # because the toc uses silence for track 01 index 00 while EAC puts it in # Range.wav - - class SurferRosaTestCase(common.TestCase): def setUp(self): - self.path = os.path.join(os.path.dirname(__file__), - u'surferrosa.toc') + self.path = os.path.join(os.path.dirname(__file__), u'surferrosa.toc') self.toc = toc.TocFile(self.path) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 21) diff --git a/whipper/test/test_program_cdparanoia.py b/whipper/test/test_program_cdparanoia.py index cb97848..deb90ea 100644 --- a/whipper/test/test_program_cdparanoia.py +++ b/whipper/test/test_program_cdparanoia.py @@ -15,7 +15,7 @@ class ParseTestCase(common.TestCase): def setUp(self): # report from Afghan Whigs - Sweet Son Of A Bitch path = os.path.join(os.path.dirname(__file__), - 'cdparanoia.progress') + 'cdparanoia.progress') self._parser = cdparanoia.ProgressParser(start=45990, stop=47719) self._handle = open(path) @@ -27,11 +27,12 @@ class ParseTestCase(common.TestCase): q = '%.01f %%' % (self._parser.getTrackQuality() * 100.0, ) self.assertEquals(q, '99.6 %') + class Parse1FrameTestCase(common.TestCase): def setUp(self): path = os.path.join(os.path.dirname(__file__), - 'cdparanoia.progress.strokes') + 'cdparanoia.progress.strokes') self._parser = cdparanoia.ProgressParser(start=0, stop=0) self._handle = open(path) @@ -49,7 +50,7 @@ class ErrorTestCase(common.TestCase): def setUp(self): # report from a rip with offset -1164 causing scsi errors path = os.path.join(os.path.dirname(__file__), - 'cdparanoia.progress.error') + 'cdparanoia.progress.error') self._parser = cdparanoia.ProgressParser(start=0, stop=10800) self._handle = open(path) @@ -87,7 +88,7 @@ class CacheTestCase(common.TestCase): self.runner = task.SyncRunner(verbose=False) path = os.path.join(os.path.dirname(__file__), - 'cdparanoia', 'PX-L890SA.cdparanoia-A.stderr') + 'cdparanoia', 'PX-L890SA.cdparanoia-A.stderr') t = AnalyzeFileTask(path) self.runner.run(t) self.failUnless(t.defeatsCache) diff --git a/whipper/test/test_program_cdrdao.py b/whipper/test/test_program_cdrdao.py index 07a2e5c..87b5a73 100644 --- a/whipper/test/test_program_cdrdao.py +++ b/whipper/test/test_program_cdrdao.py @@ -1,14 +1,12 @@ # -*- Mode: Python; test-case-name: whipper.test.test_program_cdparanoia -*- # vi:si:et:sw=4:sts=4:ts=4 -import os - from whipper.program import cdrdao - from whipper.test import common # TODO: Current test architecture makes testing cdrdao difficult. Revisit. + class VersionTestCase(common.TestCase): def testGetVersion(self): v = cdrdao.getCDRDAOVersion() diff --git a/whipper/test/test_program_sox.py b/whipper/test/test_program_sox.py index a5cd6bb..08c6aef 100644 --- a/whipper/test/test_program_sox.py +++ b/whipper/test/test_program_sox.py @@ -5,6 +5,7 @@ import os from whipper.program import sox from whipper.test import common + class PeakLevelTestCase(common.TestCase): def setUp(self): self.path = os.path.join(os.path.dirname(__file__), 'track.flac') diff --git a/whipper/test/test_program_soxi.py b/whipper/test/test_program_soxi.py index ac98da4..aa8102d 100644 --- a/whipper/test/test_program_soxi.py +++ b/whipper/test/test_program_soxi.py @@ -11,6 +11,7 @@ from whipper.test import common as tcommon base_track_file = os.path.join(os.path.dirname(__file__), u'track.flac') base_track_length = 10 * common.SAMPLES_PER_FRAME + class AudioLengthTestCase(tcommon.TestCase): def testLength(self): @@ -34,6 +35,7 @@ class AudioLengthPathTestCase(tcommon.TestCase): self.assertEquals(t.length, base_track_length) os.unlink(path) + class NormalAudioLengthPathTestCase(AudioLengthPathTestCase): def testSingleQuote(self): @@ -46,12 +48,13 @@ class NormalAudioLengthPathTestCase(AudioLengthPathTestCase): class UnicodeAudioLengthPathTestCase(AudioLengthPathTestCase, - tcommon.UnicodeTestMixin): + tcommon.UnicodeTestMixin): def testUnicodePath(self): # this test makes sure we can checksum a unicode path self._testSuffix(u'whipper.test.B\xeate Noire.empty.flac') + class AbsentFileAudioLengthPathTestCase(AudioLengthPathTestCase): def testAbsentFile(self): tempdir = tempfile.mkdtemp() @@ -60,6 +63,6 @@ class AbsentFileAudioLengthPathTestCase(AudioLengthPathTestCase): t = AudioLengthTask(path) runner = task.SyncRunner() self.assertRaises(task.TaskException, runner.run, - t, verbose=False) + t, verbose=False) os.rmdir(tempdir)