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

View file

@ -20,6 +20,8 @@
from PyQt4.QtGui import QListWidgetItem, QImage, QPixmap, QLabel, QIcon, QBrush, QColor from PyQt4.QtGui import QListWidgetItem, QImage, QPixmap, QLabel, QIcon, QBrush, QColor
from PyQt4.QtCore import SIGNAL, Qt from PyQt4.QtCore import SIGNAL, Qt
from decimal import Decimal
from weboob.tools.application.qt import QtMainWindow, QtDo, HTMLDelegate from weboob.tools.application.qt import QtMainWindow, QtDo, HTMLDelegate
from weboob.tools.application.qt.backendcfg import BackendCfg from weboob.tools.application.qt.backendcfg import BackendCfg
from weboob.capabilities.housing import ICapHousing, Query, City from weboob.capabilities.housing import ICapHousing, Query, City
@ -35,8 +37,8 @@ class HousingListWidgetItem(QListWidgetItem):
self.read = True self.read = True
def __lt__(self, other): def __lt__(self, other):
return '%s%s' % (self.read, float(self.housing.cost or 0) / float(self.housing.area or 1)) < \ return '%s%s' % (self.read, Decimal(self.housing.cost or 0) / Decimal(self.housing.area or 1)) < \
'%s%s' % (other.read, float(other.housing.cost or 0) / float(other.housing.area or 1)) '%s%s' % (other.read, Decimal(other.housing.cost or 0) / Decimal(other.housing.area or 1))
def setAttrs(self, storage): def setAttrs(self, storage):
text = u'<h2>%s</h2>' % self.housing.title text = u'<h2>%s</h2>' % self.housing.title

View file

