New submission from Luke Macken <lmac...@redhat.com>: Problem:
lib2to3.fixer_util.touch_import('__future__', ...) will insert the import statement below all other imports. This will then trigger the following error: SyntaxError: from __future__ imports must occur at the beginning of the file How to reproduce the issue (using modernize, which uses lib2to3): $ git clone https://github.com/mitsuhiko/python-modernize.git $ cd python-modernize $ echo << EOF >> test.py # test.py "Test case for lib2to3.fixer_util.touch_import('__future__', ...)" import os print "hi" EOF $ python modernize.py test.py --- test.py (original) +++ test.py (refactored) @@ -1,4 +1,5 @@ # test.py "Test case for lib2to3.fixer_util.touch_import('__future__', ...)" import os -print "hi" +from __future__ import print_function +print("hi") $ python3 test.py File "test.py", line 4 from __future__ import print_function ^ SyntaxError: from __future__ imports must occur at the beginning of the file The following patch to lib2to3 seems to solve the issue: --- /usr/lib64/python2.7/lib2to3/fixer_util.py.orig 2012-03-09 21:53:10.841083479 -0800 +++ /usr/lib64/python2.7/lib2to3/fixer_util.py 2012-03-09 21:58:18.678946683 -0800 @@ -306,14 +306,15 @@ # figure out where to insert the new import. First try to find # the first import and then skip to the last one. insert_pos = offset = 0 - for idx, node in enumerate(root.children): - if not is_import_stmt(node): - continue - for offset, node2 in enumerate(root.children[idx:]): - if not is_import_stmt(node2): - break - insert_pos = idx + offset - break + if package != '__future__': + for idx, node in enumerate(root.children): + if not is_import_stmt(node): + continue + for offset, node2 in enumerate(root.children[idx:]): + if not is_import_stmt(node2): + break + insert_pos = idx + offset + break # if there are no imports where we can insert, find the docstring. # if that also fails, we stick to the beginning of the file After the patch, all is well: $ python modernize.py test.py --- test.py (original) +++ test.py (refactored) @@ -1,4 +1,5 @@ # test.py "Test case for lib2to3.fixer_util.touch_import('__future__', ...)" +from __future__ import print_function import os -print "hi" +print("hi") $ python3 test.py hi ---------- components: 2to3 (2.x to 3.x conversion tool) messages: 155569 nosy: lmacken priority: normal severity: normal status: open title: lib2to3.fixer_util.touch_import('__future__', ...) can lead to SyntaxError in code type: behavior _______________________________________ Python tracker <rep...@bugs.python.org> <http://bugs.python.org/issue14282> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com