Porting from Ipkiss 3.8 to Ipkiss 3.9 py3

Starting from IPKISS 3.9, IPKISS is available for Python 3.

Python 3 is the most recent version of Python. The Python community decided to stop supporting Python 2 in 2020, which means no improvements are added to Python 2 anymore. In addition, the Python ecosystem is now centered around Python 3.

To keep improving IPKISS, we have migrated IPKISS 3.9 to Python 3. This way we can benefit from the latest functionality, stability, safety and performance improvements that the Python ecosystem has to offer. Migration to Python 3 involves making certain changes to your code that are easy to perform by following the guidelines in this document.

IPKISS 3.9 comes in two flavors:

  • IPKISS 3.9 py2.

  • IPKISS 3.9 py3.

To make the transition to Python 3 as smooth as possible, this release does not contain changes to IPKISS’s API. This means that changes you have to make in your code relate to differences between Python 2 and Python 3, and potentially to backward incompatibilities in IPKISS. As usual, we treat backward compatibility very seriously, and only introduce incompatibilities when they fix bugs or with the goal to make improvents to the product that are hard to make without the backward incompatibility. In addition, the Python 2 and Python 3 version of IPKISS 3.9 have exactly the same codebase.

As an IPKISS user, you can follow the instructions below to migrate your existing code to Python 3:

Migration to Python 3.

This image shows the five steps for migrating to IPKISS 3.9 py3. They are explained in more detail below.

  1. Install IPKISS 3.9 py2 and set up your code editor to use the IPKISS 3.9 py2 Python interpreter. (see also creating a new project).

  2. When working with one of our officially supported PDKs, retrieve the latest Python 3 compatible PDK by using your regular channels or by contacting our support team.

  3. Update your code so that it is compatible with both Python 2 and Python 3. You can follow the guide below for more detailed steps on converting your code.

  4. Install IPKISS 3.9 py3, and set up your code editor to use the IPKISS 3.9 py3 Python interpreter.

  5. Run your code again to test that everything works as expected.

Updating your code for IPKISS 3.9 py3

There are two things to keep in mind when updating your code:

  1. Actual Python 2 to Python 3 changes.

  2. Any IPKISS-related backward incompatibilities. Those are, as always, described in detail in the IPKISS porting guides. For example, if you come from IPKISS 3.7, then first follow the porting guide 3.7 –> 3.7.1 and then the porting guide 3.7.1 –> 3.8.

Since converting code from Python 2 to Python 3 means making small changes over many places, we recommend that you use a version control system. For this you can check out our tutorial on version control.

General Python 2 to Python 3 migration

The main differences between Python 2 and Python 3 are discussed below.

Print

In Python 2, print is treated as a statement instead of a function. If you want to print out “Hello, world!” you can do so with the following print statement:

print "Hello, world!"

With Python 3, print() is now explicitly a function, so to print out the same string above, you can do so simply and easily using the syntax of a function:

print("Hello, world!")

Conveniently, the print() syntax is also backward compatible with Python 2.7, so your Python 3 print() functions can run in either version.

Division

When the two numbers on either side of the division / symbol are integers, Python 2 does floor division so that for the quotient x the number returned is the largest integer less than or equal to x. This means that when you write 5 / 2 to divide the two numbers, Python 2.7 returns the largest integer less than or equal to 2.5, in this case 2:

To override this, you could add decimal places as in 5.0 / 2.0 to get the expected answer 2.5.

In Python 3, integer division became more intuitive, as in:

5 / 2 == 2.5

You can still use 5.0 / 2.0 to return 2.5, but if you want to do floor division you should use the Python 3 syntax of //, like this:

5 // 2 == 2

This modification in Python 3 made dividing by integers much more intuitive and is a feature that is not backwards compatible with Python 2.7.

Round

Python’s round() function behaves differently on Python 2 and Python 3. Make sure to check your code that uses round() carefully.

  • In Python 2, in the case of a tie, the value provided is rounded away from zero:

    • round(2.5) == 3.0

    • round(-2.5) == -3.0

    • round(3.5) == 4.0

  • In Python 3, it is rounded to the nearest even:

    • round(2.5) == 2.0

    • round(-2.5) == -2.0

    • round(3.5) == 4.0

If you don’t want to adapt the behavior to Python 3 and would like to stick with Python 2 rounding behavior, you could use the following function:

def round_python2(val):
    # in the case of a tie, round float away from zero as in python2
    if round(val + 1) - round(val) != 1:
        return val + abs(val) / val * 0.5
    return round(val)

Ceil and floor

The functions math.ceil() and math.floor() return an integer in Python 3 while they returned a floating point number in Python 2. You may need to adapt your code if it relies on the result being a floating-point number.

Imports relative to a package

Suppose you have a package wherein you import code from one of its files in another one of its files. The package:

  • mypackage/
    • __init__.py

    • submodule1.py

    • submodule2.py

and you want to import submodule2 in submodule1.py.

In Python 2, you can just import the submodule directly, via an implicit relative import:

# Python 2 only!
import submodule2

In Python 3, this is no longer the case. You have to be more explicit:

# Python 2 and 3!
from . import submodule2

