diff --git a/README.rst b/README.rst index 3ac5f37..8a7c96a 100644 --- a/README.rst +++ b/README.rst @@ -45,9 +45,11 @@ There's only one function to use:: 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) * ``ordinal`` +* ``ordinal_num`` * ``year`` * ``currency`` diff --git a/num2words/__init__.py b/num2words/__init__.py index 208be76..04da9c2 100644 --- a/num2words/__init__.py +++ b/num2words/__init__.py @@ -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): diff --git a/num2words/base.py b/num2words/base.py index 96d1912..5b3657f 100644 --- a/num2words/base.py +++ b/num2words/base.py @@ -18,6 +18,7 @@ from __future__ import unicode_literals import math from collections import OrderedDict +from decimal import Decimal from .compat import to_s @@ -106,6 +107,10 @@ class Num2Word_Base(object): def float2tuple(self, 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 if abs(round(post) - post) < 0.01: # We generally floor all values beyond our precision (rather than diff --git a/num2words/lang_ES.py b/num2words/lang_ES.py index c3f6095..be8969b 100644 --- a/num2words/lang_ES.py +++ b/num2words/lang_ES.py @@ -91,7 +91,7 @@ class Num2Word_ES(Num2Word_EU): if nnum < 1000000: return next ctext = "un" - elif cnum == 100 and not nnum == 1000: + elif cnum == 100 and not nnum % 1000 == 0: ctext += "t" + self.gender_stem if nnum < cnum: @@ -117,7 +117,6 @@ class Num2Word_ES(Num2Word_EU): def to_ordinal(self, value): self.verify_ordinal(value) - text = "" try: if value == 0: text = "" @@ -167,31 +166,10 @@ class Num2Word_ES(Num2Word_EU): return "%s%s" % (value, "º" if self.gender_stem == 'o' else "ª") def to_currency(self, val, longval=True, old=False): + hightxt, lowtxt = "euro/s", "centavo/s" if old: - return self.to_splitnum(val, hightxt="peso/s", lowtxt="peseta/s", - divisor=1000, jointxt="y", longval=longval) - return super(Num2Word_ES, self).to_currency(val, jointxt="y", - longval=longval) - - -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() + hightxt, lowtxt = "peso/s", "peseta/s" + result = self.to_splitnum(val, hightxt=hightxt, lowtxt=lowtxt, + divisor=1, jointxt="y", longval=longval) + # Handle exception, in spanish is "un euro" and not "uno euro" + return result.replace("uno", "un") diff --git a/num2words/lang_ES_CO.py b/num2words/lang_ES_CO.py index a7e03bd..6ed0a4b 100644 --- a/num2words/lang_ES_CO.py +++ b/num2words/lang_ES_CO.py @@ -24,28 +24,7 @@ from .lang_ES import Num2Word_ES class Num2Word_ES_CO(Num2Word_ES): def to_currency(self, val, longval=True, old=False): - return self.to_splitnum(val, hightxt="peso/s", lowtxt="peso/s", - divisor=1000, jointxt="y", longval=longval) - - -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() + result = self.to_splitnum(val, hightxt="peso/s", lowtxt="centavo/s", + divisor=1, jointxt="y", longval=longval) + # Handle exception, in spanish is "un euro" and not "uno euro" + return result.replace("uno", "un") diff --git a/num2words/lang_ES_VE.py b/num2words/lang_ES_VE.py index 10c2217..bb93b87 100644 --- a/num2words/lang_ES_VE.py +++ b/num2words/lang_ES_VE.py @@ -24,29 +24,10 @@ from .lang_ES import Num2Word_ES class Num2Word_ES_VE(Num2Word_ES): def to_currency(self, val, longval=True, old=False): - return self.to_splitnum(val, hightxt="bolívar/es Fuerte/s", - lowtxt="bolívar/es fuerte/s", - divisor=1000, jointxt="y", longval=longval) - - -n2w = Num2Word_ES_VE() -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() + hightxt = "bolívar/es" if old else "bolívar/es fuerte/s" + result = self.to_splitnum( + val, hightxt=hightxt, lowtxt="centavo/s", + divisor=1, jointxt="y", longval=longval + ) + # Handle exception, in spanish is "un euro" and not "uno euro" + return result.replace("uno", "un") diff --git a/setup.py b/setup.py index deda731..648fe40 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ setup( author='Taro Ogawa ', author_email='tos@users.sourceforge.net', 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 ' 'localisation localization internationalisation ' 'internationalization', diff --git a/tests/test_de.py b/tests/test_de.py index 4865c26..b4e9e9e 100644 --- a/tests/test_de.py +++ b/tests/test_de.py @@ -56,7 +56,9 @@ class Num2WordsDETest(TestCase): self.assertEqual(num2words(4000000000, lang='de'), "vier milliarden") 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): self.assertRaises(TypeError, num2words, -12, ordinal=True, lang='de') diff --git a/tests/test_en.py b/tests/test_en.py index fe4c77c..fa78b3a 100644 --- a/tests/test_en.py +++ b/tests/test_en.py @@ -25,7 +25,7 @@ class Num2WordsENTest(TestCase): def test_cardinal_for_float_number(self): # 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.53), "twelve point five three") self.assertEqual(num2words(12.59), "twelve point five nine") diff --git a/tests/test_es.py b/tests/test_es.py index ab008f9..1c64854 100644 --- a/tests/test_es.py +++ b/tests/test_es.py @@ -23,30 +23,36 @@ TEST_CASES_CARDINAL = ( (1, 'uno'), (2, 'dos'), (3, 'tres'), + (5.5, 'cinco punto cinco'), (11, 'once'), (12, 'doce'), (16, 'dieciseis'), + (17.42, 'diecisiete punto cuatro dos'), (19, 'diecinueve'), (20, 'veinte'), (21, 'veintiuno'), (26, 'veintiséis'), + (27.312, 'veintisiete punto tres uno dos'), (28, 'veintiocho'), (30, 'treinta'), (31, 'treinta y uno'), (40, 'cuarenta'), (44, 'cuarenta y cuatro'), (50, 'cincuenta'), + (53.486, 'cincuenta y tres punto cuatro ocho seis'), (55, 'cincuenta y cinco'), (60, 'sesenta'), (67, 'sesenta y siete'), (70, 'setenta'), (79, 'setenta y nueve'), + (89, 'ochenta y nueve'), + (95, 'noventa y cinco'), (100, 'cien'), (101, 'ciento uno'), (199, 'ciento noventa y nueve'), (203, 'doscientos tres'), (287, 'doscientos ochenta y siete'), - (300, 'trescientos'), + (300.42, 'trescientos punto cuatro dos'), (356, 'trescientos cincuenta y seis'), (400, 'cuatrocientos'), (434, 'cuatrocientos treinta y cuatro'), @@ -63,6 +69,7 @@ TEST_CASES_CARDINAL = ( (2385, 'dos mil trescientos ochenta y cinco'), (3766, 'tres mil setecientos sesenta 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'), (6459, 'seis mil cuatrocientos cincuenta y nueve'), (7232, 'siete mil doscientos treinta y dos'), @@ -70,6 +77,12 @@ TEST_CASES_CARDINAL = ( (9539, 'nueve mil quinientos treinta y nueve'), (1000000, 'un millón'), (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 = ( @@ -79,6 +92,41 @@ TEST_CASES_ORDINAL = ( (14, 'décimo cuarto'), (28, 'vigésimo octavo'), (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, '1º'), + (8, '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), 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] + ) diff --git a/tests/test_es_co.py b/tests/test_es_co.py index 4482885..5df2bf7 100644 --- a/tests/test_es_co.py +++ b/tests/test_es_co.py @@ -20,6 +20,16 @@ from num2words import num2words 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): @@ -33,3 +43,17 @@ class Num2WordsESCOTest(test_es.Num2WordsESTest): num2words(test[0], lang='es_CO', ordinal=True), 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] + ) diff --git a/tests/test_es_ve.py b/tests/test_es_ve.py index b36bba2..42f35f6 100644 --- a/tests/test_es_ve.py +++ b/tests/test_es_ve.py @@ -20,6 +20,16 @@ from num2words import num2words 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): @@ -33,3 +43,17 @@ class Num2WordsESVETest(test_es.Num2WordsESTest): num2words(test[0], lang='es_VE', ordinal=True), 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] + ) diff --git a/tests/test_nl.py b/tests/test_nl.py index 90f274a..d8dbd1d 100644 --- a/tests/test_nl.py +++ b/tests/test_nl.py @@ -55,7 +55,9 @@ class Num2WordsNLTest(TestCase): self.assertEqual(num2words(4000000000, lang='nl'), "vier miljard") 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): self.assertRaises(TypeError, num2words, -12, ordinal=True, lang='nl') diff --git a/tests/test_pt_BR.py b/tests/test_pt_BR.py index 653f1c7..e968f14 100644 --- a/tests/test_pt_BR.py +++ b/tests/test_pt_BR.py @@ -105,14 +105,14 @@ class Num2WordsPTBRTest(TestCase): self.assertEqual(num2words( Decimal('1.01'), lang='pt_BR'), 'um vírgula zero um') 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( Decimal('1.35'), lang='pt_BR'), 'um vírgula três cinco' ) self.assertEqual( num2words(Decimal('3.14159'), lang='pt_BR'), - 'três vírgula um quatro' + 'três vírgula um quatro um cinco nove' ) self.assertEqual( 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.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.n2w.to_currency(Decimal('1.35')), 'um real e trinta e cinco centavos' ) self.assertEqual( - self.n2w.to_currency(Decimal('3.14159')), + self.n2w.to_currency(Decimal('3.14')), 'três reais e catorze centavos' ) self.assertEqual( diff --git a/tests/test_sl.py b/tests/test_sl.py index 3fe5ac7..02351f2 100644 --- a/tests/test_sl.py +++ b/tests/test_sl.py @@ -55,7 +55,7 @@ class Num2WordsDETest(TestCase): self.assertEqual(num2words(4000000000, lang='sl'), "štiri miljarde") 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): self.assertRaises(TypeError, num2words, -12, ordinal=True, lang='sl')