use decimal.Decimal instead of float to store amounts of money

This commit is contained in:
Romain Bignon 2012-03-29 16:14:32 +02:00
commit b157e92d5b
28 changed files with 111 additions and 69 deletions

View file

@ -21,6 +21,7 @@
# python2.5 compatibility # python2.5 compatibility
from __future__ import with_statement from __future__ import with_statement
from decimal import Decimal
from datetime import datetime, timedelta from datetime import datetime, timedelta
from weboob.capabilities.bank import ICapBank, AccountNotFound, Account, Recipient from weboob.capabilities.bank import ICapBank, AccountNotFound, Account, Recipient
@ -108,7 +109,7 @@ class BNPorcBackend(BaseBackend, ICapBank, ICapMessages):
try: try:
assert account.isdigit() assert account.isdigit()
assert to.isdigit() assert to.isdigit()
amount = float(amount) amount = Decimal(amount)
except (AssertionError, ValueError): except (AssertionError, ValueError):
raise AccountNotFound() raise AccountNotFound()

View file

@ -18,6 +18,8 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
from weboob.capabilities.bank import Account from weboob.capabilities.bank import Account
from weboob.capabilities.base import NotAvailable from weboob.capabilities.base import NotAvailable
from weboob.tools.browser import BasePage, BrokenPageError from weboob.tools.browser import BasePage, BrokenPageError
@ -68,7 +70,7 @@ class AccountsList(BasePage):
return account return account
def _parse_amount(self, elem): def _parse_amount(self, elem):
return float(elem.text.replace('.', '').replace(',', '.').strip(u' \t\u20ac\xa0€\n\r')) return Decimal(elem.text.replace('.', '').replace(',', '.').strip(u' \t\u20ac\xa0€\n\r'))
def get_list(self): def get_list(self):
l = [] l = []

View file

@ -19,6 +19,7 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
from datetime import date from datetime import date
from weboob.tools.browser import BasePage from weboob.tools.browser import BasePage
@ -55,9 +56,9 @@ class AccountHistory(BasePage):
amount = tds[4].text amount = tds[4].text
amount = amount.strip(u' \n\t\x80').replace(' ', '').replace(',', '.') amount = amount.strip(u' \n\t\x80').replace(' ', '').replace(',', '.')
# if we don't have exactly one '.', this is not a floatm try the next # if we don't have exactly one '.', this is not a Decimal try the next
operation = Transaction(len(self.operations)) operation = Transaction(len(self.operations))
operation.amount = float(amount) operation.amount = Decimal(amount)
operation.date = d operation.date = d
operation.label = label operation.label = label

View file

@ -19,6 +19,8 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
from weboob.capabilities.bank import Account from weboob.capabilities.bank import Account
from weboob.tools.browser import BasePage from weboob.tools.browser import BasePage
@ -55,9 +57,9 @@ class AccountsList(BasePage):
balance = span.text balance = span.text
balance = balance.strip(u' \n\t€+').replace(',', '.').replace(' ', '') balance = balance.strip(u' \n\t€+').replace(',', '.').replace(' ', '')
if balance != "": if balance != "":
account.balance = float(balance) account.balance = Decimal(balance)
else: else:
account.balance = 0.0 account.balance = Decimal(0.0)
else: else:
# because of some weird useless <tr> # because of some weird useless <tr>

View file

@ -18,6 +18,7 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
from datetime import date from datetime import date
import re import re
@ -56,9 +57,9 @@ class AccountHistory(BasePage):
amount = t.text amount = t.text
amount = ''.join(amount.replace('.', '').replace(',', '.').split()) amount = ''.join(amount.replace('.', '').replace(',', '.').split())
if amount[0] == "-": if amount[0] == "-":
operation.amount = -float(amount[1:]) operation.amount = - Decimal(amount[1:])
else: else:
operation.amount = float(amount) operation.amount = Decimal(amount)
operations.append(operation) operations.append(operation)
return operations return operations

View file

@ -18,8 +18,9 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from weboob.capabilities.bank import Account, AccountNotFound from decimal import Decimal
from weboob.capabilities.bank import Account, AccountNotFound
from weboob.tools.browser import BasePage from weboob.tools.browser import BasePage
@ -59,7 +60,7 @@ class AccountList(BasePage):
tmp_balance = tmp[0].text tmp_balance = tmp[0].text
account.id = tmp_id account.id = tmp_id
account.balance = float(''.join(tmp_balance.replace('.','').replace(',','.').split())) account.balance = Decimal(''.join(tmp_balance.replace('.','').replace(',','.').split()))
self.account_list.append(account) self.account_list.append(account)
def get_account(self, id): def get_account(self, id):

