Future-proofing Python 2 code

Let's say you've inherited a Python 2 web app. You've already tried Python 3 and you know it's better than nutella on oreos. You know you need to switch. You already have that on your roadmap. But before that happens, there's this task that requires you to build a fresh new module and deploy it to your existing servers.

Deploying both Python versions to production is not feasible, since the new module needs to interact with some of the old code. So what do you do? You future-proof the hell out of that Python 2 code!

You quickly head to the __future__ documentation page and add imports for everything on the list:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 from __future__ import nested_scopes from __future__ import generators # 5 / 2 == 2.5 instead of 2 from __future__ import division from __future__ import absolute_import from __future__ import with_statement # print('hello') instead of print 'hello' from __future__ import print_function # '{}'.format(u'câh') no longer throws an error # because '{}' is now unicode from __future__ import unicode_literals

End everything seems right, until you type str('câh') like you would do in Python 3 and the whole world comes crashing down. The problem? You're still using Python 2 builtins. str is still a Python 2 string and as such, cannot contain unicode. The solution? Install python-future.

1 2 3 4 5 from __future__ import unicode_literals from builtins import str # works like a charm str ( 'câh' )

And again, everything seems right, until you type type('something') is str and it returns False and you lose it and flip the table in sheer frustration.

(╯°□°）╯︵ ┻━┻)

After you set your table back in place

┬─┬ノ(ಠ_ಠノ)

you decide to dig through the whole thing to see what happened.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from __future__ import unicode_literals from builtins import * type ( str ) < class ' future . types . newstr . BaseNewStr '> type ( 'something' ) < type 'unicode' > # so it makes sense that type ( 'something' ) is not str # and in case you're wondering, yes, this happens for all literals type ( dict ) < class ' future . types . newdict . BaseNewDict '> type ({}) < type 'dict' > # what you need to do instead is isinstance ( 'something' , str ) True

You probably won't need to add all the __future__ imports, as most of them have been added to Python > 2.6 and, depending on your use case, you might need to add some standard library or aliased imports.

Putting it all together: