Mon premier projet Python3


Ceci est un post invité de Coyote posté sous licence creative common 3.0 unported.

Et oui, il fallait bien que ça arrive.

La genèse

Bon, ça avait commencé doucement. Il y a de ça quelques temps (avant même l’article de Sam), j’avais configuré mon Sublimissime pour qu’il me force les import du __futur__.
Étant moi-même un peu un nazi de la convention de code, ça ne m’a pas dérangé plus que cela: les keyword print et autres sont pas trop ma tasse de thé. Par contre, c’est vrai que ça m’a un peu forcé la main sur les import relatifs, que j’utilisais visiblement un peu trop.

Récemment, sur un autre projet, je me dis “allez, je passe à la syntaxe "hello {}".format("world") au lieu des "hello" % "world"” puisque c’est ce qui est désormais recommandé. Bon, c’est un peu chiant au début mais on s’y fait vite.

Aussi, j’ai adopté la suppression des prefix u devant les strings. Je sais qu’avec Python 3.3 on peut à nouveau les utiliser, mais vraiment, j’ai toujours trouvé ça moche et insupportable, alors je suis très content de ne plus avoir à me les farcir.
Que ceux que je vois râler me disent comment ils justifient qu’avec ce temple de la simplicité et de la lisibilité qu’est Python, on doivent préfixer toutes nos chaines par des petits u ridicules.

Voilà pour l’historique, lentement mais surement, je me préparais à prendre peut-être de bonnes habitudes pour le jour (très) lointain ou Python3 deviendrait réalité.

Et c’est là que mon collègue, un pervers à lunettes, nous propose d’utiliser PY3 pour de vrai, sur un nouveau projet.

C’est vrai que le projet s’y prêtait bien: un petit site web de CRUD avec Django. On s’est gratté le menton deux minutes et puis on s’est dit “pourquoi pas ?”.

Par où commencer ?

C’est con hein, mais la première chose que tu fais, c’est te demander qu’est ce qui change entre PY2 et PY3.
Et bien la réponse est pas simple du tout et si tu crois que tu vas trouver une URL avec une liste de chose à changer, tu te trompes lourdement.

Le problème est que PY3.0 avait sans doute dû être fini à la pisse et que donc les choses ont beaucoup évoluées entre 3.0, 3.1, 3.2 et 3.3. J’ai lu beaucoup de posts sans importance sur toutes ces étapes intermédiaires, mais la conclusion, c’est que grosso-modo, il faut passer de 2.7 à 3.3. Entre les deux, c’est un peu comme naitre au Sahara Occidental.

Installer PY3.3

Comme on travaille en équipe, on a des setup différents: OSX, Ubuntu 12.04 et Ubuntu 13.04.

Ça c’est passé sans douleur malgré les appréhensions. Pour Ubuntu, il suffit d’utiliser le ppa deadsnakes.
Une fois installé, un coup de virtualenv (mkvirtualenv -p /usr/bin/python3.3 monenv3) et c’est parti.

Les dépendances

Comme expliqué plus haut, on a choisi de faire ce projet en PY3 parce qu’il est petit et sans dépendances ; donc pas très représentatif.
Cependant, on utilise:
Django==1.5.4
South==0.8.2
django-mptt==0.6.0
django-picklefield==0.3.0
numpy==1.7.1
unicodecsv*