View file

@ -28,6 +28,7 @@ from weboob.tools.browser import BrowserIncorrectPassword, BrokenPageError
from re import match, compile, sub from re import match, compile, sub
from httplib import HTTPSConnection from httplib import HTTPSConnection
from urllib import urlencode from urllib import urlencode
from decimal import Decimal
from lxml import etree from lxml import etree
from datetime import date from datetime import date
@ -169,13 +170,13 @@ class CmbBackend(BaseBackend, ICapBank):
balance = td[1].text balance = td[1].text
balance = balance.replace(',', '.').replace(u"\xa0", '') balance = balance.replace(',', '.').replace(u"\xa0", '')
account.balance = float(balance) account.balance = Decimal(balance)
span = td[3].xpath('a/span') span = td[3].xpath('a/span')
if len(span): if len(span):
coming = span[0].text.replace(' ', '').replace(',', '.') coming = span[0].text.replace(' ', '').replace(',', '.')
coming = coming.replace(u"\xa0", '') coming = coming.replace(u"\xa0", '')
account.coming = float(coming) account.coming = Decimal(coming)
else: else:
account.coming = NotAvailable account.coming = NotAvailable
@ -262,10 +263,10 @@ class CmbBackend(BaseBackend, ICapBank):
if amount.count(',') != 1: if amount.count(',') != 1:
amount = td[4].text amount = td[4].text
amount = amount.replace(',', '.').replace(u'\xa0', '') amount = amount.replace(',', '.').replace(u'\xa0', '')
operation.amount = float(amount) operation.amount = Decimal(amount)
else: else:
amount = amount.replace(',', '.').replace(u'\xa0', '') amount = amount.replace(',', '.').replace(u'\xa0', '')
operation.amount = - float(amount) operation.amount = - Decimal(amount)
i += 1 i += 1
yield operation yield operation

View file

@ -18,6 +18,7 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
import re import re
from datetime import date from datetime import date
from weboob.capabilities.bank import Account from weboob.capabilities.bank import Account
@ -27,13 +28,13 @@ from weboob.capabilities.bank import Transaction
def clean_amount(amount): def clean_amount(amount):
""" """
Removes weird characters and converts to a float Removes weird characters and converts to a Decimal
>>> clean_amount(u'1 000,00 $') >>> clean_amount(u'1 000,00 $')
1000.0 1000.0
""" """
data = amount.replace(',', '.').replace(' ', '').replace(u'\xa0', '') data = amount.replace(',', '.').replace(' ', '').replace(u'\xa0', '')
matches = re.findall('^(-?[0-9]+\.[0-9]{2}).*$', data) matches = re.findall('^(-?[0-9]+\.[0-9]{2}).*$', data)
return float(matches[0]) if (matches) else 0.0 return Decimal(matches[0]) if (matches) else Decimal(0.0)
class AccountsList(CragrBasePage): class AccountsList(CragrBasePage):

View file

@ -19,6 +19,8 @@
from __future__ import with_statement from __future__ import with_statement
from decimal import Decimal
from weboob.capabilities.bank import ICapBank, AccountNotFound, Recipient, Account from weboob.capabilities.bank import ICapBank, AccountNotFound, Recipient, Account
from weboob.tools.backend import BaseBackend, BackendConfig from weboob.tools.backend import BaseBackend, BackendConfig
from weboob.tools.value import ValueBackendPassword from weboob.tools.value import ValueBackendPassword
@ -78,7 +80,7 @@ class CreditMutuelBackend(BaseBackend, ICapBank):
try: try:
assert account.isdigit() assert account.isdigit()
assert to.isdigit() assert to.isdigit()
amount = float(amount) amount = Decimal(amount)
except (AssertionError, ValueError): except (AssertionError, ValueError):
raise AccountNotFound() raise AccountNotFound()

View file

@ -18,6 +18,7 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
import re import re
from weboob.tools.browser import BasePage from weboob.tools.browser import BasePage
@ -70,7 +71,7 @@ class AccountsPage(BasePage):
balance += c balance += c
if c == ',': if c == ',':
balance += '.' balance += '.'
account.balance = float(balance) account.balance = Decimal(balance)
l.append(account) l.append(account)
#raise NotImplementedError() #raise NotImplementedError()
return l return l
@ -135,7 +136,7 @@ class OperationsPage(BasePage):
balance += c balance += c
if c == ',': if c == ',':
balance += '.' balance += '.'
operation.amount = float(balance) operation.amount = Decimal(balance)
yield operation yield operation
def next_page_url(self): def next_page_url(self):

View file

