Raw strings et chaines SMILES

Après la mise à jour sous Python 3.12 tout le monde a vu des messages SyntaxWarning en masse pourtant sur l’écriture du code lorsqu’on utilise des simples ou des double quotes, que cela soit des chaines de caractères, de la documentation comme les blocs marqués par ''' ou """ ou encore des expressions régulières. Il suffit que dans ces parties il y ait un caractère \ pour que l’ensemble soit interprété comme une séquence d’échappement problématique. Ce qui va impacter sur le codage en dur de chemins d’accès MS-DOS, mais nous donnera aussi quelques soucis dans le codage des chaînes SMILES pour les molécules, et la c’est plus embêtant.

1. Chemins d’accès et docstrings

Si nous codons en dur un chemin d’accès MS-DOS sans utiliser \\ nous aurons ce type d’alerte, qui n’impacte pas sur l’exécution du programme, mais juste sur sa syntaxe. Prenons le cas d’un mini programme de test :

Ce qui va donner (si # -*- coding: utf-8 -*- est présent) :

C:\Dev\tests-buildez\bof.py:3: SyntaxWarning: invalid escape sequence '\ '
C:\Dev\tests-buildez\bof.py:7: SyntaxWarning: invalid escape sequence '\l'
C:\local
C:\local
C:\local\bof\toto
c:\local\bof\toto
C:\local\bof\toto

Chaînes de documentation

Dans le code précédent, un caractère \ est présent dans la chaîne de documentation et Python mentionne la ligne 3. Pour corriger, il suffit de le transformer en \\ mais il faut reconnaitre que c’est moche. Dans ce que j’ai lu, ce qui est préconisé c’est de transformer ces docstrings en vrai commentaires. D’ailleurs en ligne 6 nous constatons que le \ n’impacte pas. Mais je ne peux pas m’y résoudre, je trouve qu’il y a un vrai dialogue entre ''', """, #, ## qui apparaissent avec une couleur différentes dans nos éditeurs et que l’on peut utiliser pour annoter différentiellement le code. Par exemple, quand je fais tourner un générateur de documentation/API maison, les ## ne sont pas pris en compte, il s’agit de commentaires ‘privés’ ou transitoires et c’est bien utile.
Deux résolutions sont possibles, soit de reformuler ce qui est est exprimé dans la chaine, soit d’ajouter un r sur les premières doubles ou simples quotes, par exemple r'''Je teste l'utilisation de \ dans le code.''' (le multiligne fonctionne aussi).

Chemins d’accès

Nous voyons que le problème vient de test = "C:\local" ou il aurait fallu utiliser un \\.  Mais depuis longtemps, dans les modules file (fonction file_cleanpath) ou oslocal (fonction cleanpath) de buildez, je code tout avec / sans me préoccuper de l’OS (par défaut) si c’est sous Windows ou en le spécifiant si c’est sous Linux. Les fonctions se chargent de corriger, nous voyons dans les lignes suivante qu’on peut mélanger un peu de tout, ça passe. la fonction ajoute même l’unité c: en amont de la chaine. Par contre, depuis des années, j’ai normalisé et je n’utilise plus le \ seul dans les chemins d’accès, ce qui m’arrange bien aujourd’hui.

Sous Linux la fonction marche aussi, il faut spécifier le type d’OS, par exemple file_cleanpath('/local/bof/' + '/toto/', ostype='UX') nous donnera /local/bof/toto. Dans les deux cas, ce type de fonction nous permets de faire des concaténations de chaines sans trop nous préoccuper des séparateurs / ou  \ … car il y aura toujours un moment ou ce type d’erreur se produira ! Autre avantage, tout exprimer en mode Linux, par exemple si nous changeons l’OS cible avec file_cleanpath('/local/bof/' + '/toto/', ostype='DOS') nous obtiendrons C:\local\bof\toto. Ce qui est très utile quand on travaille dans les deux mondes et que l’on doit assurer la compatibilité des codes. Si on doit changer d’unité, il faut la mentionner dans la chaîne à transformer ou utiliser cleanpath, par exemple cleanpath('/local/bof/' + '/toto/', unit="e:") donnera E:\local\bof\toto\.

Par contre, si  # -*- coding: utf-8 -*- n’est pas présent au début du code, nous aurons plus qu’une alerte mais bien une erreur de syntaxe dès la ligne 6 (en fait 7 – 1 pour comparer) :

C:\Dev\tests-buildez\bof.py:3: SyntaxWarning: invalid escape sequence '\ '
SyntaxError: Non-UTF-8 code starting with '\xe0' in file C:\Dev\tests-buildez\bof.py on line 6, but no encoding declared; see https://peps.python.org/pep-0263/ for details

2. Evolutions

En fait, depuis Python 3.6 il y avait une alerte, mais qui n’était pas affichée dans la sortie standard (deprecation warning) si le mode développement de Python n’était pas activé. Je cite la mise à jour Python 3.12 [ https://docs.python.org/3/whatsnew/3.12.html#other-language-changes ] qui est explicite :

A backslash-character pair that is not a valid escape sequence now generates a SyntaxWarning, instead of DeprecationWarning. For example, re.compile("\d+\.\d+") now emits a SyntaxWarning (« \d » is an invalid escape sequence, use raw strings for regular expression: re.compile(r"\d+\.\d+")). In a future Python version, SyntaxError will eventually be raised, instead of SyntaxWarning. (Contributed by Victor Stinner in gh-98401.)

Au passage nous voyons aussi l’impact sur les expressions régulières, il faudra prendre l’habitude d’utiliser des Raw Strings. Donc nous montons d’un cran, avec en vue, des erreurs de syntaxe (bloquantes) dans une future version de Python.

Liens et lectures

3. Chaines SMILES: isomérie cis/trans

Cette évolution touche aussi des aspects métiers. Par exemple les caractères / et \ sont utilisés pour la notation d’isoméries cis/trans ou E/Z, dans un contexte SMILES. Par exemple, CH3-CH=CH-OH va s’exprimer C\C=C\O  en SMILES. Il existe des cas de figures ou ces chaînes seront encodées dans le texte du programme : interfaces de test, transformation de molécules basées sur la manipulation de chaines de caractères, requêtes SMARTS … Encore une fois, les chaines qui ont été lues sous formes de variables à partir d’un fichier ne sont pas concernées, il ne s’agit que des SMILES qui sont exprimées dans le code. Il se peut que des paquetages de chimie, anciens ou non maintenus, soient affectés par ce type d’erreurs.

Par exemple dans les deux cas suivants, nous aurons une erreur du type SyntaxWarning: invalid escape sequence ‘\C’ :

smiles = "C\C=C\C"
à corriger avec r"C\C=C\C"
smiles = "C\C=C/C"
à corriger avec r"C\C=C/C"

Pour contourner, il faudra aussi utiliser des Raw Strings. Pour des molécules plus complexes, c’est le même problème tout dépendra de la manière dont l’isomérie est prise en compte.

Liens et lectures
Retour en haut