Skip to content

Commit d8c5431

Browse files
committed
Add tests for safe (correct) division changes in futurize
1 parent 4d7d5c4 commit d8c5431

File tree

2 files changed

+118
-6
lines changed

2 files changed

+118
-6
lines changed

future/tests/test_futurize.py

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -436,16 +436,16 @@ def addup(*x):
436436
assert addup(*(10,20)) == 30
437437
"""
438438
self.convert_check(before, after)
439-
439+
440440
@unittest.skip('not implemented yet')
441441
def test_download_pypi_package_and_test(self):
442442
URL = 'http://pypi.python.org/pypi/{0}/json'
443-
443+
444444
import requests
445445
package = 'future'
446446
r = requests.get(URL.format(package))
447447
pprint.pprint(r.json())
448-
448+
449449
download_url = r.json()['urls'][0]['url']
450450
filename = r.json()['urls'][0]['filename']
451451
# r2 = requests.get(download_url)
@@ -527,7 +527,7 @@ def test_division(self):
527527
from future.utils import old_div
528528
x = old_div(1, 2)
529529
"""
530-
self.convert_check(before, after, stages=[1])
530+
self.convert_check(before, after, stages=[1, 2])
531531

532532

533533
class TestFuturizeRenamedStdlib(CodeHandler):
@@ -546,7 +546,7 @@ def test_renamed_modules(self):
546546
import io
547547
"""
548548
self.convert_check(before, after)
549-
549+
550550
@unittest.skip('Not working yet ...')
551551
def test_urllib_refactor(self):
552552
# Code like this using urllib is refactored by futurize --stage2 to use
@@ -818,7 +818,7 @@ def test_print(self):
818818

819819
def test_print_already_function(self):
820820
"""
821-
Running futurize --stage1 should not add a second set of parentheses
821+
Running futurize --stage1 should not add a second set of parentheses
822822
"""
823823
before = """
824824
print('Hello')
@@ -1025,6 +1025,78 @@ def test_issue_12(self):
10251025
"""
10261026
self.unchanged(code)
10271027

1028+
def test_safe_division(self):
1029+
"""
1030+
Tests whether Py2 scripts using old-style division still work
1031+
after futurization.
1032+
"""
1033+
before = """
1034+
x = 3 / 2
1035+
y = 3. / 2
1036+
assert x == 1 and isinstance(x, int)
1037+
assert y == 1.5 and isinstance(y, float)
1038+
"""
1039+
after = """
1040+
from __future__ import division
1041+
from future.utils import old_div
1042+
x = old_div(3, 2)
1043+
y = old_div(3. / 2)
1044+
assert x == 1 and isinstance(x, int)
1045+
assert y == 1.5 and isinstance(y, float)
1046+
"""
1047+
self.convert_check(before, after)
1048+
1049+
def test_safe_division_overloaded(self):
1050+
"""
1051+
If division is overloaded, futurize may produce spurious old_div
1052+
calls. This test is for whether the code still works on Py2
1053+
despite these calls.
1054+
"""
1055+
before = """
1056+
class Path(str):
1057+
def __div__(self, other):
1058+
return Path(str(self) + '/' + str(other))
1059+
path1 = Path('home')
1060+
path2 = Path('user')
1061+
z = path1 / path2
1062+
assert isinstance(z, Path)
1063+
assert str(z) == 'home/user'
1064+
"""
1065+
after = """
1066+
from __future__ import division
1067+
from future.utils import old_div
1068+
class Path(str):
1069+
def __truediv__(self, other):
1070+
return Path(str(self) + '/' + str(other))
1071+
path1 = Path('home')
1072+
path2 = Path('user')
1073+
z = old_div(path1 / path2)
1074+
assert isinstance(z, Path)
1075+
assert str(z) == 'home/user'
1076+
"""
1077+
self.convert_check(before, after)
1078+
1079+
def test_range_necessary_list_calls(self):
1080+
before = """
1081+
l = range(10)
1082+
assert isinstance(l, list)
1083+
for i in range(3):
1084+
print i
1085+
for i in xrange(3):
1086+
print i
1087+
"""
1088+
after = """
1089+
from __future__ import print_function
1090+
from future.builtins import range
1091+
l = list(range(10))
1092+
assert isinstance(l, list)
1093+
for i in range(3):
1094+
print(i)
1095+
for i in range(3):
1096+
print(i)
1097+
"""
1098+
self.convert_check(before, after)
1099+
10281100

10291101
if __name__ == '__main__':
10301102
unittest.main()
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""
2+
For the ``future`` package.
3+
4+
Adds this import line:
5+
6+
from __future__ import division
7+
8+
at the top and changes any old-style divisions to be calls to
9+
future.utils.old_div so the code runs as before on Py2.6/2.7 and has the same
10+
behaviour on Py3.
11+
"""
12+
13+
from lib2to3 import fixer_base
14+
from lib2to3.fixer_util import touch_import
15+
from libfuturize.fixer_util import token, future_import
16+
17+
def match_division(node):
18+
u"""
19+
__future__.division redefines the meaning of a single slash for division,
20+
so we match that and only that.
21+
"""
22+
slash = token.SLASH
23+
return node.type == slash and not node.next_sibling.type == slash and \
24+
not node.prev_sibling.type == slash
25+
26+
class FixDivisionSafe(fixer_base.BaseFix):
27+
run_order = 4 # this seems to be ignored?
28+
29+
def match(self, node):
30+
u"""
31+
Since the tree needs to be fixed once and only once if and only if it
32+
matches, then we can start discarding matches after we make the first.
33+
"""
34+
return match_division(node)
35+
36+
def transform(self, node, results):
37+
import pdb
38+
pdb.set_trace()
39+
future_import(u"division", node)
40+
touch_import(u'future.utils', u'old_div', node)

0 commit comments

Comments
 (0)