Initial pass on python 3 port

Given the imminent end-of-life for Python 2, I didn't bother making the
codebase compatible with both.

Signed-off-by: Drew DeVault <sir@cmpwn.com>
This commit is contained in:
Drew DeVault
2019-08-10 11:45:17 +09:00
committed by JoeLametta
parent f740a0ef0d
commit 64dd9d843a
33 changed files with 274 additions and 317 deletions

View File

@@ -37,8 +37,8 @@ logger = logging.getLogger(__name__)
SILENT = 0
MAX_TRIES = 5
DEFAULT_TRACK_TEMPLATE = u'%r/%A - %d/%t. %a - %n'
DEFAULT_DISC_TEMPLATE = u'%r/%A - %d/%A - %d'
DEFAULT_TRACK_TEMPLATE = '%r/%A - %d/%t. %a - %n'
DEFAULT_DISC_TEMPLATE = '%r/%A - %d/%A - %d'
TEMPLATE_DESCRIPTION = '''
Tracks are named according to the track template, filling in the variables
@@ -137,7 +137,7 @@ class _CD(BaseCommand):
if getattr(self.options, 'working_directory', False):
os.chdir(os.path.expanduser(self.options.working_directory))
if hasattr(self.options, 'output_directory'):
out_bpath = self.options.output_directory.decode('utf-8')
out_bpath = self.options.output_directory
# Needed to preserve cdrdao's tocfile
out_fpath = self.program.getPath(out_bpath,
self.options.disc_template,
@@ -295,10 +295,9 @@ Log files will log the path to tracks relative to this 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
validate_template(self.options.track_template, 'track')
self.options.disc_template = self.options.disc_template.decode('utf-8')
self.options.disc_template = self.options.disc_template
validate_template(self.options.disc_template, 'disc')
if self.options.offset is None:
@@ -323,7 +322,7 @@ Log files will log the path to tracks relative to this directory.
def doCommand(self):
self.program.setWorkingDirectory(self.options.working_directory)
self.program.outdir = self.options.output_directory.decode('utf-8')
self.program.outdir = self.options.output_directory
self.program.result.offset = int(self.options.offset)
self.program.result.overread = self.options.overread
self.program.result.logger = self.options.logger
@@ -336,13 +335,11 @@ Log files will log the path to tracks relative to this directory.
if os.path.exists(dirname):
logs = glob.glob(os.path.join(dirname, '*.log'))
if logs:
msg = ("output directory %s is a finished rip" %
dirname.encode('utf-8'))
msg = ("output directory %s is a finished rip" % dirname)
logger.debug(msg)
raise RuntimeError(msg)
else:
logger.info("creating output directory %s",
dirname.encode('utf-8'))
logger.info("creating output directory %s", dirname)
os.makedirs(dirname)
# FIXME: turn this into a method
@@ -366,7 +363,7 @@ Log files will log the path to tracks relative to this directory.
logger.debug('ripIfNotRipped: path %r', path)
trackResult.number = number
assert isinstance(path, unicode), "%r is not unicode" % path
assert isinstance(path, str), "%r is not str" % path
trackResult.filename = path
if number > 0:
trackResult.pregap = self.itable.tracks[number - 1].getPregap()
@@ -385,7 +382,7 @@ Log files will log the path to tracks relative to this directory.
logger.info('verifying track %d of %d: %s',
number, len(self.itable.tracks),
os.path.basename(path).encode('utf-8'))
os.path.basename(path))
if not self.program.verifyTrack(self.runner, trackResult):
logger.warning('verification failed, reripping...')
os.unlink(path)
@@ -403,7 +400,7 @@ Log files will log the path to tracks relative to this directory.
extra = " (try %d)" % tries
logger.info('ripping track %d of %d%s: %s',
number, len(self.itable.tracks), extra,
os.path.basename(path).encode('utf-8'))
os.path.basename(path))
try:
logger.debug('ripIfNotRipped: track %d, try %d',
number, tries)

View File

@@ -45,7 +45,6 @@ Verifies the image from the given .cue files against the AccurateRip database.
runner = task.SyncRunner()
for arg in self.options.cuefile:
arg = arg.decode('utf-8')
cueImage = image.Image(arg)
cueImage.setup(runner)

View File

@@ -17,7 +17,7 @@ Example disc id: KnpGsLhvH.lPrNc1PBL21lb9Bg4-"""
def do(self):
try:
discId = unicode(self.options.mbdiscid)
discId = str(self.options.mbdiscid)
except IndexError:
print('Please specify a MusicBrainz disc id.')
return 3
@@ -29,7 +29,7 @@ Example disc id: KnpGsLhvH.lPrNc1PBL21lb9Bg4-"""
print('- Release %d:' % (i + 1, ))
print(' Artist: %s' % md.artist.encode('utf-8'))
print(' Title: %s' % md.title.encode('utf-8'))
print(' Type: %s' % unicode(md.releaseType).encode('utf-8')) # noqa: E501
print(' Type: %s' % str(md.releaseType).encode('utf-8')) # noqa: E501
print(' URL: %s' % md.url)
print(' Tracks: %d' % len(md.tracks))
if md.catalogNumber:

View File

@@ -177,7 +177,7 @@ CD in the AccurateRip database."""
logger.debug('ripping track %r with offset %d...', track, offset)
fd, path = tempfile.mkstemp(
suffix=u'.track%02d.offset%d.whipper.wav' % (
suffix='.track%02d.offset%d.whipper.wav' % (
track, offset))
os.close(fd)

View File

@@ -60,7 +60,7 @@ class _AccurateRipResponse(object):
position, so track 1 will have array index 0, track 2 will have array
index 1, and so forth. HTOA and other hidden tracks are not included.
"""
self.num_tracks = struct.unpack("B", data[0])[0]
self.num_tracks = data[0]
self.discId1 = "%08x" % struct.unpack("<L", data[1:5])[0]
self.discId2 = "%08x" % struct.unpack("<L", data[5:9])[0]
self.cddbDiscId = "%08x" % struct.unpack("<L", data[9:13])[0]
@@ -69,7 +69,7 @@ class _AccurateRipResponse(object):
self.checksums = []
pos = 13
for _ in range(self.num_tracks):
confidence = struct.unpack("B", data[pos])[0]
confidence = data[pos]
checksum = "%08x" % struct.unpack("<L", data[pos + 1:pos + 5])[0]
self.confidences.append(confidence)
self.checksums.append(checksum)
@@ -88,7 +88,7 @@ class _AccurateRipResponse(object):
def _split_responses(raw_entry):
responses = []
while raw_entry:
track_count = struct.unpack("B", raw_entry[0])[0]
track_count = raw_entry[0]
nbytes = 1 + 12 + track_count * (1 + 8)
responses.append(_AccurateRipResponse(raw_entry[:nbytes]))
raw_entry = raw_entry[nbytes:]

View File

@@ -124,11 +124,7 @@ class PersistedCache:
def __init__(self, path):
self.path = path
try:
os.makedirs(self.path)
except OSError as e:
if e.errno != os.errno.EEXIST: # FIXME: errno 17 is 'File Exists'
raise
os.makedirs(self.path, exist_ok=True)
def _getPath(self, key):
return os.path.join(self.path, '%s.pickle' % key)

View File

@@ -165,7 +165,7 @@ def truncate_filename(path):
fn_lim = os.pathconf(p.encode('utf-8'), 'PC_NAME_MAX')
f_max = fn_lim - len(e.encode('utf-8'))
f = unicodedata.normalize('NFC', f)
f_trunc = unicode(f.encode('utf-8')[:f_max], 'utf-8', errors='ignore')
f_trunc = f.encode()[:f_max].decode('utf-8', errors='ignore')
return os.path.join(p, f_trunc + e)
@@ -196,7 +196,7 @@ def shrinkPath(path):
name = " ".join(pieces)
# ext includes period
parts[-1] = u'%s%s' % (name, ext)
parts[-1] = '%s%s' % (name, ext)
path = os.path.join(*parts)
return path
@@ -209,11 +209,11 @@ def getRealPath(refPath, filePath):
:param refPath: path to the file from which the track is referenced;
for example, path to the .cue file in the same directory
:type refPath: unicode
:type refPath: str
:type filePath: unicode
:type filePath: str
"""
assert isinstance(filePath, unicode), "%r is not unicode" % filePath
assert isinstance(filePath, str), "%r is not str" % filePath
if os.path.exists(filePath):
return filePath
@@ -321,7 +321,7 @@ class VersionGetter(object):
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, close_fds=True)
p.wait()
output = asyncsub.recv_some(p, e=0, stderr=1)
output = asyncsub.recv_some(p, e=0, stderr=1).decode()
vre = self._regexp.search(output)
if vre:
version = self._expander % vre.groupdict()

View File

@@ -18,13 +18,12 @@
# You should have received a copy of the GNU General Public License
# along with whipper. If not, see <http://www.gnu.org/licenses/>.
import ConfigParser
import codecs
import configparser
import os.path
import shutil
import tempfile
import urllib
from urlparse import urlparse
from urllib.parse import urlparse, quote
from whipper.common import directory
@@ -37,7 +36,7 @@ class Config:
def __init__(self, path=None):
self._path = path or directory.config_path()
self._parser = ConfigParser.SafeConfigParser()
self._parser = configparser.ConfigParser()
self.open()
@@ -51,7 +50,7 @@ class Config:
len(self._parser.sections()))
def write(self):
fd, path = tempfile.mkstemp(suffix=u'.whipperrc')
fd, path = tempfile.mkstemp(suffix='.whipperrc')
handle = os.fdopen(fd, 'w')
self._parser.write(handle)
handle.close()
@@ -64,7 +63,7 @@ class Config:
method = getattr(self._parser, methodName)
try:
return method(section, option)
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
except (configparser.NoSectionError, configparser.NoOptionError):
return None
def get(self, section, option):
@@ -102,7 +101,7 @@ class Config:
try:
return int(self._parser.get(section, 'read_offset'))
except ConfigParser.NoOptionError:
except configparser.NoOptionError:
raise KeyError("Could not find read_offset for %s/%s/%s" % (
vendor, model, release))
@@ -121,7 +120,7 @@ class Config:
try:
return self._parser.get(section, 'defeats_cache') == 'True'
except ConfigParser.NoOptionError:
except configparser.NoOptionError:
raise KeyError("Could not find defeats_cache for %s/%s/%s" % (
vendor, model, release))
@@ -153,7 +152,7 @@ class Config:
try:
section = self._findDriveSection(vendor, model, release)
except KeyError:
section = 'drive:' + urllib.quote('%s:%s:%s' % (
section = 'drive:' + quote('%s:%s:%s' % (
vendor, model, release))
self._parser.add_section(section)
for key in ['vendor', 'model', 'release']:

View File

@@ -23,16 +23,16 @@ from os.path import join, expanduser, exists
def config_path():
path = join(getenv('XDG_CONFIG_HOME') or join(expanduser('~'), u'.config'),
u'whipper')
path = join(getenv('XDG_CONFIG_HOME') or join(expanduser('~'), '.config'),
'whipper')
if not exists(path):
makedirs(path)
return join(path, u'whipper.conf')
return join(path, 'whipper.conf')
def cache_path(name=None):
path = join(getenv('XDG_CACHE_HOME') or join(expanduser('~'), u'.cache'),
u'whipper')
path = join(getenv('XDG_CACHE_HOME') or join(expanduser('~'), '.cache'),
'whipper')
if name:
path = join(path, name)
if not exists(path):
@@ -42,8 +42,8 @@ def cache_path(name=None):
def data_path(name=None):
path = join(getenv('XDG_DATA_HOME') or
join(expanduser('~'), u'.local/share'),
u'whipper')
join(expanduser('~'), '.local/share'),
'whipper')
if name:
path = join(path, name)
if not exists(path):

View File

@@ -21,7 +21,7 @@
"""
Handles communication with the MusicBrainz server using NGS.
"""
import urllib2
from urllib.error import HTTPError
import whipper
@@ -61,7 +61,7 @@ class DiscMetadata(object):
:param artist: artist(s) name
:param sortName: release artist sort name
:param release: earliest release date, in YYYY-MM-DD
:type release: unicode
:type release: str
:param title: title of the disc (with disambiguation)
:param releaseTitle: title of the release (without disambiguation)
:type tracks: list of :any:`TrackMetadata`
@@ -152,7 +152,7 @@ def _getWorks(recording):
"""Get "performance of" works out of a recording."""
works = []
valid_work_rel_types = [
u'a3005666-a872-32c3-ad06-98af558e99b0', # "Performance"
'a3005666-a872-32c3-ad06-98af558e99b0', # "Performance"
]
if 'work-relation-list' in recording:
for work in recording['work-relation-list']:
@@ -298,7 +298,7 @@ def musicbrainz(discid, country=None, record=False):
result = musicbrainzngs.get_releases_by_discid(
discid, includes=["artists", "recordings", "release-groups"])
except musicbrainzngs.ResponseError as e:
if isinstance(e.cause, urllib2.HTTPError):
if isinstance(e.cause, HTTPError):
if e.cause.code == 404:
raise NotFoundException(e)
else:

View File

@@ -50,18 +50,16 @@ 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)
path = re.sub(ur'[\u201c\u201d\u201f]', '"', path, re.UNICODE)
path = re.sub(r'[\xc2\xb4\u2018\u2019\u201b]', "'", path)
path = re.sub(r'[\u201c\u201d\u201f]', '"', path)
if self._special:
path = separators(path)
path = re.sub(r'[*?&!\'\"$()`{}\[\]<>]',
'_', path, re.UNICODE)
path = re.sub(r'[*?&!\'\"$()`{}\[\]<>]', '_', path)
if self._fat:
path = separators(path)
# : and | already gone, but leave them here for reference
path = re.sub(r'[:*?"<>|]', '_', path, re.UNICODE)
path = re.sub(r'[:*?"<>|]', '_', path)
return path

View File

@@ -47,7 +47,7 @@ class Program:
:vartype metadata: mbngs.DiscMetadata
:cvar result: the rip's result
:vartype result: result.RipResult
:vartype outdir: unicode
:vartype outdir: str
:vartype config: whipper.common.config.Config
"""
@@ -197,8 +197,8 @@ class Program:
- %x: audio extension, lowercase
- %X: audio extension, uppercase
"""
assert isinstance(outdir, unicode), "%r is not unicode" % outdir
assert isinstance(template, unicode), "%r is not unicode" % template
assert isinstance(outdir, str), "%r is not str" % outdir
assert isinstance(template, str), "%r is not str" % template
v = {}
v['A'] = 'Unknown Artist'
v['d'] = mbdiscid # fallback for title
@@ -228,7 +228,7 @@ class Program:
if metadata.releaseType:
v['R'] = metadata.releaseType
v['r'] = metadata.releaseType.lower()
if track_number > 0:
if track_number is not None and track_number > 0:
v['a'] = self._filter.filter(
metadata.tracks[track_number - 1].artist)
v['s'] = self._filter.filter(
@@ -307,8 +307,8 @@ class Program:
print('\nMatching releases:')
for metadata in metadatas:
print('\nArtist : %s' % metadata.artist.encode('utf-8'))
print('Title : %s' % metadata.title.encode('utf-8'))
print('\nArtist : %s' % metadata.artist)
print('Title : %s' % metadata.title)
print('Duration: %s' % common.formatTime(
metadata.duration / 1000.0))
print('URL : %s' % metadata.url)
@@ -318,8 +318,7 @@ class Program:
print("Barcode : %s" % metadata.barcode)
# TODO: Add test for non ASCII catalog numbers: see issue #215
if metadata.catalogNumber:
print("Cat no : %s" %
metadata.catalogNumber.encode('utf-8'))
print("Cat no : %s" % metadata.catalogNumber)
delta = abs(metadata.duration - ittoc.duration())
if delta not in deltas:
@@ -346,8 +345,8 @@ class Program:
metadatas)
if len(metadatas) == 1:
logger.info('picked requested release id %s', release)
print('Artist: %s' % metadatas[0].artist.encode('utf-8'))
print('Title : %s' % metadatas[0].title.encode('utf-8'))
print('Artist: %s' % metadatas[0].artist)
print('Title : %s' % metadatas[0].title)
elif not metadatas:
logger.warning("requested release id '%s', but none of "
"the found releases match", release)
@@ -374,8 +373,8 @@ class Program:
logger.warning('picked closest match in duration. '
'Others may be wrong in MusicBrainz, '
'please correct')
print('Artist : %s' % artist.encode('utf-8'))
print('Title : %s' % metadatas[0].title.encode('utf-8'))
print('Artist : %s' % artist)
print('Title : %s' % metadatas[0].title)
# Select one of the returned releases. We just pick the first one.
ret = metadatas[0]
@@ -395,10 +394,10 @@ class Program:
:rtype: dict
"""
trackArtist = u'Unknown Artist'
releaseArtist = u'Unknown Artist'
disc = u'Unknown Disc'
title = u'Unknown Track'
trackArtist = 'Unknown Artist'
releaseArtist = 'Unknown Artist'
disc = 'Unknown Disc'
title = 'Unknown Track'
if self.metadata:
trackArtist = self.metadata.artist
@@ -435,7 +434,7 @@ class Program:
tags['TITLE'] = title
tags['ALBUM'] = disc
tags['TRACKNUMBER'] = u'%s' % number
tags['TRACKNUMBER'] = '%s' % number
if self.metadata:
if self.metadata.release is not None:
@@ -573,7 +572,7 @@ class Program:
def write_m3u(self, discname):
m3uPath = common.truncate_filename(discname + '.m3u')
with open(m3uPath, 'w') as f:
f.write(u'#EXTM3U\n'.encode('utf-8'))
f.write('#EXTM3U\n')
for track in self.result.tracks:
if not track.filename:
# false positive htoa
@@ -586,10 +585,10 @@ class Program:
common.FRAMES_PER_SECOND)
target_path = common.getRelativePath(track.filename, m3uPath)
u = u'#EXTINF:%d,%s\n' % (length, target_path)
f.write(u.encode('utf-8'))
u = '#EXTINF:%d,%s\n' % (length, target_path)
f.write(u)
u = '%s\n' % target_path
f.write(u.encode('utf-8'))
f.write(u)
def writeCue(self, discName):
assert self.result.table.canCue()
@@ -597,7 +596,7 @@ class Program:
logger.debug('write .cue file to %s', cuePath)
handle = open(cuePath, 'w')
# FIXME: do we always want utf-8 ?
handle.write(self.result.table.cue(cuePath).encode('utf-8'))
handle.write(self.result.table.cue(cuePath))
handle.close()
self.cuePath = cuePath
@@ -608,7 +607,7 @@ class Program:
logPath = common.truncate_filename(discName + '.log')
handle = open(logPath, 'w')
log = txt_logger.log(self.result)
handle.write(log.encode('utf-8'))
handle.write(log)
handle.close()
self.logPath = logPath

View File

@@ -11,7 +11,7 @@ import sys
PIPE = subprocess.PIPE
if subprocess.mswindows:
if sys.platform == 'win32':
from win32file import ReadFile, WriteFile
from win32pipe import PeekNamedPipe
import msvcrt
@@ -42,7 +42,7 @@ class Popen(subprocess.Popen):
getattr(self, which).close()
setattr(self, which, None)
if subprocess.mswindows:
if sys.platform == 'win32':
def send(self, in_put):
if not self.stdin:
@@ -149,7 +149,7 @@ def recv_some(p, t=.1, e=1, tr=5, stderr=0):
y.append(r)
else:
time.sleep(max((x - time.time()) / tr, 0))
return ''.join(y)
return ''.join(x.decode() for x in y).encode()
def send_all(p, data):

View File

@@ -53,15 +53,8 @@ class DiscID(object):
"track_count",
"playable_length"]]))
if sys.version_info[0] >= 3:
def __str__(self):
return self.__unicode__()
else:
def __str__(self):
return self.__unicode__().encode('ascii')
def __unicode__(self):
return u"{:08X}".format(int(self))
def __str__(self):
return "{:08X}".format(int(self))
def __int__(self):
digit_sum_ = sum([digit_sum(o // 75) for o in self.offsets])
@@ -90,11 +83,11 @@ def perform_lookup(disc_id, freedb_server, freedb_port):
query = freedb_command(freedb_server,
freedb_port,
u"query",
*([disc_id.__unicode__(),
u"{:d}".format(disc_id.track_count)] +
[u"{:d}".format(o) for o in disc_id.offsets] +
[u"{:d}".format(disc_id.playable_length)]))
"query",
*([disc_id.__str__(),
"{:d}".format(disc_id.track_count)] +
["{:d}".format(o) for o in disc_id.offsets] +
["{:d}".format(disc_id.playable_length)]))
line = next(query)
response = RESPONSE.match(line)
@@ -116,7 +109,7 @@ def perform_lookup(disc_id, freedb_server, freedb_port):
elif (code == 211) or (code == 210):
# multiple exact or inexact matches
line = next(query)
while not line.startswith(u"."):
while not line.startswith("."):
match = QUERY_RESULT.match(line)
if match is not None:
matches.append((match.group(1),
@@ -140,7 +133,7 @@ def perform_lookup(disc_id, freedb_server, freedb_port):
query = freedb_command(freedb_server,
freedb_port,
u"read",
"read",
category,
disc_id)
@@ -149,8 +142,8 @@ def perform_lookup(disc_id, freedb_server, freedb_port):
# FIXME: check response code here
freedb = {}
line = next(query)
while not line.startswith(u"."):
if not line.startswith(u"#"):
while not line.startswith("."):
if not line.startswith("#"):
entry = FREEDB_LINE.match(line)
if entry is not None:
if entry.group(1) in freedb:
@@ -165,52 +158,38 @@ def perform_lookup(disc_id, freedb_server, freedb_port):
def freedb_command(freedb_server, freedb_port, cmd, *args):
"""given a freedb_server string, freedb_port int,
command unicode string and argument unicode strings,
yields a list of Unicode strings"""
command string and argument strings, yields a list of strings"""
try:
from urllib.request import urlopen
from urllib.error import URLError
except ImportError:
from urllib2 import urlopen, URLError
try:
from urllib.parse import urlencode
except ImportError:
from urllib import urlencode
from urllib.error import URLError
from urllib.request import urlopen
from urllib.parse import urlencode
from socket import getfqdn
from whipper import __version__ as VERSION
from sys import version_info
PY3 = version_info[0] >= 3
# some debug type checking
assert(isinstance(cmd, str if PY3 else unicode))
assert(isinstance(cmd, str))
for arg in args:
assert(isinstance(arg, str if PY3 else unicode))
assert(isinstance(arg, str))
POST = []
# generate query to post with arguments in specific order
if len(args) > 0:
POST.append((u"cmd", u"cddb {} {}".format(cmd, " ".join(args))))
POST.append(("cmd", "cddb {} {}".format(cmd, " ".join(args))))
else:
POST.append((u"cmd", u"cddb {}".format(cmd)))
POST.append(("cmd", "cddb {}".format(cmd)))
POST.append(
(u"hello",
u"user {} {} {}".format(
getfqdn() if PY3 else getfqdn().decode("UTF-8", "replace"),
u"whipper",
VERSION if PY3 else VERSION.decode("ascii"))))
("hello",
"user {} {} {}".format(getfqdn(), "whipper", VERSION)))
POST.append((u"proto", u"6"))
POST.append(("proto", "6"))
try:
# get Request object from post
request = urlopen(
"http://{}:{:d}/~cddb/cddb.cgi".format(freedb_server, freedb_port),
urlencode(POST).encode("UTF-8") if (version_info[0] >= 3) else
urlencode(POST))
urlencode(POST).encode())
except URLError as e:
raise ValueError(str(e))
try:

View File

@@ -18,7 +18,6 @@
# You should have received a copy of the GNU General Public License
# along with whipper. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import logging
import sys
@@ -484,7 +483,7 @@ class SyncRunner(TaskRunner, ITaskListener):
self._task.addListener(self)
# only start the task after going into the mainloop,
# otherwise the task might complete before we are in it
GLib.timeout_add(0L, self._startWrap, self._task)
GLib.timeout_add(0, self._startWrap, self._task)
self.debug('run loop')
self._loop.run()
@@ -525,7 +524,7 @@ class SyncRunner(TaskRunner, ITaskListener):
self.stopped(task)
raise
GLib.timeout_add(int(delta * 1000L), c)
GLib.timeout_add(int(delta * 1000), c)
# ITaskListener methods
def progressed(self, task, value):

View File

@@ -69,9 +69,9 @@ class CueFile(object):
def __init__(self, path):
"""
:type path: unicode
:type path: str
"""
assert isinstance(path, unicode), "%r is not unicode" % path
assert isinstance(path, str), "%r is not str" % path
self._path = path
self._rems = {}
@@ -137,9 +137,9 @@ class CueFile(object):
minutes = int(m.expand('\\2'))
seconds = int(m.expand('\\3'))
frames = int(m.expand('\\4'))
frameOffset = frames \
+ seconds * common.FRAMES_PER_SECOND \
+ minutes * common.FRAMES_PER_SECOND * 60
frameOffset = int(frames
+ seconds * common.FRAMES_PER_SECOND
+ minutes * common.FRAMES_PER_SECOND * 60)
logger.debug('found index %d of track %r in %r:%d',
indexNumber, currentTrack, currentFile.path,
@@ -182,7 +182,7 @@ class CueFile(object):
"""
Translate the .cue's FILE to an existing path.
:type path: unicode
:type path: str
"""
return common.getRealPath(self._path, path)
@@ -194,9 +194,9 @@ class File:
def __init__(self, path, file_format):
"""
:type path: unicode
:type path: str
"""
assert isinstance(path, unicode), "%r is not unicode" % path
assert isinstance(path, str), "%r is not str" % path
self.path = path
self.format = file_format

View File

@@ -43,10 +43,10 @@ class Image(object):
def __init__(self, path):
"""
:type path: unicode
:type path: str
:param path: .cue path
"""
assert isinstance(path, unicode), "%r is not unicode" % path
assert isinstance(path, str), "%r is not str" % path
self._path = path
self.cue = cue.CueFile(path)
@@ -62,7 +62,7 @@ class Image(object):
:param path: .cue path
"""
assert isinstance(path, unicode), "%r is not unicode" % path
assert isinstance(path, str), "%r is not str" % path
return self.cue.getRealPath(path)
@@ -130,7 +130,7 @@ class ImageVerifyTask(task.MultiSeparateTask):
htoa = cue.table.tracks[0].indexes[0]
track = cue.table.tracks[0]
path = image.getRealPath(htoa.path)
assert isinstance(path, unicode), "%r is not unicode" % path
assert isinstance(path, str), "%r is not str" % path
logger.debug('schedule scan of audio length of %r', path)
taskk = AudioLengthTask(path)
self.addTask(taskk)
@@ -145,7 +145,7 @@ class ImageVerifyTask(task.MultiSeparateTask):
if length == -1:
path = image.getRealPath(index.path)
assert isinstance(path, unicode), "%r is not unicode" % path
assert isinstance(path, str), "%r is not str" % path
logger.debug('schedule scan of audio length of %r', path)
taskk = AudioLengthTask(path)
self.addTask(taskk)
@@ -192,7 +192,7 @@ class ImageEncodeTask(task.MultiSeparateTask):
def add(index):
path = image.getRealPath(index.path)
assert isinstance(path, unicode), "%r is not unicode" % path
assert isinstance(path, str), "%r is not str" % path
logger.debug('schedule encode of %r', path)
root, _ = os.path.splitext(os.path.basename(path))
outpath = os.path.join(outdir, root + '.' + 'flac')

View File

@@ -23,8 +23,7 @@ Wrap Table of Contents.
"""
import copy
import urllib
import urlparse
from urllib.parse import urlunparse, urlencode
import whipper
@@ -66,7 +65,7 @@ class Track:
:vartype isrc: str
:cvar cdtext: dictionary of CD Text information;
:any:`see CDTEXT_KEYS`
:vartype cdtext: str -> unicode
:vartype cdtext: str
:cvar pre_emphasis: whether track is pre-emphasised
:vartype pre_emphasis: bool
"""
@@ -91,10 +90,10 @@ class Track:
def index(self, number, absolute=None, path=None, relative=None,
counter=None):
"""
:type path: unicode or None
:type path: str or None
"""
if path is not None:
assert isinstance(path, unicode), "%r is not unicode" % path
assert isinstance(path, str), "%r is not str" % path
i = Index(number, absolute, path, relative, counter)
self.indexes[number] = i
@@ -133,7 +132,7 @@ class Index:
"""
:cvar counter: counter for the index source; distinguishes between
the matching FILE lines in .cue files for example
:vartype path: unicode or None
:vartype path: str or None
"""
number = None
absolute = None
@@ -145,7 +144,7 @@ class Index:
counter=None):
if path is not None:
assert isinstance(path, unicode), "%r is not unicode" % path
assert isinstance(path, str), "%r is not str" % path
self.number = number
self.absolute = absolute
@@ -221,9 +220,10 @@ class Table(object):
# if on a session border, subtract the session leadin
thisTrack = self.tracks[number - 1]
nextTrack = self.tracks[number]
if nextTrack.session > thisTrack.session:
gap = self._getSessionGap(nextTrack.session)
end -= gap
if None not in [thisTrack.session, nextTrack.session]:
if nextTrack.session > thisTrack.session:
gap = self._getSessionGap(nextTrack.session)
end -= gap
return end
@@ -297,8 +297,8 @@ class Table(object):
# FIXME: we can't replace these calculations with the getFrameLength
# call because the start and leadout in the algorithm get rounded
# before making the difference
startSeconds = self.getTrackStart(1) / common.FRAMES_PER_SECOND
leadoutSeconds = leadout / common.FRAMES_PER_SECOND
startSeconds = self.getTrackStart(1) // common.FRAMES_PER_SECOND
leadoutSeconds = leadout // common.FRAMES_PER_SECOND
t = leadoutSeconds - startSeconds
# durationFrames = self.getFrameLength(data=True)
# duration = durationFrames / common.FRAMES_PER_SECOND
@@ -348,12 +348,12 @@ class Table(object):
sha = sha1()
# number of first track
sha.update("%02X" % values[0])
sha.update(("%02X" % values[0]).encode())
# number of last track
sha.update("%02X" % values[1])
sha.update(("%02X" % values[1]).encode())
sha.update("%08X" % values[2])
sha.update(("%08X" % values[2]).encode())
# offsets of tracks
for i in range(1, 100):
@@ -361,7 +361,7 @@ class Table(object):
offset = values[2 + i]
except IndexError:
offset = 0
sha.update("%08X" % offset)
sha.update(("%08X" % offset).encode())
digest = sha.digest()
assert len(digest) == 20, \
@@ -372,10 +372,10 @@ class Table(object):
# (Rob) used ., _, and -
# base64 altchars specify replacements for + and /
result = base64.b64encode(digest, '._')
result = base64.b64encode(digest, b'._').decode()
# now replace =
result = "-".join(result.split("="))
result = result.replace("=", "-")
assert len(result) == 28, \
"Result should be 28 characters, not %d" % len(result)
@@ -389,13 +389,13 @@ class Table(object):
discid = self.getMusicBrainzDiscId()
values = self._getMusicBrainzValues()
query = urllib.urlencode({
query = urlencode({
'id': discid,
'toc': ' '.join([str(v) for v in values]),
'tracks': self.getAudioTracks(),
})
return urlparse.urlunparse((
return urlunparse((
'https', host, '/cdtoc/attach', '', query, ''))
def getFrameLength(self, data=False):
@@ -477,7 +477,7 @@ class Table(object):
Dump our internal representation to a .cue file content.
:rtype: unicode
:rtype: str
"""
logger.debug('generating .cue for cuePath %r', cuePath)

View File

@@ -138,9 +138,9 @@ class TocFile(object):
def __init__(self, path):
"""
:type path: unicode
:type path: str
"""
assert isinstance(path, unicode), "%r is not unicode" % path
assert isinstance(path, str), "%r is not string" % path
self._path = path
self._messages = []
self.table = table.Table()
@@ -202,7 +202,7 @@ class TocFile(object):
# usually, value is encoded with octal escapes and in latin-1
# FIXME: other encodings are possible, does cdrdao handle
# them ?
value = value.decode('string-escape').decode('latin-1')
value = value.encode().decode('unicode_escape')
if key in table.CDTEXT_FIELDS:
# FIXME: consider ISRC separate for now, but this
# is a limitation of our parser approach
@@ -412,7 +412,7 @@ class TocFile(object):
"""
Translate the .toc's FILE to an existing path.
:type path: unicode
:type path: str
"""
return common.getRealPath(self._path, path)
@@ -424,12 +424,12 @@ class File:
def __init__(self, path, start, length):
"""
:type path: unicode
:type path: str
:type start: int
:param start: starting point for the track in this file, in frames
:param length: length for the track in this file, in frames
"""
assert isinstance(path, unicode), "%r is not unicode" % path
assert isinstance(path, str), "%r is not str" % path
self.path = path
self.start = start

View File

@@ -2,4 +2,4 @@ import accuraterip
def accuraterip_checksum(f, track_number, total_tracks):
return accuraterip.compute(f.encode('utf-8'), track_number, total_tracks)
return accuraterip.compute(f, track_number, total_tracks)

View File

@@ -220,7 +220,7 @@ class ReadTrackTask(task.Task):
Read the given track.
:param path: where to store the ripped track
:type path: unicode
:type path: str
:param table: table of contents of CD
:type table: table.Table
:param start: first frame to rip
@@ -236,7 +236,7 @@ class ReadTrackTask(task.Task):
:param what: a string representing what's being read; e.g. Track
:type what: str
"""
assert isinstance(path, unicode), "%r is not unicode" % path
assert isinstance(path, str), "%r is not str" % path
self.path = path
self._table = table
@@ -314,7 +314,7 @@ class ReadTrackTask(task.Task):
self.schedule(0.01, self._read, runner)
return
self._buffer += ret
self._buffer += ret.decode()
# parse buffer into lines if possible, and parse them
if "\n" in self._buffer:
@@ -452,7 +452,6 @@ class ReadVerifyTrackTask(task.MultiSeparateTask):
logger.debug('read and verify with taglist %r', taglist)
# FIXME: choose a dir on the same disk/dir as the final path
fd, tmppath = tempfile.mkstemp(suffix='.whipper.wav')
tmppath = unicode(tmppath)
os.fchmod(fd, 0644)
os.close(fd)
self._tmpwavpath = tmppath
@@ -472,13 +471,13 @@ class ReadVerifyTrackTask(task.MultiSeparateTask):
# encode to the final path + '.part'
try:
tmpoutpath = path + u'.part'
tmpoutpath = path + '.part'
open(tmpoutpath, 'wb').close()
except IOError as e:
if errno.ENAMETOOLONG != e.errno:
raise
path = common.truncate_filename(common.shrinkPath(path))
tmpoutpath = common.truncate_filename(path + u'.part')
tmpoutpath = common.truncate_filename(path + '.part')
open(tmpoutpath, 'wb').close()
self._tmppath = tmpoutpath
self.path = path
@@ -597,7 +596,7 @@ class AnalyzeTask(ctask.PopenTask):
def done(self):
if self.cwd:
shutil.rmtree(self.cwd)
output = "".join(self._output)
output = "".join(o.decode() for o in self._output)
m = _OK_RE.search(output)
self.defeatsCache = bool(m)

View File

@@ -84,7 +84,7 @@ class ReadTOCTask(task.Task):
self._parser = ProgressParser()
self.fd, self.tocfile = tempfile.mkstemp(
suffix=u'.cdrdao.read-toc.whipper.task')
suffix='.cdrdao.read-toc.whipper.task')
def start(self, runner):
task.Task.start(self, runner)
@@ -112,7 +112,7 @@ class ReadTOCTask(task.Task):
return
self.schedule(0.01, self._read, runner)
return
self._buffer += ret
self._buffer += ret.decode()
# parse buffer into lines if possible, and parse them
if "\n" in self._buffer:
@@ -168,7 +168,7 @@ def DetectCdr(device):
cmd = [CDRDAO, 'disk-info', '-v1', '--device', device]
logger.debug("executing %r", cmd)
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
return 'CD-R medium : n/a' not in p.stdout.read()
return 'CD-R medium : n/a' not in p.stdout.read().decode()
def version():

View File

@@ -21,11 +21,11 @@ class AudioLengthTask(ctask.PopenTask):
def __init__(self, path):
"""
:type path: unicode
:type path: str
"""
assert isinstance(path, unicode), "%r is not unicode" % path
assert isinstance(path, str), "%r is not str" % path
self.logName = os.path.basename(path).encode('utf-8')
self.logName = os.path.basename(path)
self.command = [SOXI, '-s', path]
@@ -47,4 +47,4 @@ class AudioLengthTask(ctask.PopenTask):
def done(self):
if self._error:
logger.warning("soxi reported on stderr: %s", "".join(self._error))
self.length = int("".join(self._output))
self.length = int("".join(o.decode() for o in self._output))

View File

@@ -83,7 +83,7 @@ class UnicodeTestMixin:
# A helper mixin to skip tests if we're not in a UTF-8 locale
try:
os.stat(u'whipper.test.B\xeate Noire.empty')
os.stat('whipper.test.B\xeate Noire.empty')
except UnicodeEncodeError:
skip = 'No UTF-8 locale'
except OSError:

View File

@@ -1,5 +1,5 @@
# vi:si:et:sw=4:sts=4:ts=4:set fileencoding=utf-8
u"""Tests for whipper.command.mblookup"""
"""Tests for whipper.command.mblookup"""
import os
import pickle
@@ -9,22 +9,22 @@ from whipper.command import mblookup
class MBLookupTestCase(unittest.TestCase):
u"""Test cases for whipper.command.mblookup.MBLookup"""
"""Test cases for whipper.command.mblookup.MBLookup"""
@staticmethod
def _mock_musicbrainz(discid, country=None, record=False):
u"""Mock function for whipper.common.mbngs.musicbrainz function."""
filename = u"whipper.discid.{}.pickle".format(discid)
"""Mock function for whipper.common.mbngs.musicbrainz function."""
filename = "whipper.discid.{}.pickle".format(discid)
path = os.path.join(os.path.dirname(__file__), filename)
with open(path) as p:
return pickle.load(p)
def testMissingReleaseType(self):
u"""Test that lookup for release without a type set doesn't fail."""
"""Test that lookup for release without a type set doesn't fail."""
# Using: Gustafsson, Österberg & Cowle - What's Up? 8 (disc 4)
# https://musicbrainz.org/release/d8e6153a-2c47-4804-9d73-0aac1081c3b1
mblookup.musicbrainz = self._mock_musicbrainz
discid = u"xu338_M8WukSRi0J.KTlDoflB8Y-"
discid = "xu338_M8WukSRi0J.KTlDoflB8Y-"
# https://musicbrainz.org/cdtoc/xu338_M8WukSRi0J.KTlDoflB8Y-
lookup = mblookup.MBLookup([discid], u'whipper mblookup', None)
lookup = mblookup.MBLookup([discid], 'whipper mblookup', None)
lookup.do()

View File

@@ -12,7 +12,7 @@ from whipper.test import common as tcommon
class ShrinkTestCase(tcommon.TestCase):
def testSufjan(self):
path = (u'whipper/Sufjan Stevens - Illinois/02. Sufjan Stevens - '
path = ('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 '
@@ -52,7 +52,7 @@ class GetRelativePathTestCase(tcommon.TestCase):
class GetRealPathTestCase(tcommon.TestCase):
def testRealWithBackslash(self):
fd, path = tempfile.mkstemp(suffix=u'back\\slash.flac')
fd, path = tempfile.mkstemp(suffix='back\\slash.flac')
refPath = os.path.join(os.path.dirname(path), 'fake.cue')
self.assertEqual(common.getRealPath(refPath, path), path)

View File

@@ -12,7 +12,7 @@ from whipper.test import common as tcommon
class ConfigTestCase(tcommon.TestCase):
def setUp(self):
fd, self._path = tempfile.mkstemp(suffix=u'.whipper.test.config')
fd, self._path = tempfile.mkstemp(suffix='.whipper.test.config')
os.close(fd)
self._config = config.Config(self._path)

View File

@@ -37,10 +37,10 @@ class MetadataTestCase(unittest.TestCase):
metadata = mbngs._getMetadata(response['release'], discid)
self.assertEqual(metadata.artist, u'Various Artists')
self.assertEqual(metadata.release, u'2001-10-15')
self.assertEqual(metadata.artist, 'Various Artists')
self.assertEqual(metadata.release, '2001-10-15')
self.assertEqual(metadata.mbidArtist,
[u'89ad4ac3-39f7-470e-963a-56509c546377'])
['89ad4ac3-39f7-470e-963a-56509c546377'])
self.assertEqual(len(metadata.tracks), 18)
@@ -48,11 +48,11 @@ class MetadataTestCase(unittest.TestCase):
self.assertEqual(track16.artist, 'Tom Jones & Stereophonics')
self.assertEqual(track16.mbidArtist, [
u'57c6f649-6cde-48a7-8114-2a200247601a',
u'0bfba3d3-6a04-4779-bb0a-df07df5b0558',
'57c6f649-6cde-48a7-8114-2a200247601a',
'0bfba3d3-6a04-4779-bb0a-df07df5b0558',
])
self.assertEqual(track16.sortName,
u'Jones, Tom & Stereophonics')
'Jones, Tom & Stereophonics')
def testBalladOfTheBrokenSeas(self):
# various artists disc
@@ -65,26 +65,26 @@ class MetadataTestCase(unittest.TestCase):
metadata = mbngs._getMetadata(response['release'], discid)
self.assertEqual(metadata.artist, u'Isobel Campbell & Mark Lanegan')
self.assertEqual(metadata.artist, 'Isobel Campbell & Mark Lanegan')
self.assertEqual(metadata.sortName,
u'Campbell, Isobel & Lanegan, Mark')
self.assertEqual(metadata.release, u'2006-01-30')
'Campbell, Isobel & Lanegan, Mark')
self.assertEqual(metadata.release, '2006-01-30')
self.assertEqual(metadata.mbidArtist, [
u'd51f3a15-12a2-41a0-acfa-33b5eae71164',
u'a9126556-f555-4920-9617-6e013f8228a7',
'd51f3a15-12a2-41a0-acfa-33b5eae71164',
'a9126556-f555-4920-9617-6e013f8228a7',
])
self.assertEqual(len(metadata.tracks), 12)
track12 = metadata.tracks[11]
self.assertEqual(track12.artist, u'Isobel Campbell & Mark Lanegan')
self.assertEqual(track12.artist, 'Isobel Campbell & Mark Lanegan')
self.assertEqual(track12.sortName,
u'Campbell, Isobel'
'Campbell, Isobel'
' & Lanegan, Mark')
self.assertEqual(track12.mbidArtist, [
u'd51f3a15-12a2-41a0-acfa-33b5eae71164',
u'a9126556-f555-4920-9617-6e013f8228a7',
'd51f3a15-12a2-41a0-acfa-33b5eae71164',
'a9126556-f555-4920-9617-6e013f8228a7',
])
def testMalaInCuba(self):
@@ -99,23 +99,23 @@ class MetadataTestCase(unittest.TestCase):
metadata = mbngs._getMetadata(response['release'], discid)
self.assertEqual(metadata.artist, u'Mala')
self.assertEqual(metadata.sortName, u'Mala')
self.assertEqual(metadata.release, u'2012-09-17')
self.assertEqual(metadata.artist, 'Mala')
self.assertEqual(metadata.sortName, 'Mala')
self.assertEqual(metadata.release, '2012-09-17')
self.assertEqual(metadata.mbidArtist,
[u'09f221eb-c97e-4da5-ac22-d7ab7c555bbb'])
['09f221eb-c97e-4da5-ac22-d7ab7c555bbb'])
self.assertEqual(len(metadata.tracks), 14)
track6 = metadata.tracks[5]
self.assertEqual(track6.artist, u'Mala feat. Dreiser & Sexto Sentido')
self.assertEqual(track6.artist, 'Mala feat. Dreiser & Sexto Sentido')
self.assertEqual(track6.sortName,
u'Mala feat. Dreiser & Sexto Sentido')
'Mala feat. Dreiser & Sexto Sentido')
self.assertEqual(track6.mbidArtist, [
u'09f221eb-c97e-4da5-ac22-d7ab7c555bbb',
u'ec07a209-55ff-4084-bc41-9d4d1764e075',
u'f626b92e-07b1-4a19-ad13-c09d690db66c',
'09f221eb-c97e-4da5-ac22-d7ab7c555bbb',
'ec07a209-55ff-4084-bc41-9d4d1764e075',
'f626b92e-07b1-4a19-ad13-c09d690db66c',
])
def testUnknownArtist(self):
@@ -135,28 +135,28 @@ class MetadataTestCase(unittest.TestCase):
discid = "RhrwgVb0hZNkabQCw1dZIhdbMFg-"
metadata = mbngs._getMetadata(response['release'], discid)
self.assertEqual(metadata.artist, u'CunninLynguists')
self.assertEqual(metadata.release, u'2003')
self.assertEqual(metadata.artist, 'CunninLynguists')
self.assertEqual(metadata.release, '2003')
self.assertEqual(metadata.mbidArtist,
[u'69c4cc43-8163-41c5-ac81-30946d27bb69'])
['69c4cc43-8163-41c5-ac81-30946d27bb69'])
self.assertEqual(len(metadata.tracks), 30)
track8 = metadata.tracks[7]
self.assertEqual(track8.artist, u'???')
self.assertEqual(track8.sortName, u'[unknown]')
self.assertEqual(track8.artist, '???')
self.assertEqual(track8.sortName, '[unknown]')
self.assertEqual(track8.mbidArtist,
[u'125ec42a-7229-4250-afc5-e057484327fe'])
['125ec42a-7229-4250-afc5-e057484327fe'])
track9 = metadata.tracks[8]
self.assertEqual(track9.artist, u'CunninLynguists feat. Tonedeff')
self.assertEqual(track9.artist, 'CunninLynguists feat. Tonedeff')
self.assertEqual(track9.sortName,
u'CunninLynguists feat. Tonedeff')
'CunninLynguists feat. Tonedeff')
self.assertEqual(track9.mbidArtist, [
u'69c4cc43-8163-41c5-ac81-30946d27bb69',
u'b3869d83-9fb5-4eac-b5ca-2d155fcbee12'
'69c4cc43-8163-41c5-ac81-30946d27bb69',
'b3869d83-9fb5-4eac-b5ca-2d155fcbee12'
])
def testNenaAndKimWildSingle(self):
@@ -172,40 +172,40 @@ class MetadataTestCase(unittest.TestCase):
discid = "X2c2IQ5vUy5x6Jh7Xi_DGHtA1X8-"
metadata = mbngs._getMetadata(response['release'], discid)
self.assertEqual(metadata.artist, u'Nena & Kim Wilde')
self.assertEqual(metadata.release, u'2003-05-19')
self.assertEqual(metadata.artist, 'Nena & Kim Wilde')
self.assertEqual(metadata.release, '2003-05-19')
self.assertEqual(metadata.mbidArtist, [
u'38bfaa7f-ee98-48cb-acd0-946d7aeecd76',
u'4b462375-c508-432a-8c88-ceeec38b16ae',
'38bfaa7f-ee98-48cb-acd0-946d7aeecd76',
'4b462375-c508-432a-8c88-ceeec38b16ae',
])
self.assertEqual(len(metadata.tracks), 4)
track1 = metadata.tracks[0]
self.assertEqual(track1.artist, u'Nena & Kim Wilde')
self.assertEqual(track1.sortName, u'Nena & Wilde, Kim')
self.assertEqual(track1.artist, 'Nena & Kim Wilde')
self.assertEqual(track1.sortName, 'Nena & Wilde, Kim')
self.assertEqual(track1.mbidArtist, [
u'38bfaa7f-ee98-48cb-acd0-946d7aeecd76',
u'4b462375-c508-432a-8c88-ceeec38b16ae',
'38bfaa7f-ee98-48cb-acd0-946d7aeecd76',
'4b462375-c508-432a-8c88-ceeec38b16ae',
])
self.assertEqual(track1.mbid,
u'1cc96e78-28ed-3820-b0b6-614c35b121ac')
'1cc96e78-28ed-3820-b0b6-614c35b121ac')
self.assertEqual(track1.mbidRecording,
u'fde5622c-ce23-4ebb-975d-51d4a926f901')
'fde5622c-ce23-4ebb-975d-51d4a926f901')
track2 = metadata.tracks[1]
self.assertEqual(track2.artist, u'Nena & Kim Wilde')
self.assertEqual(track2.sortName, u'Nena & Wilde, Kim')
self.assertEqual(track2.artist, 'Nena & Kim Wilde')
self.assertEqual(track2.sortName, 'Nena & Wilde, Kim')
self.assertEqual(track2.mbidArtist, [
u'38bfaa7f-ee98-48cb-acd0-946d7aeecd76',
u'4b462375-c508-432a-8c88-ceeec38b16ae',
'38bfaa7f-ee98-48cb-acd0-946d7aeecd76',
'4b462375-c508-432a-8c88-ceeec38b16ae',
])
self.assertEqual(track2.mbid,
u'f16db4bf-9a34-3d5a-a975-c9375ab7a2ca')
'f16db4bf-9a34-3d5a-a975-c9375ab7a2ca')
self.assertEqual(track2.mbidRecording,
u'5f19758e-7421-4c71-a599-9a9575d8e1b0')
'5f19758e-7421-4c71-a599-9a9575d8e1b0')
def testMissingReleaseGroupType(self):
"""Check that whipper doesn't break if there's no type."""
@@ -233,37 +233,37 @@ class MetadataTestCase(unittest.TestCase):
discid = "cHW1Uutl_kyWNaLJsLmTGTe4rnE-"
metadata = mbngs._getMetadata(response['release'], discid)
self.assertEqual(metadata.artist, u'David Rovics')
self.assertEqual(metadata.sortName, u'Rovics, David')
self.assertEqual(metadata.artist, 'David Rovics')
self.assertEqual(metadata.sortName, 'Rovics, David')
self.assertFalse(metadata.various)
self.assertIsInstance(metadata.tracks, list)
self.assertEqual(metadata.release, u'2015')
self.assertEqual(metadata.releaseTitle, u'The Other Side')
self.assertEqual(metadata.releaseType, u'Album')
self.assertEqual(metadata.release, '2015')
self.assertEqual(metadata.releaseTitle, 'The Other Side')
self.assertEqual(metadata.releaseType, 'Album')
self.assertEqual(metadata.mbid,
u'6109ceed-7e21-490b-b5ad-3a66b4e4cfbb')
'6109ceed-7e21-490b-b5ad-3a66b4e4cfbb')
self.assertEqual(metadata.mbidReleaseGroup,
u'99850b41-a06e-4fb8-992c-75c191a77803')
'99850b41-a06e-4fb8-992c-75c191a77803')
self.assertEqual(metadata.mbidArtist,
[u'4d56eb9f-13b3-4f05-9db7-50195378d49f'])
['4d56eb9f-13b3-4f05-9db7-50195378d49f'])
self.assertEqual(metadata.url,
u'https://musicbrainz.org/release'
'https://musicbrainz.org/release'
'/6109ceed-7e21-490b-b5ad-3a66b4e4cfbb')
self.assertEqual(metadata.catalogNumber, u'[none]')
self.assertEqual(metadata.barcode, u'700261430249')
self.assertEqual(metadata.catalogNumber, '[none]')
self.assertEqual(metadata.barcode, '700261430249')
self.assertEqual(len(metadata.tracks), 16)
track1 = metadata.tracks[0]
self.assertEqual(track1.artist, u'David Rovics')
self.assertEqual(track1.title, u'Waiting for the Hurricane')
self.assertEqual(track1.artist, 'David Rovics')
self.assertEqual(track1.title, 'Waiting for the Hurricane')
self.assertEqual(track1.duration, 176320)
self.assertEqual(track1.mbid,
u'4116eea3-b9c2-452a-8d63-92f1e585b225')
self.assertEqual(track1.sortName, u'Rovics, David')
'4116eea3-b9c2-452a-8d63-92f1e585b225')
self.assertEqual(track1.sortName, 'Rovics, David')
self.assertEqual(track1.mbidArtist,
[u'4d56eb9f-13b3-4f05-9db7-50195378d49f'])
['4d56eb9f-13b3-4f05-9db7-50195378d49f'])
self.assertEqual(track1.mbidRecording,
u'b191794d-b7c6-4d6f-971e-0a543959b5ad')
'b191794d-b7c6-4d6f-971e-0a543959b5ad')
self.assertEqual(track1.mbidWorks,
[u'90d5be68-0b29-45a3-ba01-c27ad78e3625'])
['90d5be68-0b29-45a3-ba01-c27ad78e3625'])

View File

@@ -12,19 +12,19 @@ class FilterTestCase(common.TestCase):
self._filter = path.PathFilter(special=True)
def testSlash(self):
part = u'A Charm/A Blade'
self.assertEqual(self._filter.filter(part), u'A Charm-A Blade')
part = 'A Charm/A Blade'
self.assertEqual(self._filter.filter(part), 'A Charm-A Blade')
def testFat(self):
part = u'A Word: F**k you?'
self.assertEqual(self._filter.filter(part), u'A Word - F__k you_')
part = 'A Word: F**k you?'
self.assertEqual(self._filter.filter(part), 'A Word - F__k you_')
def testSpecial(self):
part = u'<<< $&*!\' "()`{}[]spaceship>>>'
part = '<<< $&*!\' "()`{}[]spaceship>>>'
self.assertEqual(self._filter.filter(part),
u'___ _____ ________spaceship___')
'___ _____ ________spaceship___')
def testGreatest(self):
part = u'Greatest Ever! Soul: The Definitive Collection'
part = 'Greatest Ever! Soul: The Definitive Collection'
self.assertEqual(self._filter.filter(part),
u'Greatest Ever_ Soul - The Definitive Collection')
'Greatest Ever_ Soul - The Definitive Collection')

View File

@@ -13,10 +13,10 @@ class PathTestCase(unittest.TestCase):
def testStandardTemplateEmpty(self):
prog = program.Program(config.Config())
path = prog.getPath(u'/tmp', DEFAULT_DISC_TEMPLATE,
path = prog.getPath('/tmp', DEFAULT_DISC_TEMPLATE,
'mbdiscid', None)
self.assertEqual(path, (u'/tmp/unknown/Unknown Artist - mbdiscid/'
u'Unknown Artist - mbdiscid'))
self.assertEqual(path, ('/tmp/unknown/Unknown Artist - mbdiscid/'
'Unknown Artist - mbdiscid'))
def testStandardTemplateFilled(self):
prog = program.Program(config.Config())
@@ -24,10 +24,10 @@ class PathTestCase(unittest.TestCase):
md.artist = md.sortName = 'Jeff Buckley'
md.title = 'Grace'
path = prog.getPath(u'/tmp', DEFAULT_DISC_TEMPLATE,
path = prog.getPath('/tmp', DEFAULT_DISC_TEMPLATE,
'mbdiscid', md, 0)
self.assertEqual(path, (u'/tmp/unknown/Jeff Buckley - Grace/'
u'Jeff Buckley - Grace'))
self.assertEqual(path, ('/tmp/unknown/Jeff Buckley - Grace/'
'Jeff Buckley - Grace'))
def testIssue66TemplateFilled(self):
prog = program.Program(config.Config())
@@ -35,6 +35,6 @@ class PathTestCase(unittest.TestCase):
md.artist = md.sortName = 'Jeff Buckley'
md.title = 'Grace'
path = prog.getPath(u'/tmp', u'%A/%d', 'mbdiscid', md, 0)
path = prog.getPath('/tmp', '%A/%d', 'mbdiscid', md, 0)
self.assertEqual(path,
u'/tmp/Jeff Buckley/Grace')
'/tmp/Jeff Buckley/Grace')

View File

@@ -16,7 +16,7 @@ class KingsSingleTestCase(unittest.TestCase):
def setUp(self):
self.cue = cue.CueFile(os.path.join(os.path.dirname(__file__),
u'kings-single.cue'))
'kings-single.cue'))
self.cue.parse()
self.assertEqual(len(self.cue.table.tracks), 11)
@@ -32,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'))
'kings-separate.cue'))
self.cue.parse()
self.assertEqual(len(self.cue.table.tracks), 11)
@@ -48,7 +48,7 @@ class KanyeMixedTestCase(unittest.TestCase):
def setUp(self):
self.cue = cue.CueFile(os.path.join(os.path.dirname(__file__),
u'kanye.cue'))
'kanye.cue'))
self.cue.parse()
self.assertEqual(len(self.cue.table.tracks), 13)
@@ -61,24 +61,24 @@ class WriteCueFileTestCase(unittest.TestCase):
@staticmethod
def testWrite():
fd, path = tempfile.mkstemp(suffix=u'.whipper.test.cue')
fd, path = tempfile.mkstemp(suffix='.whipper.test.cue')
os.close(fd)
it = table.Table()
t = table.Track(1)
t.index(1, absolute=0, path=u'track01.wav', relative=0, counter=1)
t.index(1, absolute=0, path='track01.wav', relative=0, counter=1)
it.tracks.append(t)
t = table.Track(2)
t.index(0, absolute=1000, path=u'track01.wav',
t.index(0, absolute=1000, path='track01.wav',
relative=1000, counter=1)
t.index(1, absolute=2000, path=u'track02.wav', relative=0, counter=2)
t.index(1, absolute=2000, path='track02.wav', relative=0, counter=2)
it.tracks.append(t)
it.absolutize()
it.leadout = 3000
common.diffStrings(u"""REM DISCID 0C002802
common.diffStrings("""REM DISCID 0C002802
REM COMMENT "whipper %s"
FILE "track01.wav" WAVE
TRACK 01 AUDIO

View File

@@ -14,7 +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__), 'cure.toc')
self.toc = toc.TocFile(self.path)
self.toc.parse()
self.assertEqual(len(self.toc.table.tracks), 13)
@@ -93,8 +93,8 @@ class CureTestCase(common.TestCase):
'3/c/4/dBAR-013-0019d4c3-00fe8924-b90c650d.bin')
def testGetRealPath(self):
self.assertRaises(KeyError, self.toc.getRealPath, u'track01.wav')
(fd, path) = tempfile.mkstemp(suffix=u'.whipper.test.wav')
self.assertRaises(KeyError, self.toc.getRealPath, 'track01.wav')
(fd, path) = tempfile.mkstemp(suffix='.whipper.test.wav')
self.assertEqual(self.toc.getRealPath(path), path)
winpath = path.replace('/', '\\')
@@ -108,7 +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__), 'bloc.toc')
self.toc = toc.TocFile(self.path)
self.toc.parse()
self.assertEqual(len(self.toc.table.tracks), 13)
@@ -173,7 +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__), 'breeders.toc')
self.toc = toc.TocFile(self.path)
self.toc.parse()
self.assertEqual(len(self.toc.table.tracks), 13)
@@ -200,7 +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__), 'ladyhawke.toc')
self.toc = toc.TocFile(self.path)
self.toc.parse()
self.assertEqual(len(self.toc.table.tracks), 13)
@@ -237,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'))
'capital.1.toc'))
self.toc1.parse()
self.assertEqual(len(self.toc1.table.tracks), 11)
self.assertTrue(self.toc1.table.tracks[-1].audio)
self.toc2 = toc.TocFile(os.path.join(os.path.dirname(__file__),
u'capital.2.toc'))
'capital.2.toc'))
self.toc2.parse()
self.assertEqual(len(self.toc2.table.tracks), 1)
self.assertFalse(self.toc2.table.tracks[-1].audio)
@@ -278,8 +278,8 @@ class UnicodeTestCase(common.TestCase, common.UnicodeTestMixin):
# we copy the normal non-utf8 filename to a utf-8 filename
# in this test because builds with LANG=C fail if we include
# utf-8 filenames in the dist
path = u'Jos\xe9Gonz\xe1lez.toc'
self._performer = u'Jos\xe9 Gonz\xe1lez'
path = 'Jos\xe9Gonz\xe1lez.toc'
self._performer = 'Jos\xe9 Gonz\xe1lez'
source = os.path.join(os.path.dirname(__file__), 'jose.toc')
(fd, self.dest) = tempfile.mkstemp(suffix=path)
os.close(fd)
@@ -311,7 +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__), 'totbl.fast.toc')
self.toc = toc.TocFile(self.path)
self.toc.parse()
self.assertEqual(len(self.toc.table.tracks), 11)
@@ -324,7 +324,7 @@ class GentlemenTestCase(common.TestCase):
def setUp(self):
self.path = os.path.join(os.path.dirname(__file__),
u'gentlemen.fast.toc')
'gentlemen.fast.toc')
self.toc = toc.TocFile(self.path)
self.toc.parse()
self.assertEquals(len(self.toc.table.tracks), 11)
@@ -341,7 +341,7 @@ class StrokesTestCase(common.TestCase):
def setUp(self):
self.path = os.path.join(os.path.dirname(__file__),
u'strokes-someday.toc')
'strokes-someday.toc')
self.toc = toc.TocFile(self.path)
self.toc.parse()
self.assertEqual(len(self.toc.table.tracks), 1)
@@ -358,7 +358,7 @@ class StrokesTestCase(common.TestCase):
self.assertEqual(i1.relative, 0)
self.assertEqual(i1.absolute, 1)
self.assertEqual(i1.counter, 1)
self.assertEqual(i1.path, u'data.wav')
self.assertEqual(i1.path, 'data.wav')
cue = self._filterCue(self.toc.table.cue())
ref = self._filterCue(
@@ -400,7 +400,7 @@ class StrokesTestCase(common.TestCase):
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__), 'surferrosa.toc')
self.toc = toc.TocFile(self.path)
self.toc.parse()
self.assertEqual(len(self.toc.table.tracks), 21)

View File

@@ -8,7 +8,7 @@ from whipper.extern.task import task
from whipper.program.soxi import AudioLengthTask
from whipper.test import common as tcommon
base_track_file = os.path.join(os.path.dirname(__file__), u'track.flac')
base_track_file = os.path.join(os.path.dirname(__file__), 'track.flac')
base_track_length = 10 * common.SAMPLES_PER_FRAME
@@ -39,26 +39,18 @@ class AudioLengthPathTestCase(tcommon.TestCase):
class NormalAudioLengthPathTestCase(AudioLengthPathTestCase):
def testSingleQuote(self):
self._testSuffix(u"whipper.test.Guns 'N Roses.flac")
self._testSuffix("whipper.test.Guns 'N Roses.flac")
def testDoubleQuote(self):
# This test makes sure we can checksum files with double quote in
# their name
self._testSuffix(u'whipper.test.12" edit.flac')
class UnicodeAudioLengthPathTestCase(AudioLengthPathTestCase,
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')
self._testSuffix('whipper.test.12" edit.flac')
class AbsentFileAudioLengthPathTestCase(AudioLengthPathTestCase):
def testAbsentFile(self):
tempdir = tempfile.mkdtemp()
path = os.path.join(tempdir, u"nonexistent.flac")
path = os.path.join(tempdir, "nonexistent.flac")
t = AudioLengthTask(path)
runner = task.SyncRunner()