@ -18,9 +18,11 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from datetime import datetime, date, time
from decimal import Decimal
from weboob.tools.browser import BasePage from weboob.tools.browser import BasePage
from weboob.capabilities.bill import Detail, Bill from weboob.capabilities.bill import Detail, Bill
from datetime import datetime, date, time
__all__ = ['HistoryPage', 'DetailsPage'] __all__ = ['HistoryPage', 'DetailsPage']
@ -30,9 +32,9 @@ def convert_price(div):
try: try:
price = div.find('div[@class="horsForfait"]/p/span').text price = div.find('div[@class="horsForfait"]/p/span').text
price = price.encode('utf-8', 'replace').replace('€', '').replace(',', '.') price = price.encode('utf-8', 'replace').replace('€', '').replace(',', '.')
return float(price) return Decimal(price)
except: except:
return 0. return Decimal(0)
class DetailsPage(BasePage): class DetailsPage(BasePage):
@ -118,9 +120,9 @@ class HistoryPage(BasePage):
detail.datetime = datetime.combine(mydate, mytime) detail.datetime = datetime.combine(mydate, mytime)
detail.label = tds[1].text.lstrip().rstrip() + " " + tds[2].text.lstrip().rstrip() + " " + tds[3].text.lstrip().rstrip() detail.label = tds[1].text.lstrip().rstrip() + " " + tds[2].text.lstrip().rstrip() + " " + tds[3].text.lstrip().rstrip()
try: try:
detail.price = float(tds[4].text[0:4].replace(',', '.')) detail.price = Decimal(tds[4].text[0:4].replace(',', '.'))
except: except:
detail.price = 0. detail.price = Decimal(0.0)
self.calls.append(detail) self.calls.append(detail)

View file

@ -18,6 +18,7 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
import re import re
from weboob.tools.browser import BasePage from weboob.tools.browser import BasePage
@ -49,7 +50,7 @@ class AccountsListPage(BasePage):
tag = tds[2].find('font') tag = tds[2].find('font')
if tag is None: if tag is None:
tag = tds[2] tag = tds[2]
account.balance = float(tag.text.replace('.','').replace(',','.').replace(' ', '').strip(u' \t\u20ac\xa0€\n\r')) account.balance = Decimal(tag.text.replace('.','').replace(',','.').replace(' ', '').strip(u' \t\u20ac\xa0€\n\r'))
account.coming = NotAvailable account.coming = NotAvailable
yield account yield account

View file

@ -18,6 +18,7 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
from datetime import date from datetime import date
from weboob.tools.browser import BasePage from weboob.tools.browser import BasePage
@ -52,7 +53,7 @@ class AccountHistoryCC(BasePage):
amount = texte[5].replace('\t', '').strip().replace(u'€', '').\ amount = texte[5].replace('\t', '').strip().replace(u'€', '').\
replace(',', '.').replace(u'\xa0', u'') replace(',', '.').replace(u'\xa0', u'')
op.amount = float(amount) op.amount = Decimal(amount)
self.transactions.append(op) self.transactions.append(op)
i += 1 i += 1
@ -81,7 +82,7 @@ class AccountHistoryLA(BasePage):
amount = texte[length - 1].replace('\t', '').strip().\ amount = texte[length - 1].replace('\t', '').strip().\
replace('.', '').replace(u'€', '').\ replace('.', '').replace(u'€', '').\
replace(',', '.').replace(u'\xa0', u'') replace(',', '.').replace(u'\xa0', u'')
op.amount = float(amount) op.amount = Decimal(amount)
self.transactions.append(op) self.transactions.append(op)
i += 1 i += 1

View file

@ -18,6 +18,7 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
import re import re
from weboob.capabilities.bank import Account from weboob.capabilities.bank import Account
@ -46,8 +47,8 @@ class AccountsList(BasePage):
linkbis = self.document.xpath(urltofind).pop() linkbis = self.document.xpath(urltofind).pop()
if linkbis.text == link.text: if linkbis.text == link.text:
linkbis = self.document.xpath(urltofind)[1] linkbis = self.document.xpath(urltofind)[1]
account.balance = float(linkbis.text.replace('.', '').\ account.balance = Decimal(linkbis.text.replace('.', '').\
replace(' ', '').replace(',', '.')) replace(' ', '').replace(',', '.'))
account.coming = NotAvailable account.coming = NotAvailable
l.append(account) l.append(account)

View file

