Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Ionuț Ciocîrlan
2013-06-17 21:50:47 +03:00
11 changed files with 554 additions and 85 deletions

View File

@@ -20,6 +20,8 @@
from PyQt4 import QtCore
import os.path
import re
from picard import log
from picard.util import webbrowser2
class FileLookup(object):
@@ -33,7 +35,9 @@ class FileLookup(object):
return str(QtCore.QUrl.toPercentEncoding(text))
def launch(self, url):
log.debug("webbrowser2: %s" % url)
webbrowser2.open(url)
return True
def discLookup(self, url):
return self.launch("%s&tport=%d" % (url, self.localPort))
@@ -56,11 +60,34 @@ class FileLookup(object):
def artistLookup(self, artist_id):
return self._lookup('artist', artist_id)
def mbidLookup(self, string, type_):
"""Parses string for known entity type and mbid, open browser for it
If entity type is 'release', it will load corresponding release if
possible.
"""
uuid = '[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}'
entity_type = '(?:release-group|release|recording|work|artist|label|url|area|track)'
regex = r"\b(%s)?\W*(%s)" % (entity_type, uuid)
m = re.search(regex, string, re.IGNORECASE)
if m is None:
return False
if m.group(1) is None:
entity = type_
else:
entity = m.group(1).lower()
mbid = m.group(2).lower()
if entity == 'release':
QtCore.QObject.tagger.load_album(mbid)
return True
return self._lookup(entity, mbid)
def _search(self, type_, query, adv=False):
if self.mbidLookup(query, type_):
return True
url = "http://%s:%d/search/textsearch?limit=25&type=%s&query=%s&tport=%d" % (
self._encode(self.server),
self.port,
type_,
type_,
self._encode(query),
self.localPort)
if adv:

65
picard/i18n.py Normal file
View File

@@ -0,0 +1,65 @@
import gettext
import locale
import os.path
import sys
import __builtin__
__builtin__.__dict__['N_'] = lambda a: a
def setup_gettext(localedir, ui_language=None, logdebug=None):
"""Setup locales, load translations, install gettext functions."""
current_locale = ''
if ui_language:
os.environ['LANGUAGE'] = ''
os.environ['LANG'] = ui_language
try:
current_locale = locale.normalize(ui_language)
locale.setlocale(locale.LC_ALL, current_locale)
except:
pass
if sys.platform == "win32":
try:
locale.setlocale(locale.LC_ALL, os.environ["LANG"])
except KeyError:
os.environ["LANG"] = locale.getdefaultlocale()[0]
try:
current_locale = locale.setlocale(locale.LC_ALL, "")
except:
pass
except:
pass
elif not ui_language:
if sys.platform == "darwin":
try:
import Foundation
defaults = Foundation.NSUserDefaults.standardUserDefaults()
os.environ["LANG"] = \
defaults.objectForKey_("AppleLanguages")[0]
except:
pass
try:
current_locale = locale.setlocale(locale.LC_ALL, "")
except:
pass
if logdebug:
logdebug("Using locale %r", current_locale)
try:
if logdebug:
logdebug("Loading gettext translation, localedir=%r", localedir)
trans = gettext.translation("picard", localedir)
trans.install(True)
_ungettext = trans.ungettext
except IOError:
__builtin__.__dict__['_'] = lambda a: a
def _ungettext(a, b, c):
if c == 1:
return a
else:
return b
__builtin__.__dict__['ungettext'] = _ungettext
if logdebug:
logdebug("_ = %r", _)
logdebug("N_ = %r", N_)
logdebug("ungettext = %r", ungettext)

View File

