Fix bugs in the float precision and the currency, increase test coverage (#134)

* Fix some bugs in the float precision and the currency, increase test coverage.

Ref: issue #112 #113

* Update README.rst
This commit is contained in:
Ernesto Rodriguez Ortiz
2017-11-06 20:19:26 -05:00
committed by GitHub
parent 5a131fedc6
commit 1c699d1bb4
15 changed files with 158 additions and 92 deletions

View File

@@ -45,9 +45,11 @@ There's only one function to use::
Besides the numerical argument, there's two optional arguments. Besides the numerical argument, there's two optional arguments.
**to:** The converter to use. Supperted values are **to:** The converter to use. Supperted values are:
* ``cardinal`` (default) * ``cardinal`` (default)
* ``ordinal`` * ``ordinal``
* ``ordinal_num``
* ``year`` * ``year``
* ``currency`` * ``currency``

View File

@@ -73,7 +73,7 @@ CONVERTER_CLASSES = {
} }
CONVERTES_TYPES = ['cardinal', 'ordinal', 'year', 'currency'] CONVERTES_TYPES = ['cardinal', 'ordinal', 'ordinal_num', 'year', 'currency']
def num2words(number, ordinal=False, lang='en', to='cardinal', **kwargs): def num2words(number, ordinal=False, lang='en', to='cardinal', **kwargs):

View File

@@ -18,6 +18,7 @@ from __future__ import unicode_literals
import math import math
from collections import OrderedDict from collections import OrderedDict
from decimal import Decimal
from .compat import to_s from .compat import to_s
@@ -106,6 +107,10 @@ class Num2Word_Base(object):
def float2tuple(self, value): def float2tuple(self, value):
pre = int(value) pre = int(value)
# Simple way of finding decimal places to update the precision
self.precision = abs(Decimal(str(value)).as_tuple().exponent)
post = abs(value - pre) * 10**self.precision post = abs(value - pre) * 10**self.precision
if abs(round(post) - post) < 0.01: if abs(round(post) - post) < 0.01:
# We generally floor all values beyond our precision (rather than # We generally floor all values beyond our precision (rather than

View File

@@ -91,7 +91,7 @@ class Num2Word_ES(Num2Word_EU):
if nnum < 1000000: if nnum < 1000000:
return next return next
ctext = "un" ctext = "un"
elif cnum == 100 and not nnum == 1000: elif cnum == 100 and not nnum % 1000 == 0:
ctext += "t" + self.gender_stem ctext += "t" + self.gender_stem
if nnum < cnum: if nnum < cnum:
@@ -117,7 +117,6 @@ class Num2Word_ES(Num2Word_EU):
def to_ordinal(self, value): def to_ordinal(self, value):
self.verify_ordinal(value) self.verify_ordinal(value)
text = ""
try: try:
if value == 0: if value == 0:
text = "" text = ""
@@ -167,31 +166,10 @@ class Num2Word_ES(Num2Word_EU):
return "%s%s" % (value, "º" if self.gender_stem == 'o' else "ª") return "%s%s" % (value, "º" if self.gender_stem == 'o' else "ª")
def to_currency(self, val, longval=True, old=False): def to_currency(self, val, longval=True, old=False):
hightxt, lowtxt = "euro/s", "centavo/s"
if old: if old:
return self.to_splitnum(val, hightxt="peso/s", lowtxt="peseta/s", hightxt, lowtxt = "peso/s", "peseta/s"
divisor=1000, jointxt="y", longval=longval) result = self.to_splitnum(val, hightxt=hightxt, lowtxt=lowtxt,
return super(Num2Word_ES, self).to_currency(val, jointxt="y", divisor=1, jointxt="y", longval=longval)
longval=longval) # Handle exception, in spanish is "un euro" and not "uno euro"
return result.replace("uno", "un")
n2w = Num2Word_ES()
to_card = n2w.to_cardinal
to_ord = n2w.to_ordinal
to_ordnum = n2w.to_ordinal_num
def main():
for val in [1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155,
180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000,
8280, 8291, 150000, 500000, 1000000, 2000000, 2000001,
-21212121211221211111, -2.121212, -1.0000100]:
n2w.test(val)
n2w.test(13253254360678768017687001076010010122121321432104732075403270573)
print(n2w.to_currency(1222))
print(n2w.to_currency(1222, old=True))
print(n2w.to_year(1222))
if __name__ == "__main__":
main()

