Skip to content

Commit f4806f3

Browse files
authored
Test Python 3.7 support (#288)
* Add Python 3.7 to Travis matrix * Add Python 3.7 to supported versions * Update complex ops tests for Python 3.7 * Exclude perf tests using tag
1 parent 8bb517d commit f4806f3

File tree

6 files changed

+58
-15
lines changed

6 files changed

+58
-15
lines changed

.travis.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ python:
55
- "3.4"
66
- "3.5"
77
- "3.6"
8+
- "3.7"
89

910
install:
1011
- travis_retry pip install -U six setuptools pip wheel
@@ -17,15 +18,15 @@ after_success:
1718

1819
matrix:
1920
include:
20-
- python: "3.6"
21+
- python: "3.7"
2122
env: TOXENV="performance"
2223
script: tox -- -v 2
23-
- python: "3.6"
24+
- python: "3.7"
2425
env: TOXENV="warnings"
25-
- python: "3.6"
26+
- python: "3.7"
2627
env: TOXENV="isort,lint"
2728

28-
- python: "3.6"
29+
- python: "3.7"
2930
env: TOXENV="dist"
3031
script:
3132
- python setup.py bdist_wheel

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Features
5555
Requirements
5656
------------
5757

58-
* **Python**: 3.4, 3.5, 3.6
58+
* **Python**: 3.4, 3.5, 3.6, 3.7
5959
* **Django**: 1.11, 2.0, 2.1
6060
* **DRF**: 3.9
6161
* **django-filter**: 2.0

tests/perf/__init__.py

Whitespace-only changes.

tests/perf/tests.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import argparse
22
from timeit import repeat
33

4-
from django.test import TestCase, override_settings
4+
from django.test import TestCase, override_settings, tag
55
from rest_framework.test import APIRequestFactory
66

77
from tests.perf import views
@@ -20,6 +20,7 @@
2020
verbosity = args.verbosity
2121

2222

23+
@tag('perf')
2324
class PerfTestMixin(object):
2425
"""
2526
This mixin provides common setup for testing the performance differences

tests/test_complex_ops.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
from operator import attrgetter
23
from urllib.parse import quote
34

@@ -12,14 +13,20 @@
1213

1314

1415
def encode(querysting):
15-
return quote(querysting) \
16-
.replace('-', '%2D')
16+
"""Mimics the encoding logic of the client."""
17+
result = quote(querysting)
18+
19+
# Python 3.7 added '~' to the reserved character set.
20+
if sys.version_info < (3, 7):
21+
result = result.replace('%7E', '~')
22+
23+
return result
1724

1825

1926
class DecodeComplexOpsTests(TestCase):
2027

2128
def test_docstring(self):
22-
encoded = '%28a%253D1%29%20%26%20%28b%253D2%29%20%7C%20%7E%28c%253D3%29'
29+
encoded = '%28a%253D1%29%20%26%20%28b%253D2%29%20%7C%20~%28c%253D3%29'
2330
readable = '(a%3D1) & (b%3D2) | ~(c%3D3)'
2431
result = [
2532
('a=1', False, QuerySet.__and__),
@@ -106,7 +113,7 @@ def test_invalid_ops(self):
106113
])
107114

108115
def test_negation(self):
109-
encoded = '%28a%253D1%29%20%26%20%7E%28b%253D2%29'
116+
encoded = '%28a%253D1%29%20%26%20~%28b%253D2%29'
110117
readable = '(a%3D1) & ~(b%3D2)'
111118
result = [
112119
('a=1', False, QuerySet.__and__),
@@ -116,8 +123,29 @@ def test_negation(self):
116123
self.assertEqual(encode(readable), encoded)
117124
self.assertEqual(decode_complex_ops(encoded), result)
118125

126+
def test_leading_negation(self):
127+
encoded = '~%28a%253D1%29%20%26%20%28b%253D2%29'
128+
readable = '~(a%3D1) & (b%3D2)'
129+
result = [
130+
('a=1', True, QuerySet.__and__),
131+
('b=2', False, None),
132+
]
133+
134+
self.assertEqual(encode(readable), encoded)
135+
self.assertEqual(decode_complex_ops(encoded), result)
136+
137+
def test_only_negation(self):
138+
encoded = '~%28a%253D1%29'
139+
readable = '~(a%3D1)'
140+
result = [
141+
('a=1', True, None),
142+
]
143+
144+
self.assertEqual(encode(readable), encoded)
145+
self.assertEqual(decode_complex_ops(encoded), result)
146+
119147
def test_duplicate_negation(self):
120-
encoded = '%28a%253D1%29%20%26%20%7E%7E%28b%253D2%29'
148+
encoded = '%28a%253D1%29%20%26%20~~%28b%253D2%29'
121149
readable = '(a%3D1) & ~~(b%3D2)'
122150

123151
self.assertEqual(encode(readable), encoded)
@@ -129,6 +157,19 @@ def test_duplicate_negation(self):
129157
"Invalid querystring operator. Matched: ' & ~'."
130158
])
131159

160+
def test_tilde_decoding(self):
161+
# Ensure decoding handles both RFC 2396 & 3986
162+
encoded_rfc3986 = '~%28a%253D1%29'
163+
encoded_rfc2396 = '%7E%28a%253D1%29'
164+
readable = '~(a%3D1)'
165+
result = [
166+
('a=1', True, None),
167+
]
168+
169+
self.assertEqual(encode(readable), encoded_rfc3986)
170+
self.assertEqual(decode_complex_ops(encoded_rfc3986), result)
171+
self.assertEqual(decode_complex_ops(encoded_rfc2396), result)
172+
132173

133174
class CombineComplexQuerysetTests(TestCase):
134175

tox.ini

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ envlist =
99
unignore_outcomes = true
1010

1111
[testenv]
12-
commands = coverage run manage.py test {posargs}
12+
commands = coverage run manage.py test --exclude-tag=perf {posargs}
1313
envdir = {toxworkdir}/venvs/{envname}
1414
setenv =
1515
PYTHONDONTWRITEBYTECODE=1
@@ -22,14 +22,14 @@ deps =
2222

2323

2424
[testenv:performance]
25-
commands = python manage.py test tests.perf {posargs}
25+
commands = python manage.py test --tag=perf {posargs}
2626
deps =
2727
django
2828
djangorestframework
2929

3030
[testenv:warnings]
3131
ignore_outcome = True
32-
commands = python -Werror manage.py test {posargs}
32+
commands = python -Werror manage.py test --exclude-tag=perf {posargs}
3333
deps =
3434
https://github.com/django/django/archive/master.tar.gz
3535
https://github.com/tomchristie/django-rest-framework/archive/master.tar.gz
@@ -45,7 +45,7 @@ deps = flake8
4545
[testenv:dist]
4646
commands =
4747
twine check dist/*
48-
python manage.py test --no-pkgroot {posargs}
48+
python manage.py test --no-pkgroot --exclude-tag=perf {posargs}
4949
deps =
5050
django
5151
djangorestframework

0 commit comments

Comments
 (0)