@@ -55,7 +55,8 @@ def _decamelcase(text):
_REPLACE_MAP = {}
_EXTRA_ATTRS = ['guest', 'additional', 'minor']
def _parse_attributes(attrs):
_BLANK_SPECIAL_RELTYPES = {'vocal': 'vocals'}
def _parse_attributes(attrs, reltype):
attrs = [_decamelcase(_REPLACE_MAP.get(a, a)) for a in attrs]
prefix = ' '.join([a for a in attrs if a in _EXTRA_ATTRS])
attrs = [a for a in attrs if a not in _EXTRA_ATTRS]
@@ -64,7 +65,7 @@ def _parse_attributes(attrs):
elif len(attrs) == 1:
attrs = attrs[0]
else:
attrs = ''
attrs = _BLANK_SPECIAL_RELTYPES.get(reltype, '')
return ' '.join([prefix, attrs]).strip().lower()
@@ -79,7 +80,7 @@ def _relations_to_metadata(relation_lists, m):
if 'attribute_list' in relation.children:
attribs = [a.text for a in relation.attribute_list[0].attribute]
if reltype in ('vocal', 'instrument', 'performer'):
name = 'performer:' + _parse_attributes(attribs)
name = 'performer:' + _parse_attributes(attribs, reltype)
elif reltype == 'mix-DJ' and len(attribs) > 0:
if not hasattr(m, "_djmix_ars"):
m._djmix_ars = {}

View File

@@ -20,8 +20,6 @@
from PyQt4 import QtGui, QtCore
import gettext
import locale
import getopt
import os.path
import shutil
@@ -30,18 +28,6 @@ import sys
from collections import deque
from itertools import chain
# Install gettext "noop" function.
import __builtin__
__builtin__.__dict__['N_'] = lambda a: a
# Py2exe 0.6.6 has broken fake_getline which doesn't work with Python 2.5
if hasattr(sys, "frozen"):
import linecache
def fake_getline(filename, lineno, module_globals = None):
return ''
linecache.getline = fake_getline
del linecache, fake_getline
# A "fix" for http://python.org/sf/1438480
def _patched_shutil_copystat(src, dst):
try: _orig_shutil_copystat(src, dst)
@@ -51,6 +37,7 @@ shutil.copystat = _patched_shutil_copystat
import picard.resources
import picard.plugins
from picard.i18n import setup_gettext
from picard import version_string, log, acoustid, config
from picard.album import Album, NatAlbum
@@ -140,7 +127,7 @@ class Tagger(QtGui.QApplication):
check_io_encoding()
self.setup_gettext(localedir)
setup_gettext(localedir, config.setting["ui_language"], log.debug)
self.xmlws = XmlWebService()
@@ -198,47 +185,6 @@ class Tagger(QtGui.QApplication):
# default format, disabled
remove_va_file_naming_format(merge=False)
def setup_gettext(self, localedir):
"""Setup locales, load translations, install gettext functions."""
ui_language = config.setting["ui_language"]
if ui_language:
os.environ['LANGUAGE'] = ''
os.environ['LANG'] = ui_language
if sys.platform == "win32":
try:
locale.setlocale(locale.LC_ALL, os.environ["LANG"])
except KeyError:
os.environ["LANG"] = locale.getdefaultlocale()[0]
try:
locale.setlocale(locale.LC_ALL, "")
except:
pass
except:
pass
else:
if sys.platform == "darwin" and not ui_language:
try:
import Foundation
defaults = Foundation.NSUserDefaults.standardUserDefaults()
os.environ["LANG"] = defaults.objectForKey_("AppleLanguages")[0]
except:
pass
try:
locale.setlocale(locale.LC_ALL, "")
except:
pass
try:
log.debug("Loading gettext translation, localedir=%r", localedir)
self.translation = gettext.translation("picard", localedir)
self.translation.install(True)
ungettext = self.translation.ungettext
except IOError:
__builtin__.__dict__['_'] = lambda a: a
def ungettext(a, b, c):
if c == 1: return a
else: return b
__builtin__.__dict__['ungettext'] = ungettext
def move_files_to_album(self, files, albumid=None, album=None):
"""Move `files` to tracks on album `albumid`."""
if album is None:

View File

