diff --git a/ChangeLog b/ChangeLog index 335653e..9b1202c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2009-09-11 Thomas Vander Stichele + + * morituri/image/cue.py: + * morituri/image/toc.py: + * morituri/test/test_image_cue.py: + * morituri/test/test_image_toc.py: + Read input file as utf-8. Fix logging of paths. + * morituri/image/image.py: + Document and add asserts for unicodeness of paths. + Encode path in launch lines as utf-8 + 2009-09-11 Thomas Vander Stichele * morituri/common/task.py: diff --git a/morituri/image/cue.py b/morituri/image/cue.py index fb4078a..a88fafa 100644 --- a/morituri/image/cue.py +++ b/morituri/image/cue.py @@ -28,6 +28,7 @@ See http://digitalx.org/cuesheetsyntax.php import os import re +import codecs from morituri.common import common, log from morituri.image import table @@ -65,6 +66,11 @@ class CueFile(object, log.Loggable): @ivar table: the index table. """ def __init__(self, path): + """ + @type path: unicode + """ + assert type(path) is unicode, "%r is not unicode" % path + self._path = path self._rems = {} self._messages = [] @@ -77,8 +83,8 @@ class CueFile(object, log.Loggable): currentTrack = None counter = 0 - self.info('Parsing .cue file %s', self._path) - handle = open(self._path, 'r') + self.info('Parsing .cue file %r', self._path) + handle = codecs.open(self._path, 'r', 'utf-8') for number, line in enumerate(handle.readlines()): line = line.rstrip() @@ -134,7 +140,7 @@ class CueFile(object, log.Loggable): + seconds * common.FRAMES_PER_SECOND \ + minutes * common.FRAMES_PER_SECOND * 60 - self.debug('found index %d of track %r in %s:%d', + self.debug('found index %d of track %r in %r:%d', indexNumber, currentTrack, currentFile.path, frameOffset) # FIXME: what do we do about File's FORMAT ? currentTrack.index(indexNumber, @@ -173,7 +179,11 @@ class CueFile(object, log.Loggable): def getRealPath(self, path): """ Translate the .cue's FILE to an existing path. + + @type path: unicode """ + assert type(path) is unicode, "%r is not unicode" % path + if os.path.exists(path): return path @@ -199,7 +209,7 @@ class CueFile(object, log.Loggable): if os.path.exists(cpath): return cpath - raise KeyError, "Cannot find file for %s" % path + raise KeyError, "Cannot find file for %r" % path class File: @@ -207,8 +217,13 @@ class File: I represent a FILE line in a cue file. """ def __init__(self, path, format): + """ + @type path: unicode + """ + assert type(path) is unicode, "%r is not unicode" % path + self.path = path self.format = format def __repr__(self): - return '' % (self.path, self.format) + return '' % (self.path, self.format) diff --git a/morituri/image/image.py b/morituri/image/image.py index c4fc48b..199d585 100644 --- a/morituri/image/image.py +++ b/morituri/image/image.py @@ -37,8 +37,11 @@ class Image(object, log.Loggable): def __init__(self, path): """ + @type path: unicode @param path: .cue path """ + assert type(path) is unicode, "%r is not unicode" % path + self._path = path self.cue = cue.CueFile(path) self.cue.parse() @@ -50,7 +53,11 @@ class Image(object, log.Loggable): def getRealPath(self, path): """ Translate the .cue's FILE to an existing path. + + @param path: .cue path """ + assert type(path) is unicode, "%r is not unicode" % path + return self.cue.getRealPath(path) def setup(self, runner): @@ -132,6 +139,11 @@ class AudioLengthTask(task.Task): length = None def __init__(self, path): + """ + @type path: unicode + """ + assert type(path) is unicode, "%r is not unicode" % path + self._path = path def start(self, runner): @@ -139,7 +151,7 @@ class AudioLengthTask(task.Task): self._pipeline = gst.parse_launch(''' filesrc location="%s" ! decodebin ! audio/x-raw-int ! - fakesink name=sink''' % self._path) + fakesink name=sink''' % self._path.encode('utf-8')) self.debug('pausing') self._pipeline.set_state(gst.STATE_PAUSED) self._pipeline.get_state() @@ -152,12 +164,12 @@ class AudioLengthTask(task.Task): try: length, qformat = sink.query_duration(gst.FORMAT_DEFAULT) except gst.QueryError: - print 'failed to query %s' % self._path + print 'failed to query %r' % self._path # wavparse 0.10.14 returns in bytes if qformat == gst.FORMAT_BYTES: self.debug('query returned in BYTES format') length /= 4 - self.debug('total length of %s in samples: %d', self._path, length) + self.debug('total length of %r in samples: %d', self._path, length) self.length = length self._pipeline.set_state(gst.STATE_NULL) @@ -186,7 +198,8 @@ class ImageVerifyTask(task.MultiSeparateTask): if length == -1: path = image.getRealPath(index.path) - self.debug('schedule scan of audio length of %s', path) + assert type(path) is unicode, "%r is not unicode" % path + self.debug('schedule scan of audio length of %r', path) taskk = AudioLengthTask(path) self.addTask(taskk) self._tasks.append((trackIndex + 1, track, taskk)) diff --git a/morituri/image/toc.py b/morituri/image/toc.py index 660249d..c86fdcf 100644 --- a/morituri/image/toc.py +++ b/morituri/image/toc.py @@ -26,6 +26,7 @@ Reading .toc files import os import re +import codecs from morituri.common import common, log from morituri.image import table @@ -87,6 +88,10 @@ _INDEX_RE = re.compile(r""" class TocFile(object, log.Loggable): def __init__(self, path): + """ + @type path: unicode + """ + assert type(path) is unicode, "%r is not unicode" % path self._path = path self._messages = [] self.table = table.Table() @@ -113,7 +118,7 @@ class TocFile(object, log.Loggable): # 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 # at the end of each parsed TRACK record - handle = open(self._path, 'r') + handle = codecs.open(self._path, "r", "utf-8") for number, line in enumerate(handle.readlines()): line = line.rstrip() @@ -313,7 +318,11 @@ class TocFile(object, log.Loggable): def getRealPath(self, path): """ Translate the .cue's FILE to an existing path. + + @type path: unicode """ + assert type(path) is unicode, "%r is not unicode" % path + if os.path.exists(path): return path @@ -339,16 +348,21 @@ class TocFile(object, log.Loggable): if os.path.exists(cpath): return cpath - raise KeyError, "Cannot find file for %s" % path + raise KeyError, "Cannot find file for %r" % path class File: """ I represent a FILE line in a .toc file. """ def __init__(self, path, start, length): + """ + @type path: unicode + """ + assert type(path) is unicode, "%r is not unicode" % path + self.path = path #self.start = start #self.length = length def __repr__(self): - return '' % (self.path, ) + return '' % (self.path, ) diff --git a/morituri/test/test_image_cue.py b/morituri/test/test_image_cue.py index 3fb3096..e8432fa 100644 --- a/morituri/test/test_image_cue.py +++ b/morituri/test/test_image_cue.py @@ -12,7 +12,7 @@ from morituri.image import table, cue class KingsSingleTestCase(unittest.TestCase): def setUp(self): self.cue = cue.CueFile(os.path.join(os.path.dirname(__file__), - 'kings-single.cue')) + u'kings-single.cue')) self.cue.parse() self.assertEquals(len(self.cue.table.tracks), 11) @@ -26,7 +26,7 @@ class KingsSingleTestCase(unittest.TestCase): class KingsSeparateTestCase(unittest.TestCase): def setUp(self): self.cue = cue.CueFile(os.path.join(os.path.dirname(__file__), - 'kings-separate.cue')) + u'kings-separate.cue')) self.cue.parse() self.assertEquals(len(self.cue.table.tracks), 11) @@ -40,7 +40,7 @@ class KingsSeparateTestCase(unittest.TestCase): class KanyeMixedTestCase(unittest.TestCase): def setUp(self): self.cue = cue.CueFile(os.path.join(os.path.dirname(__file__), - 'kanye.cue')) + u'kanye.cue')) self.cue.parse() self.assertEquals(len(self.cue.table.tracks), 13) @@ -51,18 +51,19 @@ class KanyeMixedTestCase(unittest.TestCase): class WriteCueFileTestCase(unittest.TestCase): def testWrite(self): - fd, path = tempfile.mkstemp(suffix='morituri.test.cue') + fd, path = tempfile.mkstemp(suffix=u'morituri.test.cue') os.close(fd) it = table.Table() t = table.Track(1) - t.index(1, absolute=0, path='track01.wav', relative=0, counter=1) + t.index(1, absolute=0, path=u'track01.wav', relative=0, counter=1) it.tracks.append(t) t = table.Track(2) - t.index(0, absolute=1000, path='track01.wav', relative=1000, counter=1) - t.index(1, absolute=2000, path='track02.wav', relative=0, counter=2) + t.index(0, absolute=1000, path=u'track01.wav', + relative=1000, counter=1) + t.index(1, absolute=2000, path=u'track02.wav', relative=0, counter=2) it.tracks.append(t) it.absolutize() it.leadout = 3000 diff --git a/morituri/test/test_image_toc.py b/morituri/test/test_image_toc.py index 31502fd..5efadf5 100644 --- a/morituri/test/test_image_toc.py +++ b/morituri/test/test_image_toc.py @@ -12,7 +12,7 @@ from morituri.test import common class CureTestCase(unittest.TestCase): def setUp(self): self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__), - 'cure.toc')) + u'cure.toc')) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 13) @@ -93,7 +93,7 @@ class CureTestCase(unittest.TestCase): class BlocTestCase(unittest.TestCase): def setUp(self): self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__), - 'bloc.toc')) + u'bloc.toc')) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 13) @@ -140,7 +140,7 @@ class BlocTestCase(unittest.TestCase): class BreedersTestCase(unittest.TestCase): def setUp(self): self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__), - 'breeders.toc')) + u'breeders.toc')) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 13) @@ -166,7 +166,7 @@ class BreedersTestCase(unittest.TestCase): class LadyhawkeTestCase(unittest.TestCase): def setUp(self): self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__), - 'ladyhawke.toc')) + u'ladyhawke.toc')) self.toc.parse() self.assertEquals(len(self.toc.table.tracks), 13) #import code; code.interact(local=locals()) @@ -182,13 +182,13 @@ class LadyhawkeTestCase(unittest.TestCase): class CapitalMergeTestCase(unittest.TestCase): def setUp(self): self.toc1 = toc.TocFile(os.path.join(os.path.dirname(__file__), - '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__), - '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)