8. Python

8.1. Imposer python3 comme défaut sous debian

Surtout valable sur Buster et versions plus anciennes. En mode root dans un terminal et en partant du principe que j’ai python 3.7 sur morpho

update-alternatives --install /usr/bin/python python /usr/bin/python3.7 2

Le 2 de la fin indique la priorité. Source

8.2. Erreurs Unicode !!!

Argh le truc qui fait tout planter tout le temps. Apparemment Pour des raisons de sécurité Python3 a un interpréteur unicode strict afin de protéger contre des attaques de hacker. Vvoui mais voilà étant donné la diversité des origines de texte c’est vite la foire. En ce qui me concerne c’est le parser de urllib qui plante en essayant de décoder des chaînes de caractères des popup d’une carte folium :((.

Le hack consiste alors à encoder une chaîne en autorisant explicitement une certaine latitude dans la gestion des erreurs puis à la décoder afin d’obtenir une chaine «propre» ce qui donne quelque chose du genre:

popup_str.encode("utf-8", errors="surrogateescape").decode()

De cette façon on nettoie popup_str afin qu’un parseur ultérieur ne plante pas en la lisant. Pour plus de détail voire ces deux sites:

8.3. Tester le codec d’encodage/décodage

dans le même ordre d’idée, quand on discute avec des machines par le port série par exemple, on récupère parfois des résultats du genre b”x84xa9xfex18)Nn” et on aimerait bien savoir comment les décoder. Sans donner directement la solution il est possible de tester les codecs d’encodage et de décodage qui marchent et ceux qui ne marchent pas ! Ci-dessous une fonction qui teste tous les codecs des fonctions encode/decode de python.

def test_codec(bytes_to_decode):
  codec_list = [
      "ascii","big5","big5hkscs","cp037","cp273","cp424","cp437",\
      "cp500","cp720","cp737","cp775","cp850","cp852","cp855","cp856",\
      "cp857","cp858","cp860","cp861","cp862","cp863","cp864","cp865",\
      "cp866","cp869","cp874","cp875","cp932","cp949","cp950","cp1006",\
      "cp1026","cp1125","cp1140","cp1250","cp1251","cp1252","cp1253",\
      "cp1254","cp1255","cp1256","cp1257","cp1258","euc_jp","euc_jis_2004",\
      "euc_jisx0213","euc_kr","gb2312","gbk","gb18030","hz","iso2022_jp",\
      "iso2022_jp_1","iso2022_jp_2","iso2022_jp_2004","iso2022_jp_3",\
      "iso2022_jp_ext","iso2022_kr","latin_1","iso8859_2","iso8859_3",\
      "iso8859_4","iso8859_5","iso8859_6","iso8859_7","iso8859_8",\
      "iso8859_9","iso8859_10","iso8859_11","iso8859_13","iso8859_14",\
      "iso8859_15","iso8859_16","johab","koi8_r","koi8_t","koi8_u",\
      "kz1048","mac_cyrillic","mac_greek","mac_iceland","mac_latin2",\
      "mac_roman","mac_turkish","ptcp154","shift_jis","shift_jis_2004",\
      "shift_jisx0213","utf_32","utf_32_be","utf_32_le","utf_16",\
      "utf_16_be","utf_16_le","utf_7","utf_8","utf_8_sig",
  ]

  for codec in codec_list:
      try:
          print(codec + ": " + bytes_to_decode.decode(codec))
      except:
          print(codec + " does not work")

8.4. Le double usage du « % »

Problème qui m’est arrivé quand j’utilise % en double emploi dans une chaîne de caractère SQL c’est à dire

  • comme placeholder pour des variables

  • en tant que tel comme %

Si j’écris

st = "%s gagne 25% de plus que %s et c'est moche" % ('il','moi')

et bien ça plante ! La bonne écriture est

st = "%s gagne 25%% de plus que %s et c'est moche" % ('il','moi')

8.5. Utiliser mod_wsgi pour servir un serveur python sous Apache

  • What is this ? L’idée ici est d’éviter de passer par les serveurs propres de python mais de les asservir à Apache2.

  • Why this ? Je souhaite permettre à mes sites python et wordpress (en ce qui me concerne) de cohabiter et d’utiliser les même ports que ce soit le 80 ou, et surtout, le 443.

Les sites wordpress que j’utilise sont servis par Apache qui bloque le port sécurisé (443). Si j’utilise cheerypy comme serveur de site je ne dispose plus que du port 80 non sécurisé. Ce n’est pas que cela m’angoisse mais la plupart des navigateurs deviennent de plus en plus méfiant vis à vis des serveurs non sécurisés qui se raréfient. Normal me direz-vous il faut bien protéger les mauvais OS qui pullulent…enfin surtout un !

  • Howto: pour pouvoir servir un site en python à côté d’un site en php il faut que l’on laisse la main à Apache. Pour cela il faut utiliser la librairie mod_wsgi. Comme la doc existante n’est pas toujours hyper claire — en tout cas j’ai du bidouiller longtemps ! — on commence donc par le plus simple bottle pour finir avec CherryPy.

8.5.1. Principe commun

Cela se passe en deux temps:

  • un fichier python avec une extension .wsgi (recommandée mais pas obligatoire vous pouvez aussi bien garder l’extension .py) qui sera le fichier de référence d’Apache,

  • une modification des sites autorisés dans /etc/apache2/sites-enabled.

8.5.2. Avec bottle

Le fichier bapp.wsgi ressemble à cela (je l’ai appelé bapp mais vous pouvez lui donner le nom que vous voulez !):

# import des librairies
import sys, os, bottle
from bottle import route, run, template

# se mettre dans le bon dir
os.chdir(os.path.dirname(__file__))


# l'application minimale
@route("/bobo")
@route("/bobo/<name>")
def index(name="memet"):
    return template("Hello {{name}}, how are you?", name=name)

# Définir l'application asservie à apache
# Apparemment elle doit toujours s'appeler application !
application = bottle.default_app()

Le fichier 000-default.conf d’Apache2 (qui se trouve dans /etc/apache2/sites-enabled/) ressemblera lui à

<VirtualHost *:80>

  #
  # Plein de truc avant ...
  #

  #
  # Facultatif ! Définition d'un démon et du nombre de process et de threads affectés
  #
  WSGIDaemonProcess bobo user=www-data group=www-data processes=1 threads=5

  #
  # Obligatoire ! Définition de l'emplacement de l'application à charger
  # WSGIScriptAlias /non_du_serveur /ou/aller/chercher/le/fichier.wsgi
  #
  WSGIScriptAlias / /var/www/bobo/bapp.wsgi

  #
  # Très conseillé voire nécessaire suivant ce qui précède !
  # Définition de propriétés du répertoire virtuel
  #
  <Directory /var/www/bobo>
      WSGIProcessGroup bobo
      WSGIApplicationGroup %{GLOBAL}
      Require all granted
  </Directory>

  #
  # Plein de truc après si on veut
  #
</VirtualHost>

Attention dans cet exemple je redéfinis la valeur de “/” donc pour voir la page d’accueil d’Apache à nouveau ou pour ajouter des sites il faut changer le routing (nom de site) de WSGIScriptAlias.

Note

Si vous disposez d’un certificat et souhaitez que votre site soit sécurisé ce qui précède doit être placé dans le fichier correspondant (a priori /etc/apache2/sites-enabled/default-ssl.conf).

8.5.3. Avec CherryPy

Plus important pour moi car tout mes serveurs sont sous CherryPy et pas sous bottle ! qui plus est aucune doc sérieuse à l’horizon pour s’en sortir la seule ref pour s’en sortir est celle de Schneide blog et franchement…

Là encore deux étapes:

  • créer le fichier python qui contient l’application pour mod_wsgi,

  • modifier le fichier de configuration des sites-enabled d’Apache.

# librairies
import sys, os
import cherrypy as chp


# repertoire de base des applications python
# ok ok c'est chez moi dans la version test
# normalement il vaut mieux éviter
base_rep = "/chemin/vers/safem_verse"
os.chdir(base_rep)
sys.path.append(base_rep)


# Ze function
def application(environ, start_response):

    data = {}
    site_dic = {
        "/": {
            "tools.staticdir.root": base_rep,
        },
        "/public": {"tools.staticdir.on": True, "tools.staticdir.dir": "./public"},
    }

    # importation de root file
    from safem_verse_root import safem_verse

    chp.tree.mount(safem_verse(data), "/safem_verse", site_dic)

    return chp.tree(environ, start_response)

Pour le xml du fichier de configuration cela ressemble à cela:

WSGIDaemonProcess safem_verse user=utilisateur group=groupe_de_l_utilisateur processes=1 threads=5
WSGIScriptAlias /safem_verse /chemin/vers/safem_verse/launch_serveur.wsgi

 <Directory /chemin/vers/safem_verse>
     WSGIProcessGroup safem_verse
     WSGIApplicationGroup %{GLOBAL}
     Require all granted
 </Directory>

Et là ou c’est cool — enfin! — c’est qu’on peut empiler les sites en CherryPy, bottle ou tout ce qu’on veut.

8.6. Recompiler mod_wsgi avec la bonne version de python

Et oui… sous Buster, par defaut, la librairie charge une version de mod_wsgi pour python2. Donc quand tout votre site fonctionne en python3, librairies included, c’est la foire ! Il faut donc recompiler mod_wsgi depuis le dépôt github (en mode root of course) puis demander gentiment à apache de le charger soit

apt-get install apache2-dev
cd /opt
wget https://github.com/GrahamDumpleton/mod_wsgi/archive/4.6.5.tar.gz
tar -xvzf 4.6.5.tar.gz
cd mod_wsgi-4.6.5
which python3.7
./configure --with-python=/usr/bin/python3.7
make

puis enregistrer la ligne suivante

LoadModule wsgi_module /opt/mod_wsgi-4.6.5/src/server/.libs/mod_wsgi.so

que j’ai pour ma part mis en fin du fichier apache2.conf.

Avertissement

Si mod_wsgi était déjà installé auparavant il faut penser à le désinstaller sinon ça plante

apt-get remove  libapache2-mod-wsgi

Ouf !

Source

8.7. Communication série

Librairie pyserial. tester si le port envoie des données

if(serialPort.in_waiting > 0):
    serialString = serialPort.readline()

Dernière modification le 2023-06-22