@@ -19,7 +19,7 @@
import os.path
from PyQt4 import QtGui
from picard.util import format_time, encode_filename
from picard.util import format_time, encode_filename, bytes2human
from picard.ui.ui_infodialog import Ui_InfoDialog
@@ -48,11 +48,17 @@ class InfoDialog(QtGui.QDialog):
for image in images:
data = image["data"]
size = len(data)
item = QtGui.QListWidgetItem()
pixmap = QtGui.QPixmap()
pixmap.loadFromData(data)
icon = QtGui.QIcon(pixmap)
item.setIcon(icon)
s = "%s (%s)\n%d x %d" % (bytes2human.decimal(size),
bytes2human.binary(size),
pixmap.width(),
pixmap.height())
item.setText(s)
self.ui.artwork_list.addItem(item)
def tab_hide(self, widget):
@@ -75,13 +81,8 @@ class FileInfoDialog(InfoDialog):
info.append((_('Format:'), file.orig_metadata['~format']))
try:
size = os.path.getsize(encode_filename(file.filename))
if size < 1024:
size = '%d B' % size
elif size < 1024 * 1024:
size = '%0.1f kB' % (size / 1024.0)
else:
size = '%0.1f MB' % (size / 1024.0 / 1024.0)
info.append((_('Size:'), size))
sizestr = "%s (%s)" % (bytes2human.decimal(size), bytes2human.binary(size))
info.append((_('Size:'), sizestr))
except:
pass
if file.orig_metadata.length:

125
picard/util/bytes2human.py Normal file
View File

@@ -0,0 +1,125 @@
# -*- coding: utf-8 -*-
#
# Picard, the next-generation MusicBrainz tagger
# Copyright (C) 2013 Laurent Monin
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import locale
import picard.i18n
"""
Helper class to convert bytes to human-readable form
It supports i18n through gettext, decimal and binary units.
>>> n = 1572864
>>> [binary(n), decimal(n)]
['1.5 MiB', '1.6 MB']
"""
#used to force gettextization
_BYTES_STRINGS_I18N = (
N_('%s B'),
N_('%s kB'),
N_('%s KiB'),
N_('%s MB'),
N_('%s MiB'),
N_('%s GB'),
N_('%s GiB'),
N_('%s TB'),
N_('%s TiB'),
N_('%s PB'),
N_('%s PiB'),
)
def decimal(number, prec=1):
"""
Convert bytes to short human-readable string, decimal mode
>>> [decimal(n) for n in [1000, 1024, 15500]]
['1 kB', '1 kB', '15.5 kB']
"""
return short_string(int(number), 1000)
def binary(number, prec=1):
"""
Convert bytes to short human-readable string, binary mode
>>> [binary(n) for n in [1000, 1024, 15500]]
['1000 B', '1 KiB', '15.1 KiB']
"""
return short_string(int(number), 1024, prec)
def short_string(number, multiple, prec=1):
"""
Returns short human-readable string for `number` bytes
>>> [short_string(n, 1024, 2) for n in [1000, 1100, 15500]]
['1000 B', '1.07 KiB', '15.14 KiB']
>>> [short_string(n, 1000, 1) for n in [10000, 11000, 1550000]]
['10 kB', '11 kB', '1.6 MB']
"""
num, unit = calc_unit(number, multiple)
n = int(num)
nr = round(num, prec)
if n == nr or unit == 'B':
fmt = '%d'
num = n
else:
fmt = '%%0.%df' % prec
num = nr
fmtnum = locale.format(fmt, num)
return _("%s " + unit) % fmtnum
def calc_unit(number, multiple=1000):
"""
Calculate rounded number of multiple * bytes, finding best unit
>>> calc_unit(12456, 1024)
(12.1640625, 'KiB')
>>> calc_unit(-12456, 1000)
(-12.456, 'kB')
>>> calc_unit(0, 1001)
Traceback (most recent call last):
...
ValueError: multiple parameter has to be 1000 or 1024
"""
if number < 0:
sign = -1
number = -number
else:
sign = 1
n = float(number)
if multiple == 1000:
k, b = 'k', 'B'
elif multiple == 1024:
k, b = 'K', 'iB'
else:
raise ValueError('multiple parameter has to be 1000 or 1024')
suffixes = ["B"] + [i + b for i in k + "MGTP"]
for suffix in suffixes:
if n < multiple or suffix == suffixes[-1]:
return (sign*n, suffix)
else:
n /= multiple
if __name__ == "__main__":
import doctest
doctest.testmod()

