Since January 1, 2020 Python2 has been no longer supported nor
maintained. This means no improvement to Python2 should happen after
that day even if someone finds a security
problem in it. If you
still have projects/applications written in Python2, you should start
converting them. In this tutorial, I’ll discuss how to do that with
2to3
.
2to3 (read like two to three ) is a Python2 to Python3 code translation library.
Python3’s Print & Input
Let’s see example.py
def greet(name):
print "Hello, {0}!".format(name)
print "What's your name? "
name = raw_input()
greet(name)
It’s clearly written in Python2 so when we run it with Python2, we get a prompt asking for your name:
$ python2 example.py
What's your name?
Ezz
Hello, Ezz!
while with Python3, you get a SyntaxError
$ python3 example.py
File "/<path>/example.py", line 2
print "Hello, {0}!".format(name)
^
SyntaxError: invalid syntax
Let’s convert that code into Python3 with 2to3 automated Python translation from version 2 to 3. Check first that it already exists in your machine. If not, you can install it with pip:
$ pip install 2to3
and then we can run it on example.py
and see the difference between
the original Python2 code version and Python3 that we want to refactor
to:
$ 2to3 example.py
RefactoringTool: Skipping optional fixer: buffer
RefactoringTool: Skipping optional fixer: idioms
RefactoringTool: Skipping optional fixer: set_literal
RefactoringTool: Skipping optional fixer: ws_comma
RefactoringTool: Refactored example.py
--- example.py (original)
+++ example.py (refactored)
@@ -1,6 +1,6 @@
def greet(name):
- print "Hello, {0}!".format(name)
+ print("Hello, {0}!".format(name))
-print "What's your name? "
-name = raw_input()
+print("What's your name? ")
+name = input()
greet(name)
RefactoringTool: Files that need to be modified:
RefactoringTool: example.py
But this printed the difference between the source code written in
Python2 and the refactored one. If you want to write the changes to the
same file you can use the write option -w
$ 2to3 -w example.py
Now example.py
is the Python3 version of the code:
def greet(name):
print("Hello, {0}!".format(name))
print("What's your name? ")
name = input()
greet(name)
If you run it with Python3, you get the same response as Python2:
$ python3 example.py
What's your name?
Ezz
Hello, Ezz!
And don’t worry about the Python2 script because it’s backed up in this
file example.py.bak
Python3’s Range Function
Let’s see another example experimenting with this file xrange_example.py
:
for i in xrange(5):
print i
What really 2to3
program does, is that it has a list of fixers and
applies transformation on the Python2.x code to be converted into valid
Python3.x code. By default, it applies almost all
fixers to the
source code. You can list them by the 2to3 -l
command. But if you
need to choose a specific fixer, you can use the -f
option and
choose whatever fixer you like.
For example, let’s fix the xrange
function on the latest example
$ 2to3 -f xrange xrange_example.py
This will only convert xrange
to range
and forget about the rest
which is the print
statement.
If you include all
as the value of fixers or just ignore the fixer
option at all, you get both xrange
and print
transformed into
Python3 code.
To exclude specific fixer, you can use -x
option:
$ 2to3 -x xrange xrange_example.py
...
--- xrange_example.py (original)
+++ xrange_example.py (refactored)
@@ -1,2 +1,2 @@
for i in xrange(5):
- print i
+ print(i)
...
2to3 Drawback
Honestly, this library can’t solve all your problems with Python2.
For example, let’s see this time conversion using datetime standard library:
import datetime
print((datetime.datetime.fromtimestamp(1621718115)))
This code simply converts the timestamp to a datetime format and it runs by default in both Python2 and Python3 according to the time zone that your machine has.
But what if you want to change the timezone? you’ll then need to pass the value of the region to the TZ environment variable like this:
import datetime
import os
os.environ['TZ'] = 'UTC'
print((datetime.datetime.fromtimestamp(1621718115)))
And when you run it and assuming your timezone is not UTC, Python2 will output the UTC datetime. The problem is with Python3 because it will output the default timezone of your system.
So we should add this line time.tzset()
to set the new timezone:
import datetime
import os
import time
os.environ['TZ'] = 'UTC'
time.tzset()
print((datetime.datetime.fromtimestamp(1621718115)))
Conclusion
2to3
should be your first step to automatically convert your Python2
application/library into Python3. On the other hand, it’s not a silver
bullet; you still need to patiently review the differences and make sure
you do unit tests.
Wrap-up Demo
Resources
- Sunsetting Python 2
- 2to3 documentation
- Python2 vs Python3: Different result when converting to datetime from timestamp
- [Photo by Jan Kopřiva on Unsplash ]