View File

@@ -24,28 +24,7 @@ from .lang_ES import Num2Word_ES
class Num2Word_ES_CO(Num2Word_ES): class Num2Word_ES_CO(Num2Word_ES):
def to_currency(self, val, longval=True, old=False): def to_currency(self, val, longval=True, old=False):
return self.to_splitnum(val, hightxt="peso/s", lowtxt="peso/s", result = self.to_splitnum(val, hightxt="peso/s", lowtxt="centavo/s",
divisor=1000, jointxt="y", longval=longval) divisor=1, jointxt="y", longval=longval)
# Handle exception, in spanish is "un euro" and not "uno euro"
return result.replace("uno", "un")
n2w = Num2Word_ES_CO()
to_card = n2w.to_cardinal
to_ord = n2w.to_ordinal
to_ordnum = n2w.to_ordinal_num
def main():
for val in [1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155,
180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000,
8280, 8291, 150000, 500000, 1000000, 2000000, 2000001,
-21212121211221211111, -2.121212, -1.0000100]:
n2w.test(val)
n2w.test(13253254360678768017687001076010010122121321432104732075403270573)
print(n2w.to_currency(1222))
print(n2w.to_currency(1222, old=True))
print(n2w.to_year(1222))
if __name__ == "__main__":
main()

View File

@@ -24,29 +24,10 @@ from .lang_ES import Num2Word_ES
class Num2Word_ES_VE(Num2Word_ES): class Num2Word_ES_VE(Num2Word_ES):
def to_currency(self, val, longval=True, old=False): def to_currency(self, val, longval=True, old=False):
return self.to_splitnum(val, hightxt="bolívar/es Fuerte/s", hightxt = "bolívar/es" if old else "bolívar/es fuerte/s"
lowtxt="bolívar/es fuerte/s", result = self.to_splitnum(
divisor=1000, jointxt="y", longval=longval) val, hightxt=hightxt, lowtxt="centavo/s",
divisor=1, jointxt="y", longval=longval
)
n2w = Num2Word_ES_VE() # Handle exception, in spanish is "un euro" and not "uno euro"
to_card = n2w.to_cardinal return result.replace("uno", "un")
to_ord = n2w.to_ordinal
to_ordnum = n2w.to_ordinal_num
def main():
for val in [1, 11, 12, 21, 31, 33, 71, 80, 81, 91, 99, 100, 101, 102, 155,
180, 300, 308, 832, 1000, 1001, 1061, 1100, 1500, 1701, 3000,
8280, 8291, 150000, 500000, 1000000, 2000000, 2000001,
-21212121211221211111, -2.121212, -1.0000100]:
n2w.test(val)
n2w.test(13253254360678768017687001076010010122121321432104732075403270573)
print(n2w.to_currency(1222))
print(n2w.to_currency(1222, old=True))
print(n2w.to_year(1222))
if __name__ == "__main__":
main()

View File