View File

@@ -51,10 +51,13 @@ class Queue:
self.mutex.unlock()
def remove(self,item):
"""Remove an item into the queue."""
"""Remove an item from the queue."""
self.mutex.lock()
try:
self._remove(item)
self.queue.remove(item)
except ValueError:
pass
else:
self.not_full.wakeOne()
finally:
self.mutex.unlock()
@@ -91,21 +94,6 @@ class Queue:
def _put(self, item):
self.queue.append(item)
# Remove an item from the queue
def _remove(self, item):
if item in self.queue:
try:
# remove is only availible in python 2.5
self.queue.remove(item)
except AttributeError:
# remove items this way in older versions of python.
for i in range(0, len(self.queue)):
if self.queue[i] == item:
self.queue.rotate(-i)
self.queue.popleft()
self.queue.rotate(i)
break
# Get an item from the queue
def _get(self):
return self.queue.popleft()

74
test/data/b2h_test_C.dat Normal file
View File

@@ -0,0 +1,74 @@
0;0 B;0 B;0 B
1;1 B;1 B;1 B
100;100 B;100 B;100 B
102;102 B;102 B;102 B
500;500 B;500 B;500 B
512;512 B;512 B;512 B
990;990 B;990 B;990 B
999;999 B;999 B;999 B
1000;1 kB;1000 B;1000 B
1013;1 kB;1013 B;1013 B
1023;1 kB;1023 B;1023 B
1024;1 kB;1 KiB;1 KiB
1500;1.5 kB;1.5 KiB;1.46 KiB
1536;1.5 kB;1.5 KiB;1.50 KiB
100000;100 kB;97.7 KiB;97.66 KiB
104857;104.9 kB;102.4 KiB;102.40 KiB
500000;500 kB;488.3 KiB;488.28 KiB
524288;524.3 kB;512 KiB;512 KiB
990000;990 kB;966.8 KiB;966.80 KiB
999900;999.9 kB;976.5 KiB;976.46 KiB
1000000;1 MB;976.6 KiB;976.56 KiB
1038090;1 MB;1013.8 KiB;1013.76 KiB
1048471;1 MB;1023.9 KiB;1023.90 KiB
1048576;1 MB;1 MiB;1 MiB
1500000;1.5 MB;1.4 MiB;1.43 MiB
1572864;1.6 MB;1.5 MiB;1.50 MiB
100000000;100 MB;95.4 MiB;95.37 MiB
107374182;107.4 MB;102.4 MiB;102.40 MiB
500000000;500 MB;476.8 MiB;476.84 MiB
536870912;536.9 MB;512 MiB;512 MiB
990000000;990 MB;944.1 MiB;944.14 MiB
999900000;999.9 MB;953.6 MiB;953.58 MiB
1000000000;1 GB;953.7 MiB;953.67 MiB
1063004405;1.1 GB;1013.8 MiB;1013.76 MiB
1073634449;1.1 GB;1023.9 MiB;1023.90 MiB
1073741824;1.1 GB;1 GiB;1 GiB
1500000000;1.5 GB;1.4 GiB;1.40 GiB
1610612736;1.6 GB;1.5 GiB;1.50 GiB
100000000000;100 GB;93.1 GiB;93.13 GiB
109951162777;110.0 GB;102.4 GiB;102.40 GiB
500000000000;500 GB;465.7 GiB;465.66 GiB
549755813888;549.8 GB;512 GiB;512 GiB
990000000000;990 GB;922 GiB;922.01 GiB
999900000000;999.9 GB;931.2 GiB;931.23 GiB
1000000000000;1 TB;931.3 GiB;931.32 GiB
1088516511498;1.1 TB;1013.8 GiB;1013.76 GiB
1099401676613;1.1 TB;1023.9 GiB;1023.90 GiB
1099511627776;1.1 TB;1 TiB;1 TiB
1500000000000;1.5 TB;1.4 TiB;1.36 TiB
1649267441664;1.6 TB;1.5 TiB;1.50 TiB
100000000000000;100 TB;90.9 TiB;90.95 TiB
112589990684262;112.6 TB;102.4 TiB;102.40 TiB
500000000000000;500 TB;454.7 TiB;454.75 TiB
562949953421312;562.9 TB;512 TiB;512 TiB
990000000000000;990 TB;900.4 TiB;900.40 TiB
999900000000000;999.9 TB;909.4 TiB;909.40 TiB
1000000000000000;1 PB;909.5 TiB;909.49 TiB
1114640907774197;1.1 PB;1013.8 TiB;1013.76 TiB
1125787316851939;1.1 PB;1023.9 TiB;1023.90 TiB
1125899906842624;1.1 PB;1 PiB;1 PiB
1500000000000000;1.5 PB;1.3 PiB;1.33 PiB
1688849860263936;1.7 PB;1.5 PiB;1.50 PiB
100000000000000000;100 PB;88.8 PiB;88.82 PiB
115292150460684704;115.3 PB;102.4 PiB;102.40 PiB
500000000000000000;500 PB;444.1 PiB;444.09 PiB
576460752303423488;576.5 PB;512 PiB;512 PiB
990000000000000000;990 PB;879.3 PiB;879.30 PiB
999900000000000000;999.9 PB;888.1 PiB;888.09 PiB
1000000000000000000;1000 PB;888.2 PiB;888.18 PiB
1141392289560778496;1141.4 PB;1013.8 PiB;1013.76 PiB
1152806212456386304;1152.8 PB;1023.9 PiB;1023.90 PiB
1152921504606846976;1152.9 PB;1024 PiB;1024 PiB
1500000000000000000;1500 PB;1332.3 PiB;1332.27 PiB
1729382256910270464;1729.4 PB;1536 PiB;1536 PiB

