This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: lib2to3.fixer_util.touch_import('__future__', ...) can lead to SyntaxError in code
Type: behavior Stage:
Components: 2to3 (2.x to 3.x conversion tool) Versions:
process
Status: closed Resolution: works for me
Dependencies: Superseder:
Assigned To: Nosy List: lmacken, loewis
Priority: normal Keywords: patch

Created on 2012-03-13 04:58 by lmacken, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
python-lib2to3-touch-future-import.patch lmacken, 2012-03-13 05:07 python-lib2to3-touch-future-import.patch review
Messages (4)
msg155569 - (view) Author: Luke Macken (lmacken) Date: 2012-03-13 04:58
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
msg155594 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2012-03-13 12:04
I think that's actually a bug in python-modernize, not in touch_import - or, rather, touch_import shouldn't be used to add future imports.

Instead, I think there should be a touch_future function which adds a future import, taking into account that future imports need to go before all other imports, but after a possible docstring.
msg155607 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2012-03-13 13:17
Instead of changing touch_import, I propose to add a function similar to

https://github.com/loewis/python-modernize/commit/0db885e616807d0cc6859b4035d81fd260b06a67
msg155667 - (view) Author: Luke Macken (lmacken) Date: 2012-03-13 21:06
Yep, that seems like the right solution. Thanks, Martin.
History
Date User Action Args
2022-04-11 14:57:27adminsetgithub: 58490
2012-03-13 22:05:33benjamin.petersonsetstatus: open -> closed
resolution: works for me
2012-03-13 21:06:27lmackensetmessages: + msg155667
2012-03-13 13:17:18loewissetmessages: + msg155607
2012-03-13 12:04:23loewissetnosy: + loewis
messages: + msg155594
2012-03-13 05:07:31lmackensetfiles: + python-lib2to3-touch-future-import.patch
keywords: + patch
2012-03-13 04:58:02lmackencreate