Python 3 Migration Guideline

Overview

Within Cinema 4D R23, Python switched to Python 3.7.7.
Python 3.X is not always compatible with Python 2.X, some functions or syntax need to be fixed.

The upgrade affect all the locations where Python is used (e.g. plugins, scripts, tags, expressions, …) and Python 2 code is not anymore working.

Cinema 4D API is almost not touched by this porting, and if your code mainly use Cinema 4D API, the only required change is about ByteSeq.
In Python 2.X a str type defined a text and a byte. The Cinema 4D API made clear distinction with c4d.storage.ByteSeq to handle bytes.
Since Python 3 address the str issue, c4d.storage.ByteSeq is removed. For more information see c4d.storage.BitSeq Replacement.
This is the only change on the Cinema 4D API side.

Note

This guide will not cover everything needed regarding how to port Python 2 to Python3.
Many guides are available on the net which are more complete, find a no-exhaustive list:

Manual Converting

If you are familiar enough with Python 2 and Python3, it’s recommended to review your code base to spot issues.
Find a no-exhaustive list of the most common issues:
  • In Python 2, the str type was used for text and bytes, whereas in Python 3, these are separate and incompatible types. - str represents text (previously it was str or unicode) - bytes is a sequence of integers between 0 and 255.

  • print is switched from a statement to a function
    # This is not anymore valid in Python 3
    print "something"
    
    # This is valid in Python 2.7 and Python3
    print("something")
    
  • xrange is removed in favor of range

  • long type is replaced by the int type

    123L # is no more valid
    
    123 # is valid
    
    # For some reason if you still rely heavily on the long type or to be compatible with both Python 2 and 3
    # it's possible to redefine the long type as bellow
    try:
       long
    except NameError:
       long = int
    
    long(123)
    
  • Division changed

    # Python 2
    1 / 3 # is equal to 0
    
    # Python 3
    1 / 3 # is equal to 0.33333333
    1 // 3 # is equal to 0
    
  • Exception Message are removed

    # next code is only compatible in Python 2.7
    except ValueError as exception: # Or any other exception
        exception.message
    
    # next code is compatible in Python 2.7 and 3.X
    except ValueError as exception:
        print(exception.args[0])
    
  • PyCObject_AsVoidPtr is replaced by PyCapsule_GetPointer

    # next code is only compatible in Python 2.7
    P1MSG_UN = msg.GetVoid(c4d.BFM_CORE_PAR1)
    pythonapi.PyCObject_AsVoidPtr.restype = c_int
    pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object]
    P1MSG_EN = pythonapi.PyCObject_AsVoidPtr(P1MSG_UN)
    
    # next code is only compatible in 3.X
    P1MSG_UN = msg.GetVoid(c4d.BFM_CORE_PAR1)
    pythonapi.PyCapsule_GetPointer.restype = c_int
    pythonapi.PyCapsule_GetPointer.argtypes = [py_object]
    P1MSG_EN = pythonapi.PyCapsule_GetPointer(P1MSG_UN, None)
    
Finally the Python 2/3 compatible idioms website will help you to find substitute.

Automatic Conversion

While we don’t recommend Automatic Conversion, especially due to the division change.
The Python community made the 2to3 tool to automatically update a Python 2 code into Python 3.

This tool is shipped with any installation of Python.

  1. Download Python 3.9.1 from Python Official.

  2. Install Python 3.9.1 into your system
  3. Run the script located in {PYTHON_INSTALLATION_PATH}/Tools/scripts/2to3 like so

    {PYTHON_INSTALLATION_PATH}/Tools/scripts/2to3.py -w {PathToYourFile.pyp}
    

    This will fix issues and create a .bak file containing your old file.

Note

2to3.py script need to be run over each python files.

For more information on the process please read Supporting Python 3 - 2to3.