View File

@@ -0,0 +1,74 @@
0;0 o;0 o;0 o
1;1 o;1 o;1 o
100;100 o;100 o;100 o
102;102 o;102 o;102 o
500;500 o;500 o;500 o
512;512 o;512 o;512 o
990;990 o;990 o;990 o
999;999 o;999 o;999 o
1000;1 ko;1000 o;1000 o
1013;1 ko;1013 o;1013 o
1023;1 ko;1023 o;1023 o
1024;1 ko;1 Kio;1 Kio
1500;1,5 ko;1,5 Kio;1,46 Kio
1536;1,5 ko;1,5 Kio;1,50 Kio
100000;100 ko;97,7 Kio;97,66 Kio
104857;104,9 ko;102,4 Kio;102,40 Kio
500000;500 ko;488,3 Kio;488,28 Kio
524288;524,3 ko;512 Kio;512 Kio
990000;990 ko;966,8 Kio;966,80 Kio
999900;999,9 ko;976,5 Kio;976,46 Kio
1000000;1 Mo;976,6 Kio;976,56 Kio
1038090;1 Mo;1013,8 Kio;1013,76 Kio
1048471;1 Mo;1023,9 Kio;1023,90 Kio
1048576;1 Mo;1 Mio;1 Mio
1500000;1,5 Mo;1,4 Mio;1,43 Mio
1572864;1,6 Mo;1,5 Mio;1,50 Mio
100000000;100 Mo;95,4 Mio;95,37 Mio
107374182;107,4 Mo;102,4 Mio;102,40 Mio
500000000;500 Mo;476,8 Mio;476,84 Mio
536870912;536,9 Mo;512 Mio;512 Mio
990000000;990 Mo;944,1 Mio;944,14 Mio
999900000;999,9 Mo;953,6 Mio;953,58 Mio
1000000000;1 Go;953,7 Mio;953,67 Mio
1063004405;1,1 Go;1013,8 Mio;1013,76 Mio
1073634449;1,1 Go;1023,9 Mio;1023,90 Mio
1073741824;1,1 Go;1 Gio;1 Gio
1500000000;1,5 Go;1,4 Gio;1,40 Gio
1610612736;1,6 Go;1,5 Gio;1,50 Gio
100000000000;100 Go;93,1 Gio;93,13 Gio
109951162777;110,0 Go;102,4 Gio;102,40 Gio
500000000000;500 Go;465,7 Gio;465,66 Gio
549755813888;549,8 Go;512 Gio;512 Gio
990000000000;990 Go;922 Gio;922,01 Gio
999900000000;999,9 Go;931,2 Gio;931,23 Gio
1000000000000;1 To;931,3 Gio;931,32 Gio
1088516511498;1,1 To;1013,8 Gio;1013,76 Gio
1099401676613;1,1 To;1023,9 Gio;1023,90 Gio
1099511627776;1,1 To;1 Tio;1 Tio
1500000000000;1,5 To;1,4 Tio;1,36 Tio
1649267441664;1,6 To;1,5 Tio;1,50 Tio
100000000000000;100 To;90,9 Tio;90,95 Tio
112589990684262;112,6 To;102,4 Tio;102,40 Tio
500000000000000;500 To;454,7 Tio;454,75 Tio
562949953421312;562,9 To;512 Tio;512 Tio
990000000000000;990 To;900,4 Tio;900,40 Tio
999900000000000;999,9 To;909,4 Tio;909,40 Tio
1000000000000000;1 Po;909,5 Tio;909,49 Tio
1114640907774197;1,1 Po;1013,8 Tio;1013,76 Tio
1125787316851939;1,1 Po;1023,9 Tio;1023,90 Tio
1125899906842624;1,1 Po;1 Pio;1 Pio
1500000000000000;1,5 Po;1,3 Pio;1,33 Pio
1688849860263936;1,7 Po;1,5 Pio;1,50 Pio
100000000000000000;100 Po;88,8 Pio;88,82 Pio
115292150460684704;115,3 Po;102,4 Pio;102,40 Pio
500000000000000000;500 Po;444,1 Pio;444,09 Pio
576460752303423488;576,5 Po;512 Pio;512 Pio
990000000000000000;990 Po;879,3 Pio;879,30 Pio
999900000000000000;999,9 Po;888,1 Pio;888,09 Pio
1000000000000000000;1000 Po;888,2 Pio;888,18 Pio
1141392289560778496;1141,4 Po;1013,8 Pio;1013,76 Pio
1152806212456386304;1152,8 Po;1023,9 Pio;1023,90 Pio
1152921504606846976;1152,9 Po;1024 Pio;1024 Pio
1500000000000000000;1500 Po;1332,3 Pio;1332,27 Pio
1729382256910270464;1729,4 Po;1536 Pio;1536 Pio