Aucun problème avec ceux là. On a cru que South nous faisait des misères mais en fait c’était un import relatif avec un pass de cochon qui foutait la merde (try: from local_settings import * except ImportError: pass.
Donc la leçon ici, c’est que les imports relatifs c’est mal.

Au niveau des dépendances, on a du se séparer de batbelt. Oui, je parle bien de sametmax/Bat-Belt qui n’est pas du tout PY3 proof. Ne pleurez pas, moi aussi j’ai été très déçu et j’attends des explications (foireuses, je les vois venir d’ici).

Bref, comme on utilise batbelt pour presque rien, on a copié honteusement (ou pas) le code nécessaire.

Dernière remarque, vous voyez dans la liste unicodecsv. C’est un peu tricky puisque PY3 supporte unicode par défaut, le module csv de PY3 fonctionne directement ; et de fait, unicodecsv n’existe plus. Oui, je me suis fait avoir comme un débutant.
Bref, comme on souhaite aussi supporter PY2 et pas uniquement PY3, on a un beau if PY2: import unicodecsv as csv else: import csv.

Les problèmes

Peu nombreux je dois dire et c’est plutôt encourageant. De tête:

  • Fini les __unicode__() dans les modèles Django.
    Pour gérer ce cas à la con, on utilise ce fichier _compat de Jinja2. Je vous encourage à le copier, il défini notamment la variable PY2 pratique pour switcher comme le cas du csv ci-dessus.
    Bref, dans ce _compat, il y a un class decorator implements_to_string qui permet de ne définir que __str__() (renvoie de l’unicode) et le reste est géré automatiquement.
    Django propose la même chose via django.utils.encoding.python_2_unicode_compatible mais je préfère la toolbox Jinja.
  • J’ai parlé dans les dépendances du cas unicodecsv. Ici c’était le seul, mais clairement dans beaucoup de projet qui manipulent des stream ou des fichiers, il va falloir faire ce genre de combines pour suporter PY2 et PY3.
  • Un edge case très rigolo (après coup!) avec le django-picklefield. Le field se comportait correctement avec PY3 mais pas avec PY2 et pas dans tous les cas. Du bonheur à tarinerdéboguer.
    Pour l’anecdote:
    x = MyModel(id=1)
    x.picklefield = [1,2,3]
    x.save()

    x = MyModel(id=2)
    x.picklefield = {'a': 1, 'b': 3}
    x.save()

    Ce code fonctionne bien avec PY3, mais avec PY2, le fait de réutiliser le même nom de variable rend le PickleField tout chose et donc il sérialise deux fois la valeur passée. Encore une fois, la leçon ici est d’être rigoureux.

  • Les fonctions du type dict.keys() et assimilés ne renvoient plus de listes, mais ont été remplacés par leur équivalents générateurs (dict.iterkeys()) et ceux-ci n’existent plus. Donc un peu de gymnastique syntaxique quand on est habitué à l’ancienne syntaxe.
  • Numpy refusait de s’installer sur certaines versions d’Ubuntu (je me souviens plus laquelle) car il ne trouvait pas un des headers de Python. C’est du au fait qu’il cherche ce header dans le même répertoire que le header précédent alors qu’il est stocké ailleurs. Un symlink fait l’affaire.
  • Enfin, le dernier problème, qui va réveler que tout ceci n’est qu’une imposture: chaussette et circus que j’utilise pour le déploiement ne sont pas compatibles PY3 !! Pas de debug ici, ça ne s’installe même pas. Résulalt: on a déployé en PY 2.7. Bon, pour vous consoler (et moi avec), le github de ces 2 projets est plein de commits récents en rapport avec PY3 donc j’imagine que ça ne saurait tarder.

Conclusion

Et bien, on a un petit projet développé à plusieurs, en PY3.3, qui est déployé en PY2.7 donc c’est possible ; on a pas rencontré de grande difficultées donc je pense que pour du web, c’est pas loin d’être mûr.

Pas grand chose à dire finalement, et c’est sans doute ça le plus important !

Allez bookmarker le site python3porting qui contient les infos sur ce qui a changé. Ca a l’air long mais en fait, y’a beaucoup de cas spécifiques.

7 thoughts on “Mon premier projet Python3

  • David Touriste

    Serais-ce un troll de dire qu’autant j’adore Python, autant toutes ces versions, sans arrêt, et non compatibles me donnent le tournis ?

    Ou suis-je juste un gros flemmard ? Je m’interroge sur ma santé mentale ^^

  • Sam

    Toute ? Il n’y en a que 2, la 2 et la 3. Et il n’y a que 2 utilisée partout : la 2.7 et la 3.3.

    Comparé aux autre langages : JS incompatible entre les différents nav et implémentations serveurs. PHP qui n’a aucune norme. Java qui en est à la version 7, possède un version mobile déclinée en plusieurs versions incompatibles, plus dalvik, plus la version open source . Ruby qui pête un truc à chaque upgrade.

    Python est, à ma connaissance, le seul langage qui ai justement assuré sa transition vers une version incompatible avec sérieux.

  • ZZelle

    Les dict.keys() & Co. de PY3 correspondent aux dict.viewkeys() & Co. de PY2 et non aux dict.iterkeys()

  • Akira

    Je me tâte à passer définitivement sur la 3.3, je crois bien que je ne suis pas sorti de l’auberge.
    Autant j’adore Python pour sa richesse et sa simplicité, autant j’ai déjà des projets perso sur des versions de python en 32 et 64 bits (SDL), sur python 2.7.5 pour la plupart et là j’ai commencé à me mettre à Django depuis quelques semaines.

    J’avoue que j’hésite vraiment à tout reprendre à 0, mon hésitation est surtout liée au fait que je ne sais pas du tout si ça en vaut vraiment la peine ?

    On y gagne quoi en réalité ? Plus de fonctionnalités, plus de facilité de codage, un code qui s’exécute plus rapidement ?

  • kontre

    Le titre est un peu trompeur, les soucis rencontrés ici sont largement dus à la compatibilité python 2.7 et python3. Si vous n’aviez cherché à ne faire que du python3 vous auriez eu sacrément moins de problème (jusqu’au déploiement, bien sûr ^^).
    En tout cas je confirme qu’assurer la compatibilité entre 2.6, 2.7 et 3.3 est pas très compliqué une fois qu’on a vu les quelques problèmes et leurs contournements.

    @Sam: sauf que les distributions stables (c’est à dire vieilles comme le monde) utilisées dans les entreprises n’ont parfois pas de version très récente. Exemple vécu, centos5 est en python2.4, et centos6 (la dernière version) est en python2.6. Heureusement les nouveaux modules ajoutés dans la 2.7 sont installables à part.

  • Sam

    @kontre: exactement, c’est pourquoi je ne pousse pas au cul pour passer à la version 3. Je m’y met doucement, mais la 2.7 a encore de beaux jours devant elle. On en trouvera encore dans 5 ans, et je pense que pendant 2 ans ce sera encore la version majoritaire.

Comments are closed.

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.