@@ -25,7 +25,7 @@ setup(
author='Taro Ogawa <tso at users sourceforge net>', author='Taro Ogawa <tso at users sourceforge net>',
author_email='tos@users.sourceforge.net', author_email='tos@users.sourceforge.net',
maintainer='Savoir-faire Linux inc.', maintainer='Savoir-faire Linux inc.',
maintainer_email='virgil.dupras@savoirfairelinux.com', maintainer_email='ernesto.rodriguezortiz@savoirfairelinux.com',
keywords=' number word numbers words convert conversion i18n ' keywords=' number word numbers words convert conversion i18n '
'localisation localization internationalisation ' 'localisation localization internationalisation '
'internationalization', 'internationalization',

View File

@@ -56,7 +56,9 @@ class Num2WordsDETest(TestCase):
self.assertEqual(num2words(4000000000, lang='de'), "vier milliarden") self.assertEqual(num2words(4000000000, lang='de'), "vier milliarden")
def test_cardinal_for_decimal_number(self): def test_cardinal_for_decimal_number(self):
self.assertEqual(num2words(3.486, lang='de'), "drei Komma vier acht") self.assertEqual(
num2words(3.486, lang='de'), "drei Komma vier acht sechs"
)
def test_ordinal_for_negative_numbers(self): def test_ordinal_for_negative_numbers(self):
self.assertRaises(TypeError, num2words, -12, ordinal=True, lang='de') self.assertRaises(TypeError, num2words, -12, ordinal=True, lang='de')

View File

@@ -25,7 +25,7 @@ class Num2WordsENTest(TestCase):
def test_cardinal_for_float_number(self): def test_cardinal_for_float_number(self):
# issue 24 # issue 24
self.assertEqual(num2words(12.50), "twelve point five zero") self.assertEqual(num2words(12.5), "twelve point five")
self.assertEqual(num2words(12.51), "twelve point five one") self.assertEqual(num2words(12.51), "twelve point five one")
self.assertEqual(num2words(12.53), "twelve point five three") self.assertEqual(num2words(12.53), "twelve point five three")
self.assertEqual(num2words(12.59), "twelve point five nine") self.assertEqual(num2words(12.59), "twelve point five nine")

View File

@@ -23,30 +23,36 @@ TEST_CASES_CARDINAL = (
(1, 'uno'), (1, 'uno'),
(2, 'dos'), (2, 'dos'),
(3, 'tres'), (3, 'tres'),
(5.5, 'cinco punto cinco'),
(11, 'once'), (11, 'once'),
(12, 'doce'), (12, 'doce'),
(16, 'dieciseis'), (16, 'dieciseis'),
(17.42, 'diecisiete punto cuatro dos'),
(19, 'diecinueve'), (19, 'diecinueve'),
(20, 'veinte'), (20, 'veinte'),
(21, 'veintiuno'), (21, 'veintiuno'),
(26, 'veintiséis'), (26, 'veintiséis'),
(27.312, 'veintisiete punto tres uno dos'),
(28, 'veintiocho'), (28, 'veintiocho'),
(30, 'treinta'), (30, 'treinta'),
(31, 'treinta y uno'), (31, 'treinta y uno'),
(40, 'cuarenta'), (40, 'cuarenta'),
(44, 'cuarenta y cuatro'), (44, 'cuarenta y cuatro'),
(50, 'cincuenta'), (50, 'cincuenta'),
(53.486, 'cincuenta y tres punto cuatro ocho seis'),
(55, 'cincuenta y cinco'), (55, 'cincuenta y cinco'),
(60, 'sesenta'), (60, 'sesenta'),
(67, 'sesenta y siete'), (67, 'sesenta y siete'),
(70, 'setenta'), (70, 'setenta'),
(79, 'setenta y nueve'), (79, 'setenta y nueve'),
(89, 'ochenta y nueve'),
(95, 'noventa y cinco'),
(100, 'cien'), (100, 'cien'),
(101, 'ciento uno'), (101, 'ciento uno'),
(199, 'ciento noventa y nueve'), (199, 'ciento noventa y nueve'),
(203, 'doscientos tres'), (203, 'doscientos tres'),
(287, 'doscientos ochenta y siete'), (287, 'doscientos ochenta y siete'),
(300, 'trescientos'), (300.42, 'trescientos punto cuatro dos'),
(356, 'trescientos cincuenta y seis'), (356, 'trescientos cincuenta y seis'),
(400, 'cuatrocientos'), (400, 'cuatrocientos'),
(434, 'cuatrocientos treinta y cuatro'), (434, 'cuatrocientos treinta y cuatro'),
@@ -63,6 +69,7 @@ TEST_CASES_CARDINAL = (
(2385, 'dos mil trescientos ochenta y cinco'), (2385, 'dos mil trescientos ochenta y cinco'),
(3766, 'tres mil setecientos sesenta y seis'), (3766, 'tres mil setecientos sesenta y seis'),
(4196, 'cuatro mil ciento noventa y seis'), (4196, 'cuatro mil ciento noventa y seis'),
(4196.42, 'cuatro mil ciento noventa y seis punto cuatro dos'),
(5846, 'cinco mil ochocientos cuarenta y seis'), (5846, 'cinco mil ochocientos cuarenta y seis'),
(6459, 'seis mil cuatrocientos cincuenta y nueve'), (6459, 'seis mil cuatrocientos cincuenta y nueve'),
(7232, 'siete mil doscientos treinta y dos'), (7232, 'siete mil doscientos treinta y dos'),
@@ -70,6 +77,12 @@ TEST_CASES_CARDINAL = (
(9539, 'nueve mil quinientos treinta y nueve'), (9539, 'nueve mil quinientos treinta y nueve'),
(1000000, 'un millón'), (1000000, 'un millón'),
(1000001, 'un millón uno'), (1000001, 'un millón uno'),
(4000000, 'cuatro millones'),
(10000000000000, 'diez billones'),
(100000000000000, 'cien billones'),
(1000000000000000000, 'un trillón'),
(1000000000000000000000, 'mil trillones'),
(10000000000000000000000000, 'diez cuatrillones')
) )
TEST_CASES_ORDINAL = ( TEST_CASES_ORDINAL = (
@@ -79,6 +92,41 @@ TEST_CASES_ORDINAL = (
(14, 'décimo cuarto'), (14, 'décimo cuarto'),
(28, 'vigésimo octavo'), (28, 'vigésimo octavo'),
(100, 'centésimo'), (100, 'centésimo'),
(1000, 'milésimo'),
(1000000, 'millonésimo'),
(1000000000000000, 'cuadrillonésimo'),
(1000000000000000000, 'un trillón') # over 1e18 is not supported
)
TEST_CASES_ORDINAL_NUM = (
(1, ''),
(8, ''),
(12, '12º'),
(14, '14º'),
(28, '28º'),
(100, '100º'),
(1000, '1000º'),
(1000000, '1000000º')
)
TEST_CASES_TO_CURRENCY = (
(1, 'un euro'),
(2, 'dos euros'),
(8, 'ocho euros'),
(12, 'doce euros'),
(21, 'veintiun euros'),
(81.25, 'ochenta y un euros y veinticinco centavos'),
(100, 'cien euros'),
)
TEST_CASES_TO_CURRENCY_OLD = (
(1, 'un peso'),
(2, 'dos pesos'),
(8, 'ocho pesos'),
(12, 'doce pesos'),
(21, 'veintiun pesos'),
(81.25, 'ochenta y un pesos y veinticinco pesetas'),
(100, 'cien pesos'),
) )
@@ -94,3 +142,24 @@ class Num2WordsESTest(TestCase):
num2words(test[0], lang='es', ordinal=True), num2words(test[0], lang='es', ordinal=True),
test[1] test[1]
) )
def test_ordinal_num(self):
for test in TEST_CASES_ORDINAL_NUM:
self.assertEqual(
num2words(test[0], lang='es', to='ordinal_num'),
test[1]
)
def test_currency(self):
for test in TEST_CASES_TO_CURRENCY:
self.assertEqual(
num2words(test[0], lang='es', to='currency'),
test[1]
)
def test_currency_old(self):
for test in TEST_CASES_TO_CURRENCY_OLD:
self.assertEqual(
num2words(test[0], lang='es', to='currency', old=True),
test[1]
)

View File

@@ -20,6 +20,16 @@ from num2words import num2words
from . import test_es from . import test_es
TEST_CASES_TO_CURRENCY = (
(1, 'un peso'),
(2, 'dos pesos'),
(8, 'ocho pesos'),
(12, 'doce pesos'),
(21, 'veintiun pesos'),
(81.25, 'ochenta y un pesos y veinticinco centavos'),
(100, 'cien pesos'),
)
class Num2WordsESCOTest(test_es.Num2WordsESTest): class Num2WordsESCOTest(test_es.Num2WordsESTest):
@@ -33,3 +43,17 @@ class Num2WordsESCOTest(test_es.Num2WordsESTest):
num2words(test[0], lang='es_CO', ordinal=True), num2words(test[0], lang='es_CO', ordinal=True),
test[1] test[1]
) )
def test_ordinal_num(self):
for test in test_es.TEST_CASES_ORDINAL_NUM:
self.assertEqual(
num2words(test[0], lang='es', to='ordinal_num'),
test[1]
)
def test_currency(self):
for test in TEST_CASES_TO_CURRENCY:
self.assertEqual(
num2words(test[0], lang='es_CO', to='currency'),
test[1]
)