@ -19,6 +19,8 @@
import base64 import base64
from datetime import date from datetime import date
from decimal import Decimal
from weboob.capabilities.bank import Transaction from weboob.capabilities.bank import Transaction
from weboob.capabilities.bank import Account from weboob.capabilities.bank import Account
from weboob.tools.browser import BasePage, BrowserUnavailable from weboob.tools.browser import BasePage, BrowserUnavailable
@ -149,7 +151,7 @@ class AccountsPage(BasePage):
balance=a.text.replace(u"\u00A0",'').replace(' ','').replace('.','').replace('+','').replace(',','.') balance=a.text.replace(u"\u00A0",'').replace(' ','').replace('.','').replace('+','').replace(',','.')
if '-' in balance: if '-' in balance:
balance='-'+balance.strip().replace('-', '') balance='-'+balance.strip().replace('-', '')
account.balance=float(balance) account.balance=Decimal(balance)
l.append(account) l.append(account)
return l return l
@ -200,7 +202,7 @@ class AccountHistoryPage(BasePage):
mntColumn+=1 mntColumn+=1
amount=u''.join([txt.strip() for txt in td.itertext()]) amount=u''.join([txt.strip() for txt in td.itertext()])
if amount != "": if amount != "":
amount = float(amount.replace('.','').replace(',','.').replace(u"\u00A0",'').replace(' ','')) amount = Decimal(amount.replace('.','').replace(',','.').replace(u"\u00A0",'').replace(' ',''))
if value.startswith("soldeDeb") or mntColumn==1: if value.startswith("soldeDeb") or mntColumn==1:
amount=-amount amount=-amount
operation.amount=amount operation.amount=amount

View file

@ -19,6 +19,7 @@
import re import re
from decimal import Decimal
from dateutil.parser import parse as parse_date from dateutil.parser import parse as parse_date
from weboob.tools.browser import BasePage from weboob.tools.browser import BasePage
@ -53,9 +54,9 @@ class SearchResultsPage(BasePage):
housing.title = a.text.strip() housing.title = a.text.strip()
m = re.match('(\w+) (.+) (\d+)\xa0m\xb2 (.*)', housing.title) m = re.match('(\w+) (.+) (\d+)\xa0m\xb2 (.*)', housing.title)
if m: if m:
housing.area = float(m.group(3)) housing.area = Decimal(m.group(3))
housing.cost = float(div.cssselect('td.prix')[0].text.strip(u' \t\u20ac\xa0€\n\r').replace('.', '').replace(',', '.')) housing.cost = Decimal(div.cssselect('td.prix')[0].text.strip(u' \t\u20ac\xa0€\n\r').replace('.', '').replace(',', '.'))
housing.currency = u'€' housing.currency = u'€'
m = self.DATE_RE.match(div.cssselect('p.date-publication')[0].text.strip()) m = self.DATE_RE.match(div.cssselect('p.date-publication')[0].text.strip())
@ -90,12 +91,12 @@ class HousingPage(BasePage):
parts = div.find('h1').text.split(' - ') parts = div.find('h1').text.split(' - ')
housing.title = parts[0].strip() housing.title = parts[0].strip()
housing.cost = float(parts[1].strip(u' \t\u20ac\xa0€\n\r').replace('.', '').replace(',', '.')) housing.cost = Decimal(parts[1].strip(u' \t\u20ac\xa0€\n\r').replace('.', '').replace(',', '.'))
housing.currency = u'€' housing.currency = u'€'
m = re.match('(\w+) (.+) (\d+)\xa0m\xb2 (.*)', housing.title) m = re.match('(\w+) (.+) (\d+)\xa0m\xb2 (.*)', housing.title)
if m: if m:
housing.area = float(m.group(3)) housing.area = Decimal(m.group(3))
housing.date = housing.station = housing.location = housing.phone = NotAvailable housing.date = housing.station = housing.location = housing.phone = NotAvailable

View file

@ -18,6 +18,7 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
import re import re
from weboob.tools.browser import BasePage from weboob.tools.browser import BasePage
@ -59,7 +60,7 @@ class ComparisonResultsPage(BasePage):
price.product = product price.product = product
tds = tr.findall('td') tds = tr.findall('td')
price.cost = float(tds[4].text.replace(',', '.')) price.cost = Decimal(tds[4].text.replace(',', '.'))
price.currency = u'€' price.currency = u'€'
shop = Shop(price.id) shop = Shop(price.id)

View file