69
test/po/fr.po Normal file
View File

@@ -0,0 +1,69 @@
msgid ""
msgstr ""
"Project-Id-Version: MusicBrainz\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2013-01-20 13:23+0100\n"
"PO-Revision-Date: 2013-01-20 13:26+0100\n"
"Last-Translator: Laurent Monin <i18n@norz.org>\n"
"Language-Team: French (http://www.transifex.com/projects/p/musicbrainz/language/fr/)\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.6\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: picard/util/bytes2human.py:47
#, python-format
msgid "%s B"
msgstr "%s o"
#: picard/util/bytes2human.py:48
#, python-format
msgid "%s kB"
msgstr "%s ko"
#: picard/util/bytes2human.py:49
#, python-format
msgid "%s KiB"
msgstr "%s Kio"
#: picard/util/bytes2human.py:50
#, python-format
msgid "%s MB"
msgstr "%s Mo"
#: picard/util/bytes2human.py:51
#, python-format
msgid "%s MiB"
msgstr "%s Mio"
#: picard/util/bytes2human.py:52
#, python-format
msgid "%s GB"
msgstr "%s Go"
#: picard/util/bytes2human.py:53
#, python-format
msgid "%s GiB"
msgstr "%s Gio"
#: picard/util/bytes2human.py:54
#, python-format
msgid "%s TB"
msgstr "%s To"
#: picard/util/bytes2human.py:55
#, python-format
msgid "%s TiB"
msgstr "%s Tio"
#: picard/util/bytes2human.py:56
#, python-format
msgid "%s PB"
msgstr "%s Po"
#: picard/util/bytes2human.py:57
#, python-format
msgid "%s PiB"
msgstr "%s Pio"