View File

@@ -20,6 +20,16 @@ from num2words import num2words
from . import test_es from . import test_es
TEST_CASES_TO_CURRENCY = (
(1, 'un bolívar'),
(2, 'dos bolívares'),
(8, 'ocho bolívares'),
(12, 'doce bolívares'),
(21, 'veintiun bolívares'),
(81.25, 'ochenta y un bolívares y veinticinco centavos'),
(100, 'cien bolívares'),
)
class Num2WordsESVETest(test_es.Num2WordsESTest): class Num2WordsESVETest(test_es.Num2WordsESTest):
@@ -33,3 +43,17 @@ class Num2WordsESVETest(test_es.Num2WordsESTest):
num2words(test[0], lang='es_VE', ordinal=True), num2words(test[0], lang='es_VE', ordinal=True),
test[1] test[1]
) )
def test_ordinal_num(self):
for test in test_es.TEST_CASES_ORDINAL_NUM:
self.assertEqual(
num2words(test[0], lang='es', to='ordinal_num'),
test[1]
)
def test_currency(self):
for test in TEST_CASES_TO_CURRENCY:
self.assertEqual(
num2words(test[0], lang='es_VE', to='currency', old=True),
test[1]
)

View File

@@ -55,7 +55,9 @@ class Num2WordsNLTest(TestCase):
self.assertEqual(num2words(4000000000, lang='nl'), "vier miljard") self.assertEqual(num2words(4000000000, lang='nl'), "vier miljard")
def test_cardinal_for_decimal_number(self): def test_cardinal_for_decimal_number(self):
self.assertEqual(num2words(3.486, lang='nl'), "drie komma vier acht") self.assertEqual(
num2words(3.486, lang='nl'), "drie komma vier acht zes"
)
def test_ordinal_for_negative_numbers(self): def test_ordinal_for_negative_numbers(self):
self.assertRaises(TypeError, num2words, -12, ordinal=True, lang='nl') self.assertRaises(TypeError, num2words, -12, ordinal=True, lang='nl')

View File

@@ -105,14 +105,14 @@ class Num2WordsPTBRTest(TestCase):
self.assertEqual(num2words( self.assertEqual(num2words(
Decimal('1.01'), lang='pt_BR'), 'um vírgula zero um') Decimal('1.01'), lang='pt_BR'), 'um vírgula zero um')
self.assertEqual(num2words( self.assertEqual(num2words(
Decimal('1.035'), lang='pt_BR'), 'um vírgula zero três' Decimal('1.035'), lang='pt_BR'), 'um vírgula zero três cinco'
) )
self.assertEqual(num2words( self.assertEqual(num2words(
Decimal('1.35'), lang='pt_BR'), 'um vírgula três cinco' Decimal('1.35'), lang='pt_BR'), 'um vírgula três cinco'
) )
self.assertEqual( self.assertEqual(
num2words(Decimal('3.14159'), lang='pt_BR'), num2words(Decimal('3.14159'), lang='pt_BR'),
'três vírgula um quatro' 'três vírgula um quatro um cinco nove'
) )
self.assertEqual( self.assertEqual(
num2words(Decimal('101.22'), lang='pt_BR'), num2words(Decimal('101.22'), lang='pt_BR'),
@@ -332,14 +332,14 @@ class Num2WordsPTBRTest(TestCase):
self.n2w.to_currency(Decimal('1.01')), 'um real e um centavo' self.n2w.to_currency(Decimal('1.01')), 'um real e um centavo'
) )
self.assertEqual( self.assertEqual(
self.n2w.to_currency(Decimal('1.035')), 'um real e três centavos' self.n2w.to_currency(Decimal('1.03')), 'um real e três centavos'
) )
self.assertEqual( self.assertEqual(
self.n2w.to_currency(Decimal('1.35')), self.n2w.to_currency(Decimal('1.35')),
'um real e trinta e cinco centavos' 'um real e trinta e cinco centavos'
) )
self.assertEqual( self.assertEqual(
self.n2w.to_currency(Decimal('3.14159')), self.n2w.to_currency(Decimal('3.14')),
'três reais e catorze centavos' 'três reais e catorze centavos'
) )
self.assertEqual( self.assertEqual(

View File

@@ -55,7 +55,7 @@ class Num2WordsDETest(TestCase):
self.assertEqual(num2words(4000000000, lang='sl'), "štiri miljarde") self.assertEqual(num2words(4000000000, lang='sl'), "štiri miljarde")
def test_cardinal_for_decimal_number(self): def test_cardinal_for_decimal_number(self):
self.assertEqual(num2words(3.486, lang='sl'), "tri celih štiri osem") self.assertEqual(num2words(3.48, lang='sl'), "tri celih štiri osem")
def test_ordinal_for_negative_numbers(self): def test_ordinal_for_negative_numbers(self):
self.assertRaises(TypeError, num2words, -12, ordinal=True, lang='sl') self.assertRaises(TypeError, num2words, -12, ordinal=True, lang='sl')