summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrédéric Péters <fpeters@entrouvert.com>2018-03-26 07:56:16 (GMT)
committerFrédéric Péters <fpeters@entrouvert.com>2018-07-26 14:25:28 (GMT)
commit887832bc5fb442ef887e8690c5353bf833854c32 (patch)
tree96cb8ad46db0321712792d78fbfb17b5f8296716
parent31b85ae9fdece1c2c5fd7a862bae0e037e85eb87 (diff)
downloadeopayment-887832bc5fb442ef887e8690c5353bf833854c32.zip
eopayment-887832bc5fb442ef887e8690c5353bf833854c32.tar.gz
eopayment-887832bc5fb442ef887e8690c5353bf833854c32.tar.bz2
add python3 compatibility (#23720)
-rw-r--r--eopayment/__init__.py7
-rw-r--r--eopayment/common.py33
-rw-r--r--eopayment/dummy.py17
-rw-r--r--eopayment/ogone.py14
-rw-r--r--eopayment/paybox.py42
-rw-r--r--eopayment/sips.py8
-rw-r--r--eopayment/sips2.py30
-rw-r--r--eopayment/spplus.py28
-rw-r--r--eopayment/systempayv2.py60
-rw-r--r--eopayment/tipi.py22
-rwxr-xr-xsetup.py9
-rw-r--r--tests/test_ogone.py2
-rw-r--r--tests/test_paybox.py8
-rw-r--r--tests/test_spplus.py4
-rw-r--r--tests/test_systempayv2.py2
-rw-r--r--tox.ini4
16 files changed, 165 insertions, 125 deletions
diff --git a/eopayment/__init__.py b/eopayment/__init__.py
index 7a15cbc..fbd0e55 100644
--- a/eopayment/__init__.py
+++ b/eopayment/__init__.py
@@ -1,9 +1,10 @@
# -*- coding: utf-8 -*-
+import importlib
import logging
-from common import (URL, HTML, FORM, RECEIVED, ACCEPTED, PAID, DENIED,
- CANCELED, CANCELLED, ERROR, WAITING, ResponseError, force_text)
+from .common import (URL, HTML, FORM, RECEIVED, ACCEPTED, PAID, DENIED,
+ CANCELED, CANCELLED, ERROR, WAITING, ResponseError, force_text)
__all__ = ['Payment', 'URL', 'HTML', 'FORM', 'SIPS',
'SYSTEMPAY', 'SPPLUS', 'TIPI', 'DUMMY', 'get_backend', 'RECEIVED', 'ACCEPTED',
@@ -23,7 +24,7 @@ logger = logging.getLogger(__name__)
def get_backend(kind):
'''Resolve a backend name into a module object'''
- module = __import__(kind, globals(), locals(), [])
+ module = importlib.import_module('.' + kind, package='eopayment')
return module.Payment
__BACKENDS = [ DUMMY, SIPS, SIPS2, SYSTEMPAY, SPPLUS, OGONE, PAYBOX, PAYZEN, TIPI ]
diff --git a/eopayment/common.py b/eopayment/common.py
index ac37e77..258f856 100644
--- a/eopayment/common.py
+++ b/eopayment/common.py
@@ -2,9 +2,15 @@ import os.path
import os
import random
import logging
-import cgi
from datetime import date
+import six
+
+if six.PY3:
+ import html
+else:
+ import cgi
+
__all__ = ['PaymentCommon', 'URL', 'HTML', 'RANDOM', 'RECEIVED', 'ACCEPTED',
'PAID', 'ERROR', 'WAITING']
@@ -29,15 +35,27 @@ ORDERID_TRANSACTION_SEPARATOR = '!'
def force_text(s, encoding='utf-8'):
- if isinstance(s, unicode):
+ if issubclass(type(s), six.text_type):
return s
try:
- return unicode(s, encoding)
+ if not issubclass(type(s), six.string_types):
+ if six.PY3:
+ if isinstance(s, bytes):
+ s = six.text_type(s, encoding)
+ else:
+ s = six.text_type(s)
+ elif hasattr(s, '__unicode__'):
+ s = six.text_type(s)
+ else:
+ s = six.text_type(bytes(s), encoding)
+ else:
+ s = s.decode(encoding)
except UnicodeDecodeError:
- return unicode(s)
+ return six.text_type(s, encoding, 'ignore')
+ return s
def force_byte(s, encoding='utf-8'):
- if isinstance(s, str):
+ if isinstance(s, bytes):
return s
try:
return s.encode(encoding)
@@ -148,7 +166,10 @@ class Form(object):
return s
def escape(self, s):
- return cgi.escape(force_text(s, self.encoding).encode(self.encoding))
+ if six.PY3:
+ return html.escape(force_text(s, self.encoding))
+ else:
+ return cgi.escape(force_text(s, self.encoding)).encode(self.encoding)
def __str__(self):
s = '<form method="%s" action="%s">' % (self.method, self.url)
diff --git a/eopayment/dummy.py b/eopayment/dummy.py
index 2ed8655..ef08517 100644
--- a/eopayment/dummy.py
+++ b/eopayment/dummy.py
@@ -1,21 +1,18 @@
-import urllib
import string
import logging
import warnings
def N_(message): return message
-try:
- from cgi import parse_qs
-except ImportError:
- from urlparse import parse_qs
+from six.moves.urllib.parse import parse_qs, urlencode
-from common import PaymentCommon, URL, PaymentResponse, PAID, ERROR, WAITING, ResponseError
+from .common import (PaymentCommon, URL, PaymentResponse, PAID, ERROR, WAITING,
+ ResponseError, force_text)
__all__ = [ 'Payment' ]
SERVICE_URL = 'http://dummy-payment.demo.entrouvert.com/'
-ALPHANUM = string.letters + string.digits
+ALPHANUM = string.ascii_letters + string.digits
LOGGER = logging.getLogger(__name__)
class Payment(PaymentCommon):
@@ -114,14 +111,14 @@ class Payment(PaymentCommon):
}
query.update(dict(name=name, address=address, email=email, phone=phone,
orderid=orderid, info1=info1, info2=info2, info3=info3))
- for key in query.keys():
+ for key in list(query.keys()):
if query[key] is None:
del query[key]
- url = '%s?%s' % (SERVICE_URL, urllib.urlencode(query))
+ url = '%s?%s' % (SERVICE_URL, urlencode(query))
return transaction_id, URL, url
def response(self, query_string, logger=LOGGER, **kwargs):
- form = parse_qs(query_string)
+ form = parse_qs(force_text(query_string))
if not 'transaction_id' in form:
raise ResponseError()
transaction_id = form.get('transaction_id',[''])[0]
diff --git a/eopayment/ogone.py b/eopayment/ogone.py
index 900d348..af0600d 100644
--- a/eopayment/ogone.py
+++ b/eopayment/ogone.py
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
import hashlib
import string
-import urlparse
+import six
+from six.moves.urllib import parse as urlparse
from decimal import Decimal, ROUND_HALF_UP
-from common import (PaymentCommon, PaymentResponse, FORM, CANCELLED, PAID,
+from .common import (PaymentCommon, PaymentResponse, FORM, CANCELLED, PAID,
ERROR, Form, DENIED, ACCEPTED, ORDERID_TRANSACTION_SEPARATOR,
WAITING, ResponseError, force_byte, force_text)
def N_(message): return message
@@ -499,7 +500,7 @@ class Payment(PaymentCommon):
# arrondi comptable francais
amount = amount.quantize(Decimal('1.'), rounding=ROUND_HALF_UP)
params = {
- 'AMOUNT': unicode(amount),
+ 'AMOUNT': force_text(amount),
'ORDERID': reference,
'PSPID': self.pspid,
'LANGUAGE': language,
@@ -517,7 +518,7 @@ class Payment(PaymentCommon):
params['EMAIL'] = email
if description:
params['COM'] = description
- for key, value in kwargs.iteritems():
+ for key, value in kwargs.items():
params[key.upper()] = value
params['SHASIGN'] = self.sha_sign_in(params)
# uniformize all values to UTF-8 string
@@ -533,7 +534,10 @@ class Payment(PaymentCommon):
return reference, FORM, form
def response(self, query_string, **kwargs):
- params = urlparse.parse_qs(query_string, True)
+ if six.PY3:
+ params = urlparse.parse_qs(query_string, True, encoding='iso-8859-1')
+ else:
+ params = urlparse.parse_qs(query_string, True)
params = dict((key.upper(), params[key][0]) for key in params)
if not set(params) >= set(['ORDERID', 'PAYID', 'STATUS', 'NCERROR']):
raise ResponseError()
diff --git a/eopayment/paybox.py b/eopayment/paybox.py
index 2ebed40..4333173 100644
--- a/eopayment/paybox.py
+++ b/eopayment/paybox.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8
+import codecs
from collections import OrderedDict
import datetime
import logging
@@ -9,15 +10,18 @@ from decimal import Decimal, ROUND_DOWN
from Crypto.Signature import PKCS1_v1_5
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA
-import urlparse
-import urllib
+
+import six
+from six.moves.urllib import parse as urlparse
+from six.moves.urllib import parse as urllib
+
import base64
from gettext import gettext as _
import string
import warnings
-from common import (PaymentCommon, PaymentResponse, FORM, PAID, ERROR, Form,
- ORDERID_TRANSACTION_SEPARATOR, ResponseError)
+from .common import (PaymentCommon, PaymentResponse, FORM, PAID, ERROR, Form,
+ ORDERID_TRANSACTION_SEPARATOR, ResponseError, force_text)
__all__ = ['sign', 'Payment']
@@ -109,9 +113,10 @@ def sign(data, key):
algo = ALGOS[v]
break
assert algo, 'Missing or invalid PBX_HASH'
- tosign = ['%s=%s' % (k, unicode(v).encode('utf-8')) for k, v in data]
+ tosign = ['%s=%s' % (k, force_text(v)) for k, v in data]
tosign = '&'.join(tosign)
logger.debug('signed string %r', tosign)
+ tosign = tosign.encode('utf-8')
signature = hmac.new(key, tosign, algo)
return tuple(data) + (('PBX_HMAC', signature.hexdigest().upper()),)
@@ -208,22 +213,22 @@ class Payment(PaymentCommon):
def request(self, amount, email, name=None, orderid=None, **kwargs):
d = OrderedDict()
- d['PBX_SITE'] = unicode(self.site)
- d['PBX_RANG'] = unicode(self.rang).strip()[-2:]
- d['PBX_IDENTIFIANT'] = unicode(self.identifiant)
+ d['PBX_SITE'] = force_text(self.site)
+ d['PBX_RANG'] = force_text(self.rang).strip()[-2:]
+ d['PBX_IDENTIFIANT'] = force_text(self.identifiant)
d['PBX_TOTAL'] = (amount * Decimal(100)).to_integral_value(ROUND_DOWN)
- d['PBX_DEVISE'] = unicode(self.devise)
+ d['PBX_DEVISE'] = force_text(self.devise)
transaction_id = kwargs.get('transaction_id') or \
self.transaction_id(12, string.digits, 'paybox', self.site,
self.rang, self.identifiant)
- d['PBX_CMD'] = unicode(transaction_id)
+ d['PBX_CMD'] = force_text(transaction_id)
# prepend order id command reference
if orderid:
d['PBX_CMD'] = orderid + ORDERID_TRANSACTION_SEPARATOR + d['PBX_CMD']
- d['PBX_PORTEUR'] = unicode(email)
+ d['PBX_PORTEUR'] = force_text(email)
d['PBX_RETOUR'] = 'montant:M;reference:R;code_autorisation:A;erreur:E;signature:K'
d['PBX_HASH'] = 'SHA512'
- d['PBX_TIME'] = kwargs.get('time') or (unicode(datetime.datetime.utcnow().isoformat('T')).split('.')[0]+'+00:00')
+ d['PBX_TIME'] = kwargs.get('time') or (force_text(datetime.datetime.utcnow().isoformat('T')).split('.')[0]+'+00:00')
d['PBX_ARCHIVAGE'] = transaction_id
if self.normal_return_url:
d['PBX_EFFECTUE'] = self.normal_return_url
@@ -236,16 +241,21 @@ class Payment(PaymentCommon):
"use automatic_return_url", DeprecationWarning)
automatic_return_url = self.callback
if automatic_return_url:
- d['PBX_REPONDRE_A'] = unicode(automatic_return_url)
+ d['PBX_REPONDRE_A'] = force_text(automatic_return_url)
d = d.items()
- d = sign(d, self.shared_secret.decode('hex'))
+
+ if six.PY3:
+ shared_secret = codecs.decode(bytes(self.shared_secret, 'ascii'), 'hex')
+ else:
+ shared_secret = codecs.decode(bytes(self.shared_secret), 'hex')
+ d = sign(d, shared_secret)
url = URLS[self.platform]
fields = []
for k, v in d:
fields.append({
'type': u'hidden',
- 'name': unicode(k),
- 'value': unicode(v),
+ 'name': force_text(k),
+ 'value': force_text(v),
})
form = Form(url, 'POST', fields, submit_name=None,
submit_value=u'Envoyer', encoding='utf-8')
diff --git a/eopayment/sips.py b/eopayment/sips.py
index ef5f1c6..ced03a8 100644
--- a/eopayment/sips.py
+++ b/eopayment/sips.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-import urlparse
+from six.moves.urllib import parse as urlparse
import string
import subprocess
from decimal import Decimal
@@ -9,8 +9,8 @@ import os.path
import uuid
import warnings
-from common import PaymentCommon, HTML, PaymentResponse, ResponseError
-from cb import CB_RESPONSE_CODES
+from .common import PaymentCommon, HTML, PaymentResponse, ResponseError
+from .cb import CB_RESPONSE_CODES
'''
Payment backend module for the ATOS/SIPS system used by many Frenck banks.
@@ -112,7 +112,7 @@ class Payment(PaymentCommon):
if PATHFILE in self.options:
params[PATHFILE] = self.options[PATHFILE]
executable = os.path.join(self.binpath, executable)
- args = [executable] + ["%s=%s" % p for p in params.iteritems()]
+ args = [executable] + ["%s=%s" % p for p in params.items()]
self.logger.debug('executing %s' % args)
result,_ = subprocess.Popen(' '.join(args),
stdout=subprocess.PIPE, shell=True).communicate()
diff --git a/eopayment/sips2.py b/eopayment/sips2.py
index 584ec56..4def5d7 100644
--- a/eopayment/sips2.py
+++ b/eopayment/sips2.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
import collections
import json
-import urlparse
+from six.moves.urllib import parse as urlparse
import string
from decimal import Decimal
import uuid
@@ -11,8 +11,8 @@ from gettext import gettext as _
import requests
import warnings
-from common import (PaymentCommon, FORM, Form, PaymentResponse, PAID, ERROR,
- CANCELED, ResponseError)
+from .common import (PaymentCommon, FORM, Form, PaymentResponse, PAID, ERROR,
+ CANCELED, ResponseError, force_text)
__all__ = ['Payment']
@@ -139,12 +139,12 @@ class Payment(PaymentCommon):
}
def encode_data(self, data):
- return u'|'.join(u'%s=%s' % (unicode(key), unicode(value))
- for key, value in data.iteritems())
+ return u'|'.join(u'%s=%s' % (force_text(key), force_text(value))
+ for key, value in data.items())
def seal_data(self, data):
s = self.encode_data(data)
- s += unicode(self.secret_key)
+ s += force_text(self.secret_key)
s = s.encode('utf-8')
s = hashlib.sha256(s).hexdigest()
return s
@@ -172,13 +172,13 @@ class Payment(PaymentCommon):
info1=None, info2=None, info3=None, next_url=None, **kwargs):
data = self.get_data()
transaction_id = self.transaction_id(10, string.digits, 'sips2', data['merchantId'])
- data['transactionReference'] = unicode(transaction_id)
- data['orderId'] = orderid or unicode(uuid.uuid4()).replace('-', '')
+ data['transactionReference'] = force_text(transaction_id)
+ data['orderId'] = orderid or force_text(uuid.uuid4()).replace('-', '')
if info1:
- data['statementReference'] = unicode(info1)
+ data['statementReference'] = force_text(info1)
else:
data['statementReference'] = data['transactionReference']
- data['amount'] = unicode(int(Decimal(amount) * 100))
+ data['amount'] = force_text(int(Decimal(amount) * 100))
if email:
data['billingContact.email'] = email
if 'captureDay' in kwargs:
@@ -215,7 +215,7 @@ class Payment(PaymentCommon):
def decode_data(self, data):
data = data.split('|')
- data = [map(unicode, p.split('=', 1)) for p in data]
+ data = [map(force_text, p.split('=', 1)) for p in data]
return collections.OrderedDict(data)
def check_seal(self, data, seal):
@@ -254,9 +254,9 @@ class Payment(PaymentCommon):
for key in sorted(data.keys()):
if key in ('keyVersion', 'sealAlgorithm', 'seal'):
continue
- data_to_send.append(unicode(data[key]))
+ data_to_send.append(force_text(data[key]))
data_to_send_str = u''.join(data_to_send).encode('utf-8')
- return hmac.new(unicode(self.secret_key).encode('utf-8'), data_to_send_str, hashlib.sha256).hexdigest()
+ return hmac.new(force_text(self.secret_key).encode('utf-8'), data_to_send_str, hashlib.sha256).hexdigest()
def perform_cash_management_operation(self, endpoint, data):
data['merchantId'] = self.merchant_id
@@ -282,13 +282,13 @@ class Payment(PaymentCommon):
def cancel(self, amount, bank_data, **kwargs):
data = {}
- data['operationAmount'] = unicode(int(Decimal(amount) * 100))
+ data['operationAmount'] = force_text(int(Decimal(amount) * 100))
data['transactionReference'] = bank_data.get('transactionReference')
return self.perform_cash_management_operation('cancel', data)
def validate(self, amount, bank_data, **kwargs):
data = {}
- data['operationAmount'] = unicode(int(Decimal(amount) * 100))
+ data['operationAmount'] = force_text(int(Decimal(amount) * 100))
data['transactionReference'] = bank_data.get('transactionReference')
return self.perform_cash_management_operation('validate', data)
diff --git a/eopayment/spplus.py b/eopayment/spplus.py
index d6e7b48..e8b1ffc 100644
--- a/eopayment/spplus.py
+++ b/eopayment/spplus.py
@@ -4,8 +4,8 @@ import binascii
from gettext import gettext as _
import hmac
import hashlib
-import urlparse
-import urllib
+from six.moves.urllib import parse as urlparse
+from six.moves.urllib import parse as urllib
import string
import datetime as dt
import logging
@@ -13,15 +13,15 @@ import re
import warnings
import Crypto.Cipher.DES
-from common import (PaymentCommon, URL, PaymentResponse, RECEIVED, ACCEPTED,
- PAID, ERROR, ResponseError)
+from .common import (PaymentCommon, URL, PaymentResponse, RECEIVED, ACCEPTED,
+ PAID, ERROR, ResponseError, force_byte)
def N_(message): return message
__all__ = ['Payment']
-KEY_DES_KEY = '\x45\x1f\xba\x4f\x4c\x3f\xd4\x97'
-IV = '\x30\x78\x30\x62\x2c\x30\x78\x30'
+KEY_DES_KEY = b'\x45\x1f\xba\x4f\x4c\x3f\xd4\x97'
+IV = b'\x30\x78\x30\x62\x2c\x30\x78\x30'
REFERENCE = 'reference'
ETAT = 'etat'
SPCHECKOK = 'spcheckok'
@@ -56,7 +56,7 @@ TEST_STATE = ('99',)
def decrypt_ntkey(ntkey):
- key = binascii.unhexlify(ntkey.replace(' ',''))
+ key = binascii.unhexlify(ntkey.replace(b' ', b''))
return decrypt_key(key)
def decrypt_key(key):
@@ -70,7 +70,7 @@ def extract_values(query_string):
k, v = kv.split('=', 1)
if k != 'hmac':
result.append(v)
- return ''.join(result)
+ return force_byte(''.join(result))
def sign_ntkey_query(ntkey, query):
key = decrypt_ntkey(ntkey)
@@ -89,7 +89,7 @@ def sign_url_paiement(ntkey, query):
data_to_sign = ''.join(fields)
return hmac.new(key[:20], data_to_sign, hashlib.sha1).hexdigest().upper()
-ALPHANUM = string.letters + string.digits
+ALPHANUM = string.ascii_letters + string.digits
SERVICE_URL = "https://www.spplus.net/paiement/init.do"
class Payment(PaymentCommon):
@@ -178,7 +178,7 @@ class Payment(PaymentCommon):
form = urlparse.parse_qs(query_string)
if not set(form) >= set([REFERENCE, ETAT, REFSFP]):
raise ResponseError()
- for key, value in form.iteritems():
+ for key, value in form.items():
form[key] = value[0]
logger.debug('received query_string %s' % query_string)
logger.debug('parsed as %s' % form)
@@ -233,8 +233,8 @@ if __name__ == '__main__':
ntkey = '58 6d fc 9c 34 91 9b 86 3f fd 64 63 c9 13 4a 26 ba 29 74 1e c7 e9 80 79'
if len(sys.argv) == 2:
- print sign_url_paiement(ntkey, sys.argv[1])
- print sign_ntkey_query(ntkey, sys.argv[1])
+ print(sign_url_paiement(ntkey, sys.argv[1]))
+ print(sign_ntkey_query(ntkey, sys.argv[1]))
elif len(sys.argv) > 2:
- print sign_url_paiement(sys.argv[1], sys.argv[2])
- print sign_ntkey_query(sys.argv[1], sys.argv[2])
+ print(sign_url_paiement(sys.argv[1], sys.argv[2]))
+ print(sign_ntkey_query(sys.argv[1], sys.argv[2]))
diff --git a/eopayment/systempayv2.py b/eopayment/systempayv2.py
index ccf38d0..d2de01c 100644
--- a/eopayment/systempayv2.py
+++ b/eopayment/systempayv2.py
@@ -4,13 +4,13 @@ import datetime as dt
import hashlib
import logging
import string
-import urlparse
+from six.moves.urllib import parse as urlparse
import warnings
from gettext import gettext as _
-from common import (PaymentCommon, PaymentResponse, PAID, ERROR, FORM, Form,
- ResponseError, force_text, force_byte)
-from cb import CB_RESPONSE_CODES
+from .common import (PaymentCommon, PaymentResponse, PAID, ERROR, FORM, Form,
+ ResponseError, force_text, force_byte)
+from .cb import CB_RESPONSE_CODES
__all__ = ['Payment']
@@ -117,20 +117,20 @@ PARAMETERS = [
'ONEY_SANDBOX, PAYPAL, PAYPAL_SB, PAYSAFECARD, '
'VISA')),
# must be SINGLE or MULTI with parameters
- Parameter('vads_payment_config', '', 07, default='SINGLE',
+ Parameter('vads_payment_config', '', 7, default='SINGLE',
choices=('SINGLE', 'MULTI'), needed=True),
Parameter('vads_return_mode', None, 48, default='GET',
choices=('', 'NONE', 'POST', 'GET')),
Parameter('signature', 'an', None, length=40),
- Parameter('vads_site_id', 'n', 02, length=8, needed=True,
+ Parameter('vads_site_id', 'n', 2, length=8, needed=True,
description=_(u'Identifiant de la boutique')),
Parameter('vads_theme_config', 'ans', 32, max_length=255),
- Parameter(VADS_TRANS_DATE, 'n', 04, length=14, needed=True,
+ Parameter(VADS_TRANS_DATE, 'n', 4, length=14, needed=True,
default=isonow),
- Parameter('vads_trans_id', 'n', 03, length=6, needed=True),
+ Parameter('vads_trans_id', 'n', 3, length=6, needed=True),
Parameter('vads_validation_mode', 'n', 5, max_length=1, choices=('', 0, 1),
default=''),
- Parameter('vads_version', 'an', 01, default='V2', needed=True,
+ Parameter('vads_version', 'an', 1, default='V2', needed=True,
choices=('V2',)),
Parameter('vads_url_success', 'ans', 24, max_length=127),
Parameter('vads_url_referral', 'ans', 26, max_length=127),
@@ -173,7 +173,7 @@ EXTRA_RESULT_MAP = {
def add_vads(kwargs):
new_vargs = {}
- for k, v in kwargs.iteritems():
+ for k, v in kwargs.items():
if k.startswith('vads_'):
new_vargs[k] = v
else:
@@ -276,8 +276,8 @@ class Payment(PaymentCommon):
info2, info3, next_url, kwargs)
# amount unit is cents
amount = '%.0f' % (100 * amount)
- kwargs.update(add_vads({'amount': unicode(amount)}))
- if amount < 0:
+ kwargs.update(add_vads({'amount': force_text(amount)}))
+ if int(amount) < 0:
raise ValueError('amount must be an integer >= 0')
normal_return_url = self.normal_return_url
if next_url:
@@ -285,30 +285,30 @@ class Payment(PaymentCommon):
"set normal_return_url in options", DeprecationWarning)
normal_return_url = next_url
if normal_return_url:
- kwargs[VADS_URL_RETURN] = unicode(normal_return_url)
+ kwargs[VADS_URL_RETURN] = force_text(normal_return_url)
if name is not None:
- kwargs['vads_cust_name'] = unicode(name)
+ kwargs['vads_cust_name'] = force_text(name)
if first_name is not None:
- kwargs[VADS_CUST_FIRST_NAME] = unicode(first_name)
+ kwargs[VADS_CUST_FIRST_NAME] = force_text(first_name)
if last_name is not None:
- kwargs[VADS_CUST_LAST_NAME] = unicode(last_name)
+ kwargs[VADS_CUST_LAST_NAME] = force_text(last_name)
if address is not None:
- kwargs['vads_cust_address'] = unicode(address)
+ kwargs['vads_cust_address'] = force_text(address)
if email is not None:
- kwargs['vads_cust_email'] = unicode(email)
+ kwargs['vads_cust_email'] = force_text(email)
if phone is not None:
- kwargs['vads_cust_phone'] = unicode(phone)
+ kwargs['vads_cust_phone'] = force_text(phone)
if info1 is not None:
- kwargs['vads_order_info'] = unicode(info1)
+ kwargs['vads_order_info'] = force_text(info1)
if info2 is not None:
- kwargs['vads_order_info2'] = unicode(info2)
+ kwargs['vads_order_info2'] = force_text(info2)
if info3 is not None:
- kwargs['vads_order_info3'] = unicode(info3)
+ kwargs['vads_order_info3'] = force_text(info3)
if orderid is not None:
# check orderid format first
name = 'vads_order_id'
- orderid = unicode(orderid)
+ orderid = force_text(orderid)
ptype = 'an-'
p = Parameter(name, ptype, 13, max_length=32)
if not p.check_value(orderid):
@@ -318,14 +318,14 @@ class Payment(PaymentCommon):
transaction_id = self.transaction_id(6, string.digits, 'systempay',
self.options[VADS_SITE_ID])
- kwargs[VADS_TRANS_ID] = unicode(transaction_id)
+ kwargs[VADS_TRANS_ID] = force_text(transaction_id)
fields = kwargs
for parameter in PARAMETERS:
name = parameter.name
# import default parameters from configuration
if name not in fields \
and name in self.options:
- fields[name] = unicode(self.options[name])
+ fields[name] = force_text(self.options[name])
# import default parameters from module
if name not in fields and parameter.default is not None:
if callable(parameter.default):
@@ -333,7 +333,7 @@ class Payment(PaymentCommon):
else:
fields[name] = parameter.default
check_vads(fields)
- fields[SIGNATURE] = unicode(self.signature(fields))
+ fields[SIGNATURE] = force_text(self.signature(fields))
self.logger.debug('%s request contains fields: %s', __name__, fields)
transaction_id = '%s_%s' % (fields[VADS_TRANS_DATE], transaction_id)
self.logger.debug('%s transaction id: %s', __name__, transaction_id)
@@ -346,14 +346,14 @@ class Payment(PaymentCommon):
'name': force_text(field_name),
'value': force_text(field_value),
}
- for field_name, field_value in fields.iteritems()])
+ for field_name, field_value in fields.items()])
return transaction_id, FORM, form
def response(self, query_string, **kwargs):
fields = urlparse.parse_qs(query_string, True)
if not set(fields) >= set([SIGNATURE, VADS_CTX_MODE, VADS_AUTH_RESULT]):
raise ResponseError()
- for key, value in fields.iteritems():
+ for key, value in fields.items():
fields[key] = value[0]
copy = fields.copy()
bank_status = []
@@ -417,8 +417,8 @@ class Payment(PaymentCommon):
self.logger.debug('ordered keys %s' % ordered_keys)
ordered_fields = [force_byte(fields[key]) for key in ordered_keys]
secret = getattr(self, 'secret_%s' % fields['vads_ctx_mode'].lower())
- signed_data = '+'.join(ordered_fields)
- signed_data = '%s+%s' % (signed_data, force_byte(secret))
+ signed_data = b'+'.join(ordered_fields)
+ signed_data = b'%s+%s' % (signed_data, force_byte(secret))
self.logger.debug(u'generating signature on «%s»', signed_data)
sign = hashlib.sha1(signed_data).hexdigest()
self.logger.debug(u'signature «%s»', sign)
diff --git a/eopayment/tipi.py b/eopayment/tipi.py
index 3a3b571..1eb73de 100644
--- a/eopayment/tipi.py
+++ b/eopayment/tipi.py
@@ -1,15 +1,15 @@
# -*- coding: utf-8 -*-
from decimal import Decimal, ROUND_DOWN
-from common import (PaymentCommon, PaymentResponse, URL, PAID, DENIED,
+from .common import (PaymentCommon, PaymentResponse, URL, PAID, DENIED,
CANCELLED, ERROR, ResponseError)
-from urllib import urlencode
-from urlparse import parse_qs
+from six.moves.urllib.parse import urlencode, parse_qs
+
from gettext import gettext as _
import logging
import warnings
-from systempayv2 import isonow
+from .systempayv2 import isonow
__all__ = ['Payment']
@@ -95,12 +95,12 @@ class Payment(PaymentCommon):
refdet = str(refdet)
if 6 > len(refdet) > 30:
raise ValueError('len(REFDET) < 6 or > 30')
- except Exception, e:
+ except Exception as e:
raise ValueError('REFDET format invalide, %r' % refdet, e)
if objet is not None:
try:
objet = str(objet)
- except Exception, e:
+ except Exception as e:
raise ValueError('OBJET must be a string', e)
if not objet.replace(' ','').isalnum():
raise ValueError('OBJECT must only contains '
@@ -113,7 +113,7 @@ class Payment(PaymentCommon):
raise ValueError('no @ in MEL')
if not (6 <= len(mel) <= 80):
raise ValueError('len(MEL) is invalid, must be between 6 and 80')
- except Exception, e:
+ except Exception as e:
raise ValueError('MEL is not a valid email, %r' % mel, e)
saisie = saisie or self.saisie
@@ -146,7 +146,7 @@ class Payment(PaymentCommon):
fields = parse_qs(query_string, True)
if not set(fields) >= set(['refdet', 'resultrans']):
raise ResponseError()
- for key, value in fields.iteritems():
+ for key, value in fields.items():
fields[key] = value[0]
refdet = fields.get('refdet')
if refdet is None:
@@ -183,11 +183,11 @@ class Payment(PaymentCommon):
if __name__ == '__main__':
p = Payment({'numcli': '12345'})
- print p.request(amount=Decimal('123.12'),
+ print(p.request(amount=Decimal('123.12'),
exer=9999,
refdet=999900000000999999,
objet='tout a fait',
email='info@entrouvert.com',
urlcl='http://example.com/tipi/test',
- saisie='T')
- print p.response('objet=tout+a+fait&montant=12312&saisie=T&mel=info%40entrouvert.com&numcli=12345&exer=9999&refdet=999900000000999999&resultrans=P')
+ saisie='T'))
+ print(p.response('objet=tout+a+fait&montant=12312&saisie=T&mel=info%40entrouvert.com&numcli=12345&exer=9999&refdet=999900000000999999&resultrans=P'))
diff --git a/setup.py b/setup.py
index dd9543c..5bcca4c 100755
--- a/setup.py
+++ b/setup.py
@@ -46,7 +46,7 @@ class TestCommand(distutils.core.Command):
class eo_sdist(sdist):
def run(self):
- print "creating VERSION file"
+ print("creating VERSION file")
if os.path.exists('VERSION'):
os.remove('VERSION')
version = get_version()
@@ -54,7 +54,7 @@ class eo_sdist(sdist):
version_file.write(version)
version_file.close()
sdist.run(self)
- print "removing VERSION file"
+ print("removing VERSION file")
if os.path.exists('VERSION'):
os.remove('VERSION')
@@ -72,7 +72,7 @@ def get_version():
stderr=subprocess.PIPE)
result = p.communicate()[0]
if p.returncode == 0:
- version = result.split()[0][1:]
+ version = str(result.split()[0][1:])
version = version.replace('-', '.')
return version
return '0.0.0'
@@ -83,7 +83,7 @@ setuptools.setup(
license='GPLv3 or later',
description='Common API to use all French online payment credit card '
'processing services',
- long_description=file(
+ long_description=open(
os.path.join(
os.path.dirname(__file__),
'README.txt')).read(),
@@ -96,6 +96,7 @@ setuptools.setup(
install_requires=[
'pycrypto >= 2.5',
'requests',
+ 'six',
],
cmdclass={
'sdist': eo_sdist,
diff --git a/tests/test_ogone.py b/tests/test_ogone.py
index 025dcdb..b667445 100644
--- a/tests/test_ogone.py
+++ b/tests/test_ogone.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from unittest import TestCase
-import urllib
+from six.moves.urllib import parse as urllib
import eopayment
import eopayment.ogone as ogone
diff --git a/tests/test_paybox.py b/tests/test_paybox.py
index 0a8de60..bedcb69 100644
--- a/tests/test_paybox.py
+++ b/tests/test_paybox.py
@@ -1,9 +1,10 @@
# -*- coding: utf-8 -*-
+import codecs
from unittest import TestCase
from decimal import Decimal
import base64
-import urllib
+from six.moves.urllib import parse as urllib
import eopayment.paybox as paybox
import eopayment
@@ -19,7 +20,8 @@ BACKEND_PARAMS = {
class PayboxTests(TestCase):
def test_sign(self):
- key = '0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF'.decode('hex')
+ key = b'0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF'
+ key = codecs.decode(key, 'hex')
d = dict(paybox.sign([
['PBX_SITE', u'12345678'],
['PBX_RANG', u'32'],
@@ -97,7 +99,7 @@ UX4D2A/QcMvkEcRVXFx5tQqcE9/JnMqE41TF/ebn7jC/MBxxtPFkUN7+EZoeMN7x
OWzAMDm/xsCWRvvel4GGixgm3aQRUPyTrlm4Ksy32Ya0rNnEDMAvB3dxOn7cp8GR
ZdzrudBlevZXpr6iYwIDAQAB
-----END PUBLIC KEY-----'''
- data = 'coin\n'
+ data = b'coin\n'
sig64 = '''VCt3sgT0ecacmDEWWNVXJ+jGmIPBMApK42tBJV0FlDjpllOGPy8MsAmLW4/QjTtx
z0Dkz0NjxvU+5WzQZh9Uuxr/egRCwV4NMRWqu0zaVVioeBvl4/5CWm4f4/1L9+0m
FBFKOZhgBJnkC+l6+XhT4aYWKaQ4ocmOMV92yjeXTE4='''
diff --git a/tests/test_spplus.py b/tests/test_spplus.py
index 34f48a1..a1a2058 100644
--- a/tests/test_spplus.py
+++ b/tests/test_spplus.py
@@ -2,8 +2,8 @@ from unittest import TestCase
import eopayment.spplus as spplus
class SPPlustTest(TestCase):
- ntkey = '58 6d fc 9c 34 91 9b 86 3f ' \
- 'fd 64 63 c9 13 4a 26 ba 29 74 1e c7 e9 80 79'
+ ntkey = b'58 6d fc 9c 34 91 9b 86 3f ' \
+ b'fd 64 63 c9 13 4a 26 ba 29 74 1e c7 e9 80 79'
tests = [('x=coin', 'c04f8266d6ae3ce37551cce996c751be4a95d10a'),
('x=coin&y=toto', 'ef008e02f8dbf5e70e83da416b0b3a345db203de'),
diff --git a/tests/test_systempayv2.py b/tests/test_systempayv2.py
index 25ad104..c558bbf 100644
--- a/tests/test_systempayv2.py
+++ b/tests/test_systempayv2.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-import urlparse
+from six.moves.urllib import parse as urlparse
from eopayment.systempayv2 import Payment, VADS_CUST_FIRST_NAME, \
VADS_CUST_LAST_NAME, PAID
diff --git a/tox.ini b/tox.ini
index 72cd3f7..61acc97 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,6 +3,10 @@
# test suite on all supported python versions. To use it, "pip install tox"
# and then run "tox" from this directory.
+[tox]
+envlist = py2,py3
+toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/eopayment/
+
[testenv]
# django.contrib.auth is not tested it does not work with our templates
commands =