99
test/test_bytes2human.py Normal file
View File

@@ -0,0 +1,99 @@
import locale
import os.path
import shutil
import subprocess
import sys
import tempfile
import unittest
from picard.i18n import setup_gettext
from picard.util import bytes2human
class Testbytes2human(unittest.TestCase):
def setUp(self):
# we are using temporary locales for tests
self.tmp_path = tempfile.mkdtemp().decode("utf-8")
if sys.hexversion >= 0x020700F0:
self.addCleanup(shutil.rmtree, self.tmp_path)
self.localedir = os.path.join(self.tmp_path, 'locale')
test_locales = [('picard', 'fr', 'test/po/fr.po')]
for domain, locale, po in test_locales:
path = os.path.join(self.localedir, locale, 'LC_MESSAGES')
os.makedirs(path)
mo = os.path.join(path, '%s.mo' % domain)
assert(subprocess.call(['msgfmt', '-o', mo, po]) == 0)
def tearDown(self):
if sys.hexversion < 0x020700F0:
shutil.rmtree(self.tmp_path)
def test_00(self):
# testing with default C locale, english
lang = 'C'
setup_gettext(self.localedir, lang)
self.run_test(lang)
self.assertEqual(bytes2human.binary(45682), '44.6 KiB')
self.assertEqual(bytes2human.binary(-45682), '-44.6 KiB')
self.assertEqual(bytes2human.decimal(45682), '45.7 kB')
self.assertEqual(bytes2human.decimal(9223372036854775807), '9223.4 PB')
self.assertEqual(bytes2human.decimal(123.6), '123 B')
self.assertRaises(ValueError, bytes2human.decimal, 'xxx')
self.assertRaises(ValueError, bytes2human.decimal, '123.6')
self.assertRaises(ValueError, bytes2human.binary, 'yyy')
self.assertRaises(ValueError, bytes2human.binary, '456yyy')
try:
bytes2human.decimal(u'123')
except Exception as e:
self.fail('Unexpected exception: %s' % e)
def test_05(self):
# testing with french locale and translation
# 1.5 MiB -> 1,5 Mio
lang = 'fr_FR.UTF-8'
setup_gettext(self.localedir, lang)
self.run_test(lang)
def run_test(self, lang = 'C', create_test_data=False):
"""
Compare data generated with sample files
Setting create_test_data to True will generated sample files
from code execution (developper-only, check carefully)
"""
filename = os.path.join('test', 'data', 'b2h_test_%s.dat' % lang)
testlist = self._create_testlist()
if create_test_data:
self._save_expected_to(filename, testlist)
expected = self._read_expected_from(filename)
#self.maxDiff = None
self.assertEqual(testlist, expected)
if create_test_data:
# be sure it is disabled
self.fail('!!! UNSET create_test_data mode !!! (%s)' % filename)
def _create_testlist(self):
values = [0, 1]
for n in [1000, 1024]:
p = 1
for e in range(0,6):
p *= n
for x in [0.1, 0.5, 0.99, 0.9999, 1, 1.5]:
values.append(int(p*x))
l = []
for x in sorted(values):
l.append(";".join([str(x), bytes2human.decimal(x),
bytes2human.binary(x),
bytes2human.short_string(x, 1024, 2)]))
return l
def _save_expected_to(self, path, a_list):
with open(path, 'wb') as f:
f.writelines([l + "\n" for l in a_list])
f.close()
def _read_expected_from(self, path):
with open(path, 'rb') as f:
lines = [l.rstrip("\n") for l in f.readlines()]
f.close()
return lines