@ -18,6 +18,7 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
from dateutil.parser import parse as parse_date from dateutil.parser import parse as parse_date
from weboob.tools.browser import BasePage from weboob.tools.browser import BasePage
@ -41,9 +42,9 @@ class SearchResultsPage(BasePage):
housing = Housing(a.find('idannonce').text) housing = Housing(a.find('idannonce').text)
housing.title = a.find('titre').text housing.title = a.find('titre').text
housing.date = parse_date(a.find('dtfraicheur').text) housing.date = parse_date(a.find('dtfraicheur').text)
housing.cost = float(a.find('prix').text) housing.cost = Decimal(a.find('prix').text)
housing.currency = u'€' housing.currency = u'€'
housing.area = float(a.find('surface').text) housing.area = Decimal(a.find('surface').text)
housing.text = a.find('descriptif').text.strip() housing.text = a.find('descriptif').text.strip()
housing.location = a.find('ville').text housing.location = a.find('ville').text
try: try:
@ -69,10 +70,10 @@ class HousingPage(BasePage):
housing.title = details.find('titre').text housing.title = details.find('titre').text
housing.text = details.find('descriptif').text.strip() housing.text = details.find('descriptif').text.strip()
housing.cost = float(details.find('prix').text) housing.cost = Decimal(details.find('prix').text)
housing.currency = u'€' housing.currency = u'€'
housing.date = parse_date(details.find('dtfraicheur').text) housing.date = parse_date(details.find('dtfraicheur').text)
housing.area = float(details.find('surface').text) housing.area = Decimal(details.find('surface').text)
housing.phone = details.find('contact').find('telephone').text housing.phone = details.find('contact').find('telephone').text
try: try:

View file

@ -18,6 +18,7 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
import re import re
from weboob.capabilities.bank import Account from weboob.capabilities.bank import Account
@ -52,9 +53,9 @@ class AccountsList(BasePage):
balance = td.find('div').text balance = td.find('div').text
if balance != None: if balance != None:
balance = balance.replace(u'\xa0','').replace(',','.') balance = balance.replace(u'\xa0','').replace(',','.')
account.balance = float(balance) account.balance = Decimal(balance)
else: else:
account.balance = 0.0 account.balance = Decimal(0.0)
l.append(account) l.append(account)

View file

@ -18,6 +18,7 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
import sys import sys
from weboob.capabilities.bank import ICapBank, Account, Transaction from weboob.capabilities.bank import ICapBank, Account, Transaction
@ -123,8 +124,8 @@ class AccountListFormatter(IFormatter):
MANDATORY_FIELDS = ('id', 'label', 'balance', 'coming') MANDATORY_FIELDS = ('id', 'label', 'balance', 'coming')
count = 0 count = 0
tot_balance = 0.0 tot_balance = Decimal(0)
tot_coming = 0.0 tot_coming = Decimal(0)
def flush(self): def flush(self):
if self.count < 1: if self.count < 1:
@ -134,8 +135,8 @@ class AccountListFormatter(IFormatter):
result += u'%s Total %8s %8s' % ((' ' * 15) if not self.interactive else '', result += u'%s Total %8s %8s' % ((' ' * 15) if not self.interactive else '',
'%.2f' % self.tot_balance, '%.2f' % self.tot_coming) '%.2f' % self.tot_balance, '%.2f' % self.tot_coming)
self.after_format(result) self.after_format(result)
self.tot_balance = 0.0 self.tot_balance = Decimal(0)
self.tot_coming = 0.0 self.tot_coming = Decimal(0)
self.count = 0 self.count = 0
def format_dict(self, item): def format_dict(self, item):
@ -152,7 +153,7 @@ class AccountListFormatter(IFormatter):
result += '------------------------------------------%s+----------+----------\n' % (('-' * 15) if not self.interactive else '') result += '------------------------------------------%s+----------+----------\n' % (('-' * 15) if not self.interactive else '')
result += (u' %s%-' + (u'15' if self.interactive else '30') + u's%s %-25s %8s %8s') % \ result += (u' %s%-' + (u'15' if self.interactive else '30') + u's%s %-25s %8s %8s') % \
(self.BOLD, id, self.NC, (self.BOLD, id, self.NC,
item['label'], '%.2f' % item['balance'], '%.2f' % (item['coming'] or 0.0)) item['label'], '%.2f' % item['balance'], '%.2f' % (item['coming'] or Decimal(0.0)))
self.tot_balance += item['balance'] self.tot_balance += item['balance']
if item['coming']: if item['coming']:
@ -281,7 +282,7 @@ class Boobank(ReplApplication):
id_to, backend_name_to = self.parse_id(id_to) id_to, backend_name_to = self.parse_id(id_to)
try: try:
amount = float(amount) amount = Decimal(amount)
except (TypeError, ValueError): except (TypeError, ValueError):
print >>sys.stderr, 'Error: please give a decimal amount to transfer' print >>sys.stderr, 'Error: please give a decimal amount to transfer'
return 2 return 2

Some files were not shown because too many files have changed in this diff Show more