diff --git a/.travis.yml b/.travis.yml
index 3084b3440..a5f478fbe 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,34 +1,33 @@
-language: python
sudo: false
-install:
- - pip install tox codecov
-script:
- - tox
+language: python
+python:
+ - "2.7"
+ - "3.4"
+ - "3.5"
+ - "3.6"
env:
- - TOXENV=py27-django18
- - TOXENV=py27-django110
- - TOXENV=py27-django111
- - TOXENV=py34-django18
- - TOXENV=py34-django110
- - TOXENV=py34-django111
- - TOXENV=py34-django_master
- - TOXENV=py35-django18
- - TOXENV=py35-django110
- - TOXENV=py35-django111
- - TOXENV=py35-django_master
+ - DJANGO="1.11"
+ - DJANGO="2.0"
+ - DJANGO="master"
matrix:
allow_failures:
- - env: TOXENV=py27-django111
- - env: TOXENV=py34-django111
- - env: TOXENV=py35-django111
- - env: TOXENV=py34-django_master
- - env: TOXENV=py35-django_master
-after_success:
- - codecov
-addons:
- apt:
- sources:
- - deadsnakes
- packages:
- - python3.5
- - python3.5-dev
+ - python: "3.4"
+ env: DJANGO="2.0"
+ - python: "3.4"
+ env: DJANGO="master"
+ - python: "3.5"
+ env: DJANGO="2.0"
+ - python: "3.5"
+ env: DJANGO="master"
+ - python: "3.6"
+ env: DJANGO="2.0"
+ - python: "3.6"
+ env: DJANGO="master"
+ exclude:
+ - python: "2.7"
+ env: DJANGO="2.0"
+ - python: "2.7"
+ env: DJANGO="master"
+after_success: codecov
+install: pip install tox-travis codecov
+script: tox
diff --git a/payments/cybersource/forms.py b/payments/cybersource/forms.py
index 0293b5a7b..5fedde0e4 100644
--- a/payments/cybersource/forms.py
+++ b/payments/cybersource/forms.py
@@ -13,7 +13,8 @@
class FingerprintWidget(forms.HiddenInput):
def render(self, name, value, attrs=None):
- final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
+ final_attrs = dict(attrs or {}, type=self.input_type, name=name)
+ final_attrs.update(self.attrs)
final_attrs['session_id'] = value
return render_to_string(
'payments/cybersource_fingerprint.html', final_attrs)
diff --git a/payments/stripe/widgets.py b/payments/stripe/widgets.py
index f313b4fba..fe2566dbf 100644
--- a/payments/stripe/widgets.py
+++ b/payments/stripe/widgets.py
@@ -31,8 +31,8 @@ def __init__(self, provider, payment, *args, **kwargs):
def render(self, name, value, attrs=None):
if value is None:
value = ''
- final_attrs = self.build_attrs(
- attrs, src="https://checkout.stripe.com/checkout.js")
+ final_attrs = dict(attrs or {}, src='https://checkout.stripe.com/checkout.js')
+ final_attrs.update(self.attrs)
del final_attrs['id']
if value != '':
# Only add the 'value' attribute if a value is non-empty.
@@ -46,6 +46,6 @@ class Media:
js = ['https://js.stripe.com/v2/',
'js/payments/stripe.js']
- def build_attrs(self, extra_attrs=None, **kwargs):
- extra_attrs = dict(extra_attrs or {}, id='id_stripe_token')
- return super(StripeWidget, self).build_attrs(extra_attrs, **kwargs)
+ def __init__(self, attrs=None):
+ attrs = dict(attrs or {}, id='id_stripe_token')
+ super(StripeWidget, self).__init__(attrs)
diff --git a/payments/templates/payments/credit_card_expiry_widget.html b/payments/templates/payments/credit_card_expiry_widget.html
index 68fd7eda7..ab09159b7 100644
--- a/payments/templates/payments/credit_card_expiry_widget.html
+++ b/payments/templates/payments/credit_card_expiry_widget.html
@@ -1,3 +1,7 @@
- {{ month }} / {{ year }}
+ {% with widget.subwidgets.0 as month %}
+ {% with widget.subwidgets.1 as year %}
+ {% include month.template_name with widget=month %} / {% include year.template_name with widget=year %}
+ {% endwith %}
+ {% endwith %}
\ No newline at end of file
diff --git a/payments/templates/payments/sensitive_select.html b/payments/templates/payments/sensitive_select.html
new file mode 100644
index 000000000..a22fd82e2
--- /dev/null
+++ b/payments/templates/payments/sensitive_select.html
@@ -0,0 +1,5 @@
+
diff --git a/payments/templates/payments/sensitive_text_input.html b/payments/templates/payments/sensitive_text_input.html
new file mode 100644
index 000000000..3133edbcc
--- /dev/null
+++ b/payments/templates/payments/sensitive_text_input.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/payments/widgets.py b/payments/widgets.py
index a843cbe75..795906fee 100644
--- a/payments/widgets.py
+++ b/payments/widgets.py
@@ -1,12 +1,6 @@
import re
-from django import VERSION as DJANGO_VERSION
-from django.forms.utils import flatatt
from django.forms.widgets import TextInput, MultiWidget, Select
-from django.template.loader import render_to_string
-from django.utils.encoding import force_text
-from django.utils.html import format_html
-from django.utils.safestring import mark_safe
class CreditCardNumberWidget(TextInput):
@@ -28,43 +22,19 @@ def render(self, name, value, attrs=None):
# http://www.djangosnippets.org/snippets/907/
class CreditCardExpiryWidget(MultiWidget):
"""MultiWidget for representing credit card expiry date."""
+
+ template_name = 'payments/credit_card_expiry_widget.html'
+
def decompress(self, value):
if value:
return [value.month, value.year]
else:
return [None, None]
- def format_output(self, rendered_widgets):
- ctx = {'month': rendered_widgets[0], 'year': rendered_widgets[1]}
- return render_to_string('payments/credit_card_expiry_widget.html', ctx)
-
class SensitiveTextInput(TextInput):
-
- def render(self, name, value, attrs=None):
- # Explicitly skip parent implementation and exclude
- # 'name' from attrs
- if value is None:
- value = ''
- final_attrs = self.build_attrs(attrs, type=self.input_type)
- if value != '':
- # Only add the 'value' attribute if a value is non-empty.
- final_attrs['value'] = force_text(self.format_value(value))
- return format_html('', flatatt(final_attrs))
+ template_name = 'payments/sensitive_text_input.html'
class SensitiveSelect(Select):
-
- def render(self, name, value, attrs=None):
- if value is None:
- value = ''
- final_attrs = self.build_attrs(attrs)
- output = [format_html('')
- return mark_safe('\n'.join(output))
+ template_name = 'payments/sensitive_select.html'
diff --git a/setup.py b/setup.py
index 422758ee9..3874b1889 100755
--- a/setup.py
+++ b/setup.py
@@ -22,7 +22,7 @@
REQUIREMENTS = [
'braintree>=3.14.0',
- 'Django>=1.5',
+ 'Django>=1.11',
'cryptography>=1.1.0',
'PyJWT>=1.3.0',
'requests>=1.2.0',
@@ -69,6 +69,7 @@ def run_tests(self):
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
'Framework :: Django',
'Topic :: Software Development :: Libraries :: Application Frameworks',
'Topic :: Software Development :: Libraries :: Python Modules'],
diff --git a/tox.ini b/tox.ini
index 22a5672f8..63f22717b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,13 +1,12 @@
[tox]
-envlist = py{27,34,35}-django{18,110,111} py{34,35}-django_master
+envlist = py27-django111, py{34,35,36}-django{111,20,_master}
[testenv]
usedevelop=True
deps=
coverage
- django18: django>=1.8,<1.9a0
- django110: django>=1.10,<1.11a0
django111: django>=1.11a1,<1.12
+ django20: Django>=2.0a1,<2.1
django_master: https://github.com/django/django/archive/master.tar.gz
mock
pytest
@@ -17,3 +16,17 @@ commands=coverage run setup.py test
[pytest]
testpaths = payments
DJANGO_SETTINGS_MODULE = test_settings
+
+[travis]
+python =
+ 2.7: py27
+ 3.4: py34
+ 3.5: py35
+ 3.6: py36
+unignore_outcomes = True
+
+[travis:env]
+DJANGO =
+ 1.11: django111
+ 2.0: django2.0
+ master: django_master