To make Python 2 code safer and more like Python 3, it’s better to prevent implicit relative imports.

Iterators

Many built-in functions and methods in Python 2 come in pairs. One function returns a list and the other an iterator. Examples of these pairs include range and xrange, items and iteritems, keys and iterkeys, values and itervalues. In Python 3, only the version that returns an iterator exists, but it uses the name of the list-returning version in Python 2 (i.e., range, items, keys and values).

The way to write compatible code depends on what you need:

  • A list, e.g. for serialisation, or to check if something is in the list

  • Iteration, where efficiency might be important.

list

iteration

list(range(n))

range(n)

list(map(f, it))

map(f, it)

list(zip(a, b))

zip(a, b)

list(d.items())

d.items()

list(d.values())

d.values()

list(d.keys())

d.keys()

Iterating over a dictionary yields its keys, so there is rarely a need to use dict.keys() or dict.iterkeys().

The __future__ module in Python

__future__ module is a built-in module in Python that is used to inherit new features that are available in Python 3. This module includes all the latest functions which were not present in Python 2. We can use this by importing the __future__ module. The basic idea of the __future__ module is to help migrate to use Python 3 features.

We can use the Python 3 print statement in the Python 2 function using the future module.

# Code in Python 2
from __future__ import print_function
print("Hello world!")

We can use Python 3 division in Python 2:

# Code in Python 2
from __future__ import division
5 / 2 == 2.5

In Python 2 we can not use Unicode but future modules allow us to use Unicode.

# Code in Python 2
print(type("Geeks"))  # ==> <type 'str'>
# Code in Python 2
from __future__ import unicode_literals
print(type("Geeks"))  # ==> <type 'unicode'>

Unicode Support

Python 2 uses the ASCII character set by default, so when you type "Hello, Sammy!" Python 2 will handle the string as ASCII. Limited to a couple of hundred characters at best in various extended forms, ASCII is not a very flexible method for encoding characters, especially non-English ones. Python 3 uses Unicode by default, which is a more versatile and robust character encoding. This means that you can easily type and display many more characters directly into your program.

In most situations, there’s no change required from your side. It is, however, important to be aware that, in Python 2, a string is of type ‘bytes’ whereas, in Python 3, a string uses Unicode by default. If you are using Unicode characters and would like your Python 3 code to be backward compatible with Python 2, you can add a u before your string.

For more information, please check the https://portingguide.readthedocs.io/en/latest/strings.html#strings section of the “Conservative Python 3 Porting Guide”.

More information

We’ve discussed the main differences between the two Python versions. However, there are more things to consider. Here are some useful links:

Python 2 to 3 code translation using 2to3

It is possible to translate your Python 2 code into Python 3 code with the help of 2to3.

2to3 is a Python program that reads Python 2.x source code and applies a series of fixers to transform it into valid Python 3.x code. The standard library contains a rich set of fixers that will handle almost all code. The 2to3 supporting library lib2to3 is, however, a flexible and generic library, so it is possible to write your own fixers for 2to3. lib2to3 could also be adapted to custom applications in which Python code needs to be edited automatically.

More information on how to use 2to3 can be found here: 2to3 documentation.

Using 2to3 in practice

Below is a practical example of using 2to3 in PyCharm. First, open the Terminal in PyCharm and run

2to3 .
Running 2to3.

We start with running 2to3 . in the terminal of PyCharm.

This will print all changes that can be performed to make your code Python 3 compatible. Below, we do one modification based on the suggestions made by 2to3:

Making first modifications after running 2to3.

In this example we change the relative import by adding a . in the import.

After making everything Python 3 compatible, our code looks like this:

Result of running 2to3.

After 2to3 is run, the code will be updated and made Python 3 compatible.

It is important to note that 2to3 might give undesired suggestions. In the example above, we did not change the second print statement and the extra list() conversion.

To make your code compatible for both Python 2 and Python 3 (which we recommend as a first step when upgrading IPKISS), it’s important not to commit changes that make your code incompatible with Python 2.

PyCharm assistance to write Python 2 + Python 3 compatible code

If you want to make sure that new code written in Python 3 is still compatible with Python 2 code (and, hence, with IPKISS <= 3.8), PyCharm has some assistance tools for this.

First go to the settings and make the following modification in the “Inspections” tab:

Setting up PyCharm so code is compatible with both Python 2 and Python 3.

In the PyCharm settings, choose the “Code is incompatible with specific Python versions” inspection option. Code should be compatible with Python 2.7 and Python 3.8.

Afterwards, errors will be visualized in the code editor, for example:

Errors when code is not Python 2 or Python 3 compatible.

PyCharm will now show errors when code is not compatible with Python 2 or Python 3.

If there are no errors shown by the editor, it means that your code will work in both Python 2 and Python 3.

Need support?

Migration to Python 3 involves making certain changes to your code that are easy to perform by following the guidelines in this document. If you encounter any difficulties while converting your code from Python 2 to Python 3, do not hesitate to reach out to our support team and we’ll be glad to help!

We also recommend that you migrate to Python 3 at your earliest convenience. Python 2 is not supported anymore by the Python community, and future releases of IPKISS will be released for Python 3 only.