Refactor and fix some issues with to_currency. Reduce code duplication. (#129)

* Refactor and fix some issues with to_currency. Reduce code duplication.

* Use unicode literals in uk testcase.
This commit is contained in:
Mārtiņš Šulcs
2017-11-01 02:17:13 +02:00
committed by Ernesto Rodriguez Ortiz
parent abae0b56a2
commit f9d8868794
10 changed files with 132 additions and 135 deletions

37
num2words/currency.py Normal file
View File

@@ -0,0 +1,37 @@
from __future__ import division
from decimal import Decimal
def parse_currency_parts(value):
if isinstance(value, int):
# assume cents if value is integer
negative = value < 0
value = abs(value)
integer, cents = divmod(value, 100)
elif isinstance(value, Decimal):
negative = value < 0
value = abs(value)
integer, fraction = divmod(value, 1)
integer = int(integer)
cents = int(fraction * 100)
else:
# @TODO consider using something (babel) that does locale aware parsing
value = str(value).replace(',', '.')
negative = value.startswith('-')
if negative:
value = value.lstrip('-')
if '.' in value:
integer, fraction = value.rsplit('.', 1)
fraction = fraction.ljust(2, "0")
else:
integer, fraction = value, 0
integer = int(integer)
cents = int(fraction)
return integer, cents, negative

View File

@@ -95,6 +95,8 @@ vienas tūkstantis du šimtai trisdešimt keturi eurai, penkiasdešimt šeši ce
"""
from __future__ import unicode_literals
from .currency import parse_currency_parts
ZERO = (u'nulis',)
ONES = {
@@ -223,34 +225,11 @@ def n2w(n):
def to_currency(n, currency='EUR', cents=True):
if type(n) == int:
if n < 0:
minus = True
else:
minus = False
n = abs(n)
left = n / 100
right = n % 100
else:
n = str(n).replace(',', '.')
if '.' in n:
left, right = n.split('.')
else:
left, right = n, 0
left, right = int(left), int(right)
minus = False
left, right, is_negative = parse_currency_parts(n)
cr1, cr2 = CURRENCIES[currency]
if minus:
minus_str = "minus "
else:
minus_str = ""
if cents:
cents_str = int2word(right)
else:
cents_str = "%02d" % right
minus_str = "minus " if is_negative else ""
cents_str = int2word(right) if cents else "%02d" % right
return u'%s%s %s, %s %s' % (minus_str, int2word(left),
pluralize(left, cr1),

View File

@@ -99,6 +99,8 @@ mīnus divpadsmit tūkstoši pieci simti deviņpadsmit eiro, 85 centi
"""
from __future__ import unicode_literals
from .currency import parse_currency_parts
ZERO = (u'nulle',)
ONES = {
@@ -233,34 +235,11 @@ def n2w(n):
def to_currency(n, currency='EUR', cents=True, seperator=','):
if type(n) == int:
if n < 0:
minus = True
else:
minus = False
n = abs(n)
left = n / 100
right = n % 100
else:
n = str(n).replace(',', '.')
if '.' in n:
left, right = n.split('.')
else:
left, right = n, 0
left, right = int(left), int(right)
minus = False
left, right, is_negative = parse_currency_parts(n)
cr1, cr2 = CURRENCIES[currency]
if minus:
minus_str = "mīnus "
else:
minus_str = ""
if cents:
cents_str = int2word(right)
else:
cents_str = "%02d" % right
minus_str = "mīnus " if is_negative else ""
cents_str = int2word(right) if cents else "%02d" % right
return u'%s%s %s%s %s %s' % (
minus_str,

View File

@@ -104,6 +104,8 @@ sto dwadzieścia trzy złote i pięćdziesiąt groszy
"""
from __future__ import unicode_literals
from .currency import parse_currency_parts
ZERO = (u'zero',)
ONES = {
@@ -241,36 +243,11 @@ def n2w(n):
def to_currency(n, currency='EUR', cents=True, seperator=','):
if type(n) == int:
if n < 0:
minus = True
else:
minus = False
n = abs(n)
left = n // 100
right = n % 100
else:
n = str(n).replace(',', '.')
if '.' in n:
left, right = n.split('.')
if len(right) == 1:
right = right + '0'
else:
left, right = n, 0
left, right = int(left), int(right)
minus = False
left, right, is_negative = parse_currency_parts(n)
cr1, cr2 = CURRENCIES[currency]
if minus:
minus_str = "minus "
else:
minus_str = ""
if cents:
cents_str = int2word(right)
else:
cents_str = "%02d" % right
minus_str = "minus " if is_negative else ""
cents_str = int2word(right) if cents else "%02d" % right
return u'%s%s %s%s %s %s' % (
minus_str,

View File

@@ -103,6 +103,8 @@ u"""
"""
from __future__ import unicode_literals
from .currency import parse_currency_parts
ZERO = (u'ноль',)
ONES_FEMININE = {
@@ -259,29 +261,10 @@ def n2w(n):
def to_currency(n, currency='EUR', cents=True, seperator=','):
if type(n) == int:
if n < 0:
minus = True
else:
minus = False
n = abs(n)
left = n / 100
right = n % 100
else:
n = str(n).replace(',', '.')
if '.' in n:
left, right = n.split('.')
else:
left, right = n, 0
left, right = int(left), int(right)
minus = False
left, right, is_negative = parse_currency_parts(n)
cr1, cr2 = CURRENCIES[currency]
if minus:
minus_str = "минус "
else:
minus_str = ""
minus_str = "минус " if is_negative else ""
if cents:
cents_feminine = currency == 'RUB'

View File

@@ -103,6 +103,8 @@ u"""
"""
from __future__ import unicode_literals
from .currency import parse_currency_parts
ZERO = (u'нуль',)
ONES_FEMININE = {
@@ -264,29 +266,10 @@ def n2w(n):
def to_currency(n, currency='EUR', cents=True, seperator=','):
if type(n) == int:
if n < 0:
minus = True
else:
minus = False
n = abs(n)
left = n / 100
right = n % 100
else:
n = str(n).replace(',', '.')
if '.' in n:
left, right = n.split('.')
else:
left, right = n, 0
left, right = int(left), int(right)
minus = False
left, right, is_negative = parse_currency_parts(n)
cr1, cr2 = CURRENCIES[currency]
if minus:
minus_str = "мiнус "
else:
minus_str = ""
minus_str = "мiнус " if is_negative else ""
if cents:
cents_feminine = currency == 'UAH'

28
tests/test_currency.py Normal file
View File

@@ -0,0 +1,28 @@
from decimal import Decimal
from unittest import TestCase
from num2words.currency import parse_currency_parts
class CurrencyTestCase(TestCase):
def test_parse_currency_parts(self):
# integer cents
self.assertEqual(parse_currency_parts(101), (1, 1, False))
self.assertEqual(parse_currency_parts(-123), (1, 23, True))
# decimal
self.assertEqual(parse_currency_parts(Decimal("1.01")), (1, 1, False))
self.assertEqual(parse_currency_parts(Decimal("-1.23")), (1, 23, True))
self.assertEqual(parse_currency_parts(Decimal("-1.233")),
(1, 23, True))
# string
self.assertEqual(parse_currency_parts("1.01"), (1, 1, False))
self.assertEqual(parse_currency_parts("-1.23"), (1, 23, True))
self.assertEqual(parse_currency_parts("-1.2"), (1, 20, True))
self.assertEqual(parse_currency_parts("1"), (1, 0, False))
# float
self.assertEqual(parse_currency_parts(1.01), (1, 1, False))
self.assertEqual(parse_currency_parts(-1.23), (1, 23, True))
self.assertEqual(parse_currency_parts(-1.2), (1, 20, True))

15
tests/test_lv.py Normal file
View File

@@ -0,0 +1,15 @@
# -*- encoding: utf-8 -*-
from __future__ import unicode_literals
from unittest import TestCase
from num2words import num2words
class Num2WordsLVTest(TestCase):
def test_to_currency(self):
self.assertEqual(
num2words('38.4', lang='lv', to='currency', seperator=' un',
cents=False, currency='EUR'),
"trīsdesmit astoņi eiro un 40 centi"
)

View File

@@ -13,6 +13,7 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA
from __future__ import unicode_literals
from unittest import TestCase
@@ -22,23 +23,30 @@ from num2words import num2words
class Num2WordsRUTest(TestCase):
def test_cardinal(self):
self.assertEqual(num2words(5, lang='ru'), u"пять")
self.assertEqual(num2words(15, lang='ru'), u"пятнадцать")
self.assertEqual(num2words(154, lang='ru'), u"сто пятьдесят четыре")
self.assertEqual(num2words(5, lang='ru'), "пять")
self.assertEqual(num2words(15, lang='ru'), "пятнадцать")
self.assertEqual(num2words(154, lang='ru'), "сто пятьдесят четыре")
self.assertEqual(
num2words(1135, lang='ru'), u"одна тысяча сто тридцать пять"
num2words(1135, lang='ru'), "одна тысяча сто тридцать пять"
)
self.assertEqual(
num2words(418531, lang='ru'),
u"четыреста восемнадцать тысяч пятьсот тридцать один"
"четыреста восемнадцать тысяч пятьсот тридцать один"
)
self.assertEqual(
num2words(1000139, lang='ru'), u"один миллион сто тридцать девять"
num2words(1000139, lang='ru'), "один миллион сто тридцать девять"
)
def test_floating_point(self):
self.assertEqual(num2words(5.2, lang='ru'), u"пять запятая два")
self.assertEqual(num2words(5.2, lang='ru'), "пять запятая два")
self.assertEqual(
num2words(561.42, lang='ru'),
u"пятьсот шестьдесят один запятая сорок два"
"пятьсот шестьдесят один запятая сорок два"
)
def test_to_currency(self):
self.assertEqual(
num2words('38.4', lang='ru', to='currency', seperator=' и',
cents=False, currency='EUR'),
"тридцать восемь евро и 40 центов"
)

View File

@@ -13,6 +13,7 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA
from __future__ import unicode_literals
from unittest import TestCase
@@ -21,18 +22,25 @@ from num2words import num2words
class Num2WordsUKTest(TestCase):
def test_and_join_199(self):
self.assertEqual(num2words(187, lang='uk'), u"сто вiсiмдесят с")
self.assertEqual(num2words(187, lang='uk'), "сто вiсiмдесят с")
def test_cardinal_for_float_number(self):
self.assertEqual(
num2words(12.40, lang='uk'), u"дванадцять кома чотири"
num2words(12.40, lang='uk'), "дванадцять кома чотири"
)
self.assertEqual(
num2words(17.31, lang='uk'), u"сiмнадцять кома тридцять одна"
num2words(17.31, lang='uk'), "сiмнадцять кома тридцять одна"
)
self.assertEqual(
num2words(14.13, lang='uk'), u"чотирнадцять кома тринадцять"
num2words(14.13, lang='uk'), "чотирнадцять кома тринадцять"
)
self.assertEqual(
num2words(12.31, lang='uk'), u"дванадцять кома тридцять одна"
num2words(12.31, lang='uk'), "дванадцять кома тридцять одна"
)
def test_to_currency(self):
self.assertEqual(
num2words('38.4', lang='uk', to='currency', seperator=' и',
cents=False, currency='EUR'),
"тридцять вiсiм евро и 40 центiв"
)