Python 3-Migration

Requirements

  • Alle Third-Party-Add-Ons sollten sowohl Python 2 wie auch Python 3 unterstützen.

    Eine Übersicht, welche Add-Ons in Collective bereits auf Python 3 aktualisiert wurden, findet ihr in Python 3 porting state for Plone add-ons.

  • Zur Python-3-Migration verwenden wir six und modernize.

    sie können installiert werden mit:

    $ python3 -m venv py3env
    $ cd py3env
    $ ./bin/pip install modernize six
    

precompiler

Zusätzlich verwenden wir plone.recipe.precompiler um Syntaxfehler zu finden. Er kann mit Buildout installiert werden, indem in der py3.cfg-Datei folgendes angegeben wird:

parts += precompiler
…
[precompiler]
recipe = plone.recipe.precompiler
eggs = ${instance:eggs}
compile-mo-files = true

precompile wird jedes Mal ausgeführt, wenn ihr Bbuildout ausführt. Wenn ihr nur precompile ausführen möchtet, könnt ihr dies mit:

$ bin/buildout -c py3.cfg  install precompiler

python-modernize

python-modernize bereitet Python-2-Code automatisch für die Python-3-Portierung vor. Dabei weist euch python-modernize auf Probleme hin, die nicht automatisch gelöst werden können.

Mit bin/python-modernize -x libmodernize.fixes.fix_import  src/my.package könnt ihr euch anzeigen lassen, welche Änderungen modernize an eurem Plone-Add-on my.package vornehmen würde.

Note

Ihr könnt python-modernize u.a. mit folgenden Optionen aufrufen:

-x
schließt bestimmte Fixers aus.
-l
listet euch alle verfügbaren Fixers auf.

Note

Im Cheat Sheet Writing Python 2-3 compatible code erhaltet ihr einen Überblick, wie sich die Syntax von Python 2 zu Python 3 ändert.

  • Wir verwenden die py3.cfg aus dem Plone-5.2-Branch von vs_buildut:

    $ bin/buildout -c py3.cfg
    

Starten der Plone-Instanz

$ bin/wsgi.py

Häufige Probleme beim Starten sind:

  • Class Advice
  • Relative Imports
  • Syntax Error beim Import von async

Testen

Neben dem manuellen Testen solltet ihr automatisiert Testen mit:

$ bin/test --all -s my.package

Alternativ könnt ihr den Testrunner automatisch den Python-Debugger starten lassen mit:

$ bin/test -s my.package -D

Aktualisieren der Metainformationen

Aktualisiert die classifiers in setup.py aktualisiert:

classifiers=[
    …
    "Framework :: Plone :: 5.2",
    …
    "Programming Language :: Python :: 3.6",
    "Programming Language :: Python :: 3.7",
    "Programming Language :: Python :: 3.8",
    …
],

Häufige Probleme

Strings: Text vs. Bytes

Meist wird in Plone Text verwendet und nur in sehr seltenen Fällen Bytes.

Versucht den Code so zu ändern, dass ihr mit Beenden der Python 2-Unterstützung einfach nur das``if``-Statement löschen müsst, z.B.:

if six.PY2 and isinstance(value, six.text_type):
    value = value.encode('utf8')
do_something(value)

Dabei könnt Ihr Hilfsmethoden verwenden wie safe_text, safe_bytes, safe_unicode und safe_encode, z.B.:

from Products.CMFPlone.utils import safe_unicode
…
obj = self.context.unrestrictedTraverse(
    safe_unicode(item['_path'].lstrip('/')), None)

python-modernize ändert ebenfalls nicht from StringIO import StringIO obwohl der Import nur in Python-2 funktioniert. Für Python-3 müsst ihr überprüfen, ob es sich um Text- oder Binärdaten handelt und die import-Anweisung entsprechend schreiben:

from six import StringIO

oder:

from six import BytesIO

Weitere Informationen findet ihr im The Conservative Python 3 Porting Guide.