Skip to content

Commit 3fc8f2c

Browse files
committed
WIP: futurize --conservative option
Add unit tests (not yet working) for a --conservative option to futurize that converts even difficult Py2 code to run on both Py2 and Py3.
1 parent 470914c commit 3fc8f2c

File tree

2 files changed

+86
-26
lines changed

2 files changed

+86
-26
lines changed

future/tests/base.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ def setUp(self):
138138
self.env = {'PYTHONPATH': os.getcwd()}
139139

140140
def convert(self, code, stages=(1, 2), all_imports=False, from3=False,
141-
reformat=True, run=True):
141+
reformat=True, run=True, conservative=False):
142142
"""
143143
Converts the code block using ``futurize`` and returns the
144144
resulting code.
@@ -160,7 +160,7 @@ def convert(self, code, stages=(1, 2), all_imports=False, from3=False,
160160
code = reformat_code(code)
161161
self._write_test_script(code)
162162
self._futurize_test_script(stages=stages, all_imports=all_imports,
163-
from3=from3)
163+
from3=from3, conservative=conservative)
164164
output = self._read_test_script()
165165
if run:
166166
for interpreter in self.interpreters:
@@ -219,7 +219,8 @@ def strip_future_imports(self, code):
219219
return '\n'.join(output)
220220

221221
def convert_check(self, before, expected, stages=(1, 2), all_imports=False,
222-
ignore_imports=True, from3=False, run=True):
222+
ignore_imports=True, from3=False, run=True,
223+
conservative=False):
223224
"""
224225
Convenience method that calls convert() and compare().
225226
@@ -239,7 +240,7 @@ def convert_check(self, before, expected, stages=(1, 2), all_imports=False,
239240
for the purpose of the comparison.
240241
"""
241242
output = self.convert(before, stages=stages, all_imports=all_imports,
242-
from3=from3, run=run)
243+
from3=from3, run=run, conservative=conservative)
243244
if all_imports:
244245
headers = self.headers2 if 2 in stages else self.headers1
245246
else:
@@ -272,7 +273,8 @@ def _read_test_script(self, filename='mytestscript.py'):
272273
return newsource
273274

274275
def _futurize_test_script(self, filename='mytestscript.py', stages=(1, 2),
275-
all_imports=False, from3=False):
276+
all_imports=False, from3=False,
277+
conservative=False):
276278
params = []
277279
stages = list(stages)
278280
if all_imports:
@@ -287,6 +289,8 @@ def _futurize_test_script(self, filename='mytestscript.py', stages=(1, 2),
287289
params.append('--stage2')
288290
else:
289291
assert stages == [1, 2]
292+
if conservative:
293+
params.append('--conservative')
290294
# No extra params needed
291295

292296
output = subprocess.check_output([sys.executable, script] + params +

future/tests/test_futurize.py

Lines changed: 77 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,83 @@ def test_issue_12(self):
10321032
"""
10331033
self.unchanged(code)
10341034

1035+
def test_range_necessary_list_calls(self):
1036+
before = """
1037+
l = range(10)
1038+
assert isinstance(l, list)
1039+
for i in range(3):
1040+
print i
1041+
for i in xrange(3):
1042+
print i
1043+
"""
1044+
after = """
1045+
from __future__ import print_function
1046+
from future.builtins import range
1047+
l = list(range(10))
1048+
assert isinstance(l, list)
1049+
for i in range(3):
1050+
print(i)
1051+
for i in range(3):
1052+
print(i)
1053+
"""
1054+
self.convert_check(before, after)
1055+
1056+
1057+
class TestConservativeFuturize(CodeHandler):
1058+
@unittest.expectedFailure
1059+
def test_basestring(self):
1060+
"""
1061+
In conservative mode, futurize would not modify "basestring"
1062+
but merely import it, and the following code would still run on
1063+
both Py2 and Py3.
1064+
"""
1065+
before = """
1066+
assert isinstance('hello', basestring)
1067+
assert isinstance(u'hello', basestring)
1068+
assert isinstance(b'hello', basestring)
1069+
"""
1070+
after = """
1071+
from past.builtins import basestring
1072+
assert isinstance('hello', basestring)
1073+
assert isinstance(u'hello', basestring)
1074+
assert isinstance(b'hello', basestring)
1075+
"""
1076+
self.convert_check(before, after, conservative=True)
1077+
1078+
@unittest.expectedFailure
1079+
def test_open(self):
1080+
"""
1081+
In conservative mode, futurize would not import io.open because
1082+
this changes the default return type from bytes to text.
1083+
"""
1084+
before = """
1085+
filename = 'temp_file_open.test'
1086+
contents = 'Temporary file contents. Delete me.'
1087+
with open(filename, 'w') as f:
1088+
f.write(contents)
1089+
1090+
with open(filename, 'r') as f:
1091+
data = f.read()
1092+
assert isinstance(data, str)
1093+
assert data == contents
1094+
"""
1095+
after = """
1096+
from past.builtins import open, str as oldbytes, unicode
1097+
filename = oldbytes(b'temp_file_open.test')
1098+
contents = oldbytes(b'Temporary file contents. Delete me.')
1099+
with open(filename, oldbytes(b'w')) as f:
1100+
f.write(contents)
1101+
1102+
with open(filename, oldbytes(b'r')) as f:
1103+
data = f.read()
1104+
assert isinstance(data, oldbytes)
1105+
assert data == contents
1106+
assert isinstance(oldbytes(b'hello'), basestring)
1107+
assert isinstance(unicode(u'hello'), basestring)
1108+
assert isinstance(oldbytes(b'hello'), basestring)
1109+
"""
1110+
self.convert_check(before, after, conservative=True)
1111+
10351112
def test_safe_division(self):
10361113
"""
10371114
Tests whether Py2 scripts using old-style division still work
@@ -1087,27 +1164,6 @@ def __truediv__(self, other):
10871164
"""
10881165
self.convert_check(before, after)
10891166

1090-
def test_range_necessary_list_calls(self):
1091-
before = """
1092-
l = range(10)
1093-
assert isinstance(l, list)
1094-
for i in range(3):
1095-
print i
1096-
for i in xrange(3):
1097-
print i
1098-
"""
1099-
after = """
1100-
from __future__ import print_function
1101-
from future.builtins import range
1102-
l = list(range(10))
1103-
assert isinstance(l, list)
1104-
for i in range(3):
1105-
print(i)
1106-
for i in range(3):
1107-
print(i)
1108-
"""
1109-
self.convert_check(before, after)
1110-
11111167

11121168
if __name__ == '__main__':
11131169
unittest.main()

0 commit comments

Comments
 (0)