@ -20,7 +20,7 @@
from datetime import date, datetime from datetime import date, datetime
from .base import CapBaseObject, Field, StringField, DateField, FloatField, IntField from .base import CapBaseObject, Field, StringField, DateField, DecimalField, IntField
from .collection import ICapCollection from .collection import ICapCollection
@ -66,8 +66,8 @@ class Account(Recipient):
TYPE_JOINT = 6 # Joint account TYPE_JOINT = 6 # Joint account
type = IntField('Type of account', default=TYPE_UNKNOWN) type = IntField('Type of account', default=TYPE_UNKNOWN)
balance = FloatField('Balance on this bank account') balance = DecimalField('Balance on this bank account')
coming = FloatField('Coming balance') coming = DecimalField('Coming balance')
def __repr__(self): def __repr__(self):
return u"<Account id=%r label=%r>" % (self.id, self.label) return u"<Account id=%r label=%r>" % (self.id, self.label)
@ -94,7 +94,7 @@ class Transaction(CapBaseObject):
raw = StringField('Raw label of the transaction') raw = StringField('Raw label of the transaction')
category = StringField('Category of transaction') category = StringField('Category of transaction')
label = StringField('Pretty label') label = StringField('Pretty label')
amount = FloatField('Amount of transaction') amount = DecimalField('Amount of transaction')
def __repr__(self): def __repr__(self):
return "<Transaction date='%s' label='%s' amount=%s>" % (self.date, return "<Transaction date='%s' label='%s' amount=%s>" % (self.date,
@ -105,7 +105,7 @@ class Transfer(CapBaseObject):
Transfer from an account to a recipient. Transfer from an account to a recipient.
""" """
amount = FloatField('Amount to transfer') amount = DecimalField('Amount to transfer')
date = Field('Date of transfer', basestring, date, datetime) date = Field('Date of transfer', basestring, date, datetime)
origin = Field('Origin of transfer', int, long, basestring) origin = Field('Origin of transfer', int, long, basestring)
recipient = Field('Recipient', int, long, basestring) recipient = Field('Recipient', int, long, basestring)
@ -193,7 +193,7 @@ class ICapBank(ICapCollection):
:param recipient: account to send money :param recipient: account to send money
:type recipient: :class:`Recipient` :type recipient: :class:`Recipient`
:param amount: amount :param amount: amount
:type amount: :class:`float` :type amount: :class:`decimal.Decimal`
:param reason: reason of transfer :param reason: reason of transfer
:type reason: :class:`unicode` :type reason: :class:`unicode`
:rtype: :class:`Transfer` :rtype: :class:`Transfer`

View file

@ -20,6 +20,7 @@
import warnings import warnings
import datetime import datetime
from decimal import Decimal
from copy import deepcopy from copy import deepcopy
from weboob.tools.misc import to_unicode from weboob.tools.misc import to_unicode
@ -27,8 +28,8 @@ from weboob.tools.ordereddict import OrderedDict
__all__ = ['FieldNotFound', 'NotAvailable', 'NotLoaded', 'IBaseCap', __all__ = ['FieldNotFound', 'NotAvailable', 'NotLoaded', 'IBaseCap',
'Field', 'IntField', 'FloatField', 'StringField', 'BytesField', 'Field', 'IntField', 'DecimalField', 'FloatField', 'StringField',
'DateField', 'DeltaField', 'CapBaseObject', 'empty'] 'BytesField', 'DateField', 'DeltaField', 'CapBaseObject', 'empty']
def empty(value): def empty(value):
@ -154,6 +155,18 @@ class IntField(Field):
def convert(self, value): def convert(self, value):
return int(value) return int(value)
class DecimalField(Field):
"""
A field which accepts only :class:`decimal` type.
"""
def __init__(self, doc, **kwargs):
Field.__init__(self, doc, Decimal, **kwargs)
def convert(self, value):
if isinstance(value, Decimal):
return value
return Decimal(value)
class FloatField(Field): class FloatField(Field):
""" """
A field which accepts only :class:`float` type. A field which accepts only :class:`float` type.
@ -244,7 +257,7 @@ class CapBaseObject(object):
class Transfer(CapBaseObject): class Transfer(CapBaseObject):
" Transfer from an account to a recipient. " " Transfer from an account to a recipient. "
amount = FloatField('Amount to transfer') amount = DecimalField('Amount to transfer')
date = Field('Date of transfer', basestring, date, datetime) date = Field('Date of transfer', basestring, date, datetime)
origin = Field('Origin of transfer', int, long, basestring) origin = Field('Origin of transfer', int, long, basestring)
recipient = Field('Recipient', int, long, basestring) recipient = Field('Recipient', int, long, basestring)

View file

@ -17,7 +17,7 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from .base import CapBaseObject, StringField, DateField, FloatField from .base import CapBaseObject, StringField, DateField, DecimalField
from .collection import ICapCollection from .collection import ICapCollection
@ -47,7 +47,7 @@ class Detail(CapBaseObject):
label = StringField('label of the detail line') label = StringField('label of the detail line')
infos = StringField('information') infos = StringField('information')
datetime = DateField('date information') datetime = DateField('date information')
price = FloatField('price') price = DecimalField('price')
def __init__(self): def __init__(self):
CapBaseObject.__init__(self, 0) CapBaseObject.__init__(self, 0)

View file

@ -18,7 +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 .base import IBaseCap, CapBaseObject, Field, IntField, FloatField, \ from .base import IBaseCap, CapBaseObject, Field, IntField, DecimalField, \
StringField, BytesField, DateField StringField, BytesField, DateField
@ -50,8 +50,8 @@ class Housing(CapBaseObject):
Content of a housing. Content of a housing.
""" """
title = StringField('Title of housing') title = StringField('Title of housing')
area = FloatField('Area of housing, in m2') area = DecimalField('Area of housing, in m2')
cost = FloatField('Cost of housing') cost = DecimalField('Cost of housing')
currency = StringField('Currency of cost') currency = StringField('Currency of cost')
date = DateField('Date when the housing has been published') date = DateField('Date when the housing has been published')
location = StringField('Location of housing') location = StringField('Location of housing')

View file

@ -18,7 +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 .base import IBaseCap, CapBaseObject, Field, FloatField, \ from .base import IBaseCap, CapBaseObject, Field, DecimalField, \
StringField, DateField StringField, DateField
@ -44,7 +44,7 @@ class Price(CapBaseObject):
Price. Price.
""" """
date = DateField('Date when this price has been published') date = DateField('Date when this price has been published')
cost = FloatField('Cost of the product in this shop') cost = DecimalField('Cost of the product in this shop')
currency = StringField('Currency of the price') currency = StringField('Currency of the price')
message = StringField('Message related to this price') message = StringField('Message related to this price')
shop = Field('Shop information', Shop) shop = Field('Shop information', Shop)

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
import datetime import datetime
@ -53,9 +54,9 @@ class FrenchTransaction(Transaction):
debit = self.clean_amount(debit) debit = self.clean_amount(debit)
if len(debit) > 0: if len(debit) > 0:
self.amount = - float(debit) self.amount = - Decimal(debit)
else: else:
self.amount = float(credit) self.amount = Decimal(credit)
def parse(self, date, raw): def parse(self, date, raw):
""" """

View file

@ -21,6 +21,7 @@
from __future__ import with_statement from __future__ import with_statement
from ConfigParser import RawConfigParser, DEFAULTSECT from ConfigParser import RawConfigParser, DEFAULTSECT
from decimal import Decimal
import logging import logging
import os import os
@ -70,7 +71,7 @@ class INIConfig(IConfig):
def save(self): def save(self):
def save_section(values, root_section=self.ROOTSECT): def save_section(values, root_section=self.ROOTSECT):
for k, v in values.iteritems(): for k, v in values.iteritems():
if isinstance(v, (int, float, basestring)): if isinstance(v, (int, Decimal, float, basestring)):
if not self.config.has_section(root_section): if not self.config.has_section(root_section):
self.config.add_section(root_section) self.config.add_section(root_section)
self.config.set(root_section, k, unicode(v)) self.config.set(root_section, k, unicode(v))