Bibliothèque standard

Fonctions et types natifs

Cette section présente des fonctions et types accessibles dans l’interpréteur sans rien importer. Ce sont les builtins.

Plus d’informations et listes exhaustives :

Remarque : Parfois, on est amemnés (même si ce n’est pas forcément recommandé) à nommer un variable d’après un objet natif. Pour retrouver ledit objet natif, on peut explicitement passer par le module builtins.

Interactions avec l’utilisateur

print(*objects, sep=' ', end="\n", file=sys.stdout, flush=False)

Affiche les objects passés en paramètre sous forme de chaîne de caractères grâce au constructeur str(). Si plusieurs objets sont passés en paramètre, ils sont séparés par sep. La sortie se termine par end. Ces deux derniers paramètres doivent être nommés, tous les arguments positionnels sont considérés objets à afficher. Si aucun objet n’est fourni, l’affiche que end.

>>> print("Python", "OCaml", "C", "Java", sep=" > ")
Python > OCaml > C > Java

Afficher revient en fait à écrire dans un flux texte. Par défaut, il s’agit de la sortie standard (ce qui s’affiche sur la console). On peut changer la cible de la sortie avec le paramètre file ; l’objet passé en paramètre doit avoir une méthode write(chaine). On peut forcer l’effacement du tampon de flux en mettant le paramètre flush à True.

Pour afficher des progressions, on peut utiliser le retour chariot "\r" comme chaîne finale :

>>> import time
>>> for i in range(100):
...     print(f"{i+1} %", end="\r")
...     time.sleep(0.1)
... else:
...     print("\nTerminé !")
...
100%
Terminé !

input(prompt="")

Affiche prompt et lit une ligne sur l’entrée standard qui est convertie en chaîne de caractères (en supprimant le retour à la ligne final).

>>> print(input("Glou glou ?\n"))
Glou glou ?
Ouaf
Ouaf
>>> def interactive_add():
...     first = int(input("Entrer un premier entier : "))
...     second = int(input("Entrer un second entier : "))
...     result = first + second
...     print(f"{first} + {second} = {result}")
...     return result
...
>>> result = interactive_add()
Entrer un premier entier : 1846
Entrer un second entier : 898
1846 + 898 = 2744
>>> result
2744

Interactions avec le développeur et débogage

help([objet])

Invoque le système d’aide de Python. Si aucun paramètre n’est donné, lance l’aide interactive de Python. Le paramètre objet peut être tout objet importé ou un mot-clé sous forme de chaîne de caractères.

breakpoint(*args, **kwargs)

Sans paramètre, place dans le débogueur. Cette fonction appelle en fait sys.breakpointhook(). Il est possible de passer des paramètres à cette fonction, cf. la documentation.

globals()

Renvoie un dictionnaire contenant les variables globales du module courrant. Si appelé dans une fonction ou une méthode importée, renvoie les variables globales du module de provenance.

locals()

Renvoie un dictionnaire contenant les variables locales. Si appelé au niveau d’un module, a le même comportement que globals().

vars([object])

Renvoie objet.__dict__ si objet est renseigné, et locals() sinon.

dir([object])

Renvoie la liste des variables l’espace de nom courant, et si object est renseigné, tente de renvoyer la liste de ces attributs valides.

Types utilitaires pour les boucles

class range

Les objets range sont des objets séquentiels (donc itérables) dont les éléments sont calculés à la volée. Il s’agit d’un outil indispensable pour faire des boucles. Il y a deux manières de construire un objet range :

range(fin)

Construit un objet range qui permet d’itérer sur tous les entiers de 0 à fin.

>>> for i in range(5):
...     print(i)
...
0
1
2
3
4
range(debut, fin, pas=1)

Construit un objet range permettant d’itérer sur les entiers de debut à fin avec un pas de pas. Lève une exception ValueError si pas vaut 0.

>>> for i in range(6, -1, -2):
...     print(i)
...
6
4
2
0

Un objet range n’est pas un itérateur.

>>> next(range(1))
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
TypeError: 'range' object is not an iterator

Il s’agit d’un objet séquentiel itérable qui gère toutes les opérations communes sur de tels objets (indices, tranches, etc.). Les valeurs sont calculées à la volée grâce à la formule range_object[i] = debut + pas*i, avec comme contraintes i >= 0 et range_object[i] < fin si pas > 0 sinon range_object[i] > fin.

Attributs définis :

range.start

Valeur du paramètre debut passé au constructeur (0 par défaut).

range.stop

Valeur du paramètre fin passé au constructeur.

range.step

Valeur du paramètre pas passé au constructeur (1 par défaut).

class zip

Les objets zip permettent de construire des objets itérables agrégeant d’autres itérables.

zip(*iterables)

Construit un objet zip permettant d’itérer sur l’ensemble des itérables passés en paramètres à la fois. Le i-ème élément de cet itérateur est un tuple contenant les i-èmes éléments de chaque itérable. L’itérateur est épuisé lorsque dès qu’un des itérables en paramètre est épuisé.

>>> for t in zip("python", "java", "cpp", "ocaml"):
...     print(*t, sep=", ")
...
p, j, c, o
y, a, p, c
t, v, p, a

class enumerate

Les objets enumerate permettent d’itérer et d’énumérer à la fois.

enumerate(iterable, start=0)

Construit un objet enumerate générant des tuples contenant un compte (démarrant à start), et les objets résultant de l’itération sur l’itérable passé en paramètre.

>>> for i, c in enumerate("abc"):
...     print(f"{i} : {c}")
0 : a
1 : b
2 : c

En quelque sorte, enumerate(iterable) est l’équivalent de zip(range(len(iterable)), iterable).

Manipulation des attributs d’un objet

Les fonctions natives suivantes sont utiles pour manipuler dynamiquement les attributs d’un objet.

getattr(obj, name[, default])

Renvoie la valeur de l’attribut nommé name de l’objet obj : getattr(obj, "x") renvoie obj.x. Si name n’est pas pris en charge par obj (c’est-à-dire si obj.__getattribute__() et obj.__getattr__() ne parviennent pas à calculer name), renvoie default s’il est renseigné, ou lève une exception AttributeError sinon.

hasattr(obj, name)

Permet de tester l’existence l’attribut nommé name par obj (hasattr(obj, "x") teste l’existence de obj.x) : renvoie False si getattr(obj, name) lève une exception AttributeError, et True sinon.

setattr(obj, name, value)

Assigne value à l’attribut nommé name de obj : setattr(obj, "x", 1) est équivalent à obj.x = 1.

Ces fonctions sont équivalentes aux syntaxes classiques d’accès aux attributs et et de leur modificaion (i.e. obj.attr, obj.attr = val), elles ne permettent pas de d’éviter le mécanisme de descripteur ou les méthodes spéciales __getattribute__(), __getattr__() ou __setattr__().

>>> class Foo:
...     @property
...     def a(self):
...         print("prop access")
...         return 1
...
>>> getattr(Foo(), "a")
prop access
1
>>> setattr(Foo(), "a", 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

Exécuter, évaluer du code

exec(instruction)

Exécute la chaîne de caractères instruction en argument.

eval(expression)

Évalue la chaîne de caractères expression en argument et renvoie le résultat.

Héritage et typage

super(type_obj, obj) isinstance(obj, classinfo) issubclass(obj, classinfo)

Le père et le créateur

class object

Classe parente de toutes les classes. Toutes les classes héritent implicitement d’object.

object()

Constructeur de la classe object. Construit un objet vide auquel on ne peut assigner d’attribut et qui possède les méthodes communes à tous les objets, documentées ci-dessous.

object.__new__(classe)

Crée un objet vide. object.__new__() n’accepte qu’un type comme argument, sauf quand __init__() est définie dans une classe, au quel cas object.__new__() accepte tous les arguments de __init__(). Si on veut surcharger object.__new__(), il faudra cependant penser à créer l’objet vide en appelant object.__new__() avec la classe comme unique paramètre.

>>> class ClassWithoutInit:
...     pass
...
>>> class ClassWithInit:
...     def __init__(self, param):
...         self.attr = param
...
>>> class ClassWithNew:
...     def __new__(cls, param):
...         instance = super().__new__(cls)
...         instance.attr = param
...         return instance
...
>>> object.__new__(ClassWithOutInit)
<__main__.ClassWithoutInit object at 0x7f11b9448cc0>
>>> object.__new__(ClassWithInit, 1)
<__main__.ClassWithInit object at 0x7f11b933f400>
>>> object.__new__(ClassWithNew, 1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
object.__repr__(self)

Renvoie une chaîne de caractère indiquant le type de l’objet ainsi que son adresse mémoire.

object.__str__(self)

Renvoie object.__repr__(self).

object.__dir__(self)

Appelée quand dir() est appelée sur un objet. Renvoie un itérable des attributs de l’objet.

object.__eq__(self, other)

Appelée lors de l’opération objet == other. Compare les valeurs de hachage et renvoie True si elles sont égales.

object.__ne__(self, other)

Appelée lors de l’opération objet != other. Renvoie l’opposé deobject.__eq__(self, other).

object.__ge__(self, other)

Appelée lors de l’opération objet >= other. Renvoie NotImplemented.

object.__gt__(self, other)

Appelée lors de l’opération objet > other. Renvoie NotImplemented.

object.__le__(self, other)

Appelée lors de l’opération objet <= other. Renvoie NotImplemented.

object.__lt__(self, other)

Appelée lors de l’opération objet < other. Renvoie NotImplemented.

object.__getattribute__(self, name)

Appelée lorsqu’on accède à l’attribut name avec la syntaxe self.name. Cette méthode va chercher name dans le dictionnaire de l’instance self.__dict__. S’il est introuvable, elle va chercher successivement dans le dictionnaire du type de l’instance, puis dans toutes les classes parentes. Dans le cas où l’attribut est trouvé dans le dictionnaire d’une classe, s’il possède une méthode __get__() (c’est-à-dire s’il s’agit d’un descripteur ou par extension d’une propriété), alors celle-ci sera appelée.

object.__setattr__(self, name, value)

Appelée lorsque l’on écrit self.name = value. Le mécanisme de recherche d’attribut est le même que pour object.__getattribute__(). Dans le cas d’un descripteur, c’est __set__() qui est appelée.

object.__sizeof__(self)

Renvoie la taille occupée en mémoire de self en octets.

class type

Unique métaclasse (créateur de type) native.

type(objet)

Passer un objet à type renvoie la classe qui l’a instancié.

type(name, bases, attrs)

Pour créer un type, on appelle le constructeur avec les paramètres suivant :

  1. name : le nom du type à créer;

  2. bases: les classes parentes du type à créer (object est implicite) dans un itérable;

  3. attrs: un dictionnaire contenant des attributs à affecter au type.

re — Expressions régulières

Le module re permet d’utiliser les expressions régulières en Python. Plus d’informations : Documentation Python 3

Écrire une expression régulière

Les expressions régulières sont un excellent moyen de retrouver des motifs complexes dans une chaîne de caractères. On écrit les motifs à rechercher grâce à plusieurs caractères spéciaux:

Spécification du caractère

  • . désigne n’importe quel caractère.

  • [] permet de dire quels caractères on veut trouver ([a-e] : a, b, c, d ou e; [a-eA-E] idem avec les majuscule comprises; [+-*]: soit * soit + soit -).

  • \W désigne tout caractère non alpha-numérique.

  • \d équivaut à [0-9].

  • \D désigne tout caractère non numérique.

  • \w équivaut à [a-zA-Z0-9_].

  • \s désigne un espace.

Place du motif dans la chaîne

  • ^ (se place au début) signifie que le début de la chaine doit correspondre au motif.

  • \$ (se place à la fin) signifie que la fin de la chaine doit correspondre au motif.

Nombre d’apparition(s) consécutive(s)

  • {n} indique que le caractère précédent doit apparaître n fois.

  • {n,m} indique que le caractère précédent doit apparaître entre n et m fois.

  • * indique que le caractère précédent n’apparaît pas ou apparaît sans maximum d’occurrences (ab* correspond à a, ab, ou bien abbbbbb, etc.).

  • + indique que le caractère précédent apparaît au moins une fois (ab+ correspond à ab, abb, ou bien abbbbbb, etc.).

  • ? indique que le caractère précédent apparaît au plus une fois (équivalent à {0,1}).

Les quatre derniers qualificateurs sont dits gourmands : ils valident autant de caractères que possible. Par exemple pour "aaaaa", a{3,5} validera la chaîne en entier. Pour une version non gourmande, on suit le qualificateur d’un ? : *?, +?, ?? et {n,m}?. Un qualificateur non gourmand valide le moins de caractères possibles.

Pour contrôler le nombre d’apparitions d’un groupe de caractères, on met ceux-ci entre parenthèses ((abc)+: abc, abcabc, etc.). Cela crée un groupe de caractères, on peut le nommer en suivant la parenthèses ouvrante de ?P<nom>. Cela est utile par exemple quand on veut remplacer des caractères. On peut séparer des expression régulières par un | afin d’indiquer que plusieurs possibilités sont possibles.

Méthodes

On compile une expression régulière en utilisant la fonction compile . Cette fonction retourne un objet expression régulière (un objet Pattern) sur lequel on peut évaluer diverses méthodes. Si l’on cherche une phrase, la syntaxe sera:

import re

regex = re.compile(r"[A-Z]\w*\s?(\w+\s?)*.")

Remarque : On utilise le préfixe r devant la chaîne de caractère pour éviter d’avoir à écrire \\ au lieu d’un unique \.

On peut rechercher toutes les occurrences du motif grâce à la méthode re.finditer(motif, chaine) . Cela retourne un objet iterable. On accède aux objets en appelant next(iterable), qui retourne un objet expression rationnelle. Celui-ci contient plusieurs chaînes de caractères (une pour chaque groupe du motif), on y accède en appelant les différents groupes : objet.group(numéro ou nom).

Exemple : On veut extraire les phrases d’une chaîne de caractères.

>>> chaine = r"Je suis une phrase. Moi aussi"
>>> regex = re.compile(r"[A-Z]\w*\s?(?:\w+\s?)*.")
>>> resultats = regex.finditer(chaine)
>>> for phrase in resultats:
...     print(phrase.group(0))
...
Je suis une phrase.
Moi aussi.

On peut remplacer les motifs par d’autres motifs en utilisant la méthode re.sub. Elle prend en paramètres:

  1. le motif (chaîne de caractères ou objet expression rationnelle.)

  2. le remplacement (peut être une fonction)

  3. la chaine à traiter

  4. count=le nombre d’occurrences à remplacer

et renvoie la chaine de caractères modifiée. Lorsque l’on veut appeler un groupe de caractères nommé avec (?P<nom>), on y fait référence dans la chaine de remplacement par \g<nom>.

datetime — Objets dates

Le module datetime permet de créer des objets représentant des dates et de faire des opérations. La classe datetime.date représente une date par son année, son mois et son jour: jour = datetime.date(2017, 1, 1) correspond à la date 1 janvier 2017. La classe datetime.timedelta permet de faire des opérations sur les dates. Ses objets sont représentés par un nombre de jours (on peut construire un timedelta avec des semaines/mois/années, le constructeur convertit en jours). Le module datetime peut ausi être utilisé pour utiliser des durées plus réduites, i.e. secondes, minutes, heures, etc.

Exemple :

>>> import datetime
>>> j1 = datetime.date(2017, 1, 1)
>>> j2 = j1 + datetime.timedelta(30)
>>> j2
datetime.date(2017, 1, 31)

Documentation : Documentation Python 3

functools — Outils pour la programmation fonctionnelle

Ce module fournit des outils pour la manipulation de fonctions

Préservation des attributs d’une fonction décorée

Décorer une fonction change ses attributs (en effet, on retourne un wrapper en général): en particulier son nom et sa docstring:

>>> def f():
...     return "Hello!"
...
>>> f()
"Hello!"
>>> f
<function f at 0x0000023CECFFC1E0>
>>> def deco(f):
...     def wrapper():
...         print(f())
...         print("Done.")
...     return wrapper
...
>>> @deco
... def f():
...     return "Hello!"
...
>>> f()
Hello!
Done.
>>> f
<function deco.<locals>.wrapper at 0x0000023CEDB2EF28>

Le décorateur @wraps du module functools permet d’y remédier.

>>> from functools import wraps
>>> def deco(f):
...     @wraps(f)
...     def wrapper(*args, **kwargs):
...         print(f())
...         print("Done.")
...     return wrapper
...
>>> @deco
... def f():
...     return "Hello!"
...
>>> f()
Hello!
Done.
>>> f
<function f at 0x00000223E312DEA0>

turtle — Dessins basiques

Contient des classes pour dessiner des formes simples en faisant avancer des tortues. Elles peuvent avancer, reculer, tourner d’un certain angle. La classe Turtle permet de créer des objets tortues qui peuvent :

  1. Avancer: Turtle.forward(<nb de pixels>)

  2. Reculer: Turtle.backward(<nb de pixels>)

  3. Tourner à droite ou à gauche (ex: Turtle.right(<degrés>))

  4. Changer de couleur (Turtle.color(<couleur>)) ou de forme (Turtle.shape(<forme>)).

Exemple :

import turtle

Terrain = turtle.Screen()
Terrain.bgcolor("black")

Tortue = turtle.Turtle()
Tortue.speed(3)
Tortue.shape("turtle")
Tortue.color("white")

for i in range(50):
    for e in range(4):
        Tortue.forward(100)
        Tortue.right(90)
    Tortue.right(360/50)

Terrain.exitonclick()
Résultat

Résultat

Plus d’informations : Documentation Python 3, Wikilivres

ctypes — Appeler des fonctions en C

Ce module sert à appeler des fonctions écrites en langage C dans des librairies DLL par exemple.

Boites de dialogue

Le module ctypes peut servir à faire apparaître des boites de dialogue. On peut modifier le comportement du script Python en fonction du bouton appuyé car la fonction faisant apparaître ces boites renvoie un entier qui dépend du bouton appuyé. Diverses options sont disponibles :

# Boutons disponibles :
# 0 : OK
# 1 : OK | Annuler
# 2 : Abandonner | Recommencer | Ignorer
# 3 : Oui | Non | Annuler
# 4 : Oui | Non
# 5 : Recommencer | Annuler
# 6 : Annuler | Recommencer | Continuer

# Icone
# 16 Icone erreur
# 32 Icone question
# 48 Icone attention
# 64 Icone information

Exemple :

ctypes.windll.user32.MessageBoxW(0, "That's an error", "Warning!", 16)
Résultat

Résultat

asyncio — Programmation asynchrone

Nota Bene : Pour l’instant, cette section sort un peu de nulle part, mais tout s’éclaircira quand la syntaxe des async et await sera expliquée.

Cette bibliothèque permet de facilement effectuer de la programmation asynchrone (à ne pas confondre avec la programmation en parallèle). L’intérêt est de rendre les tâches non-bloquantes, typiquement les requêtes à des serveurs qui peuvent mettre du temps à obtenir une réponse. Cette librairie n’est pas adaptée pour les calculs longs, car elle ne permet pas de calculer plus rapidement !

Exemple Voici un code synchrone que l’on peut rendre asynchrone.

import time


def sync_get_response(id, temps_de_reponse):
    time.sleep(temps_de_reponse/1000)  # simulation temps de reponse
    print("Réponse {} reçue !".format(id))


def sync_main():
    sync_get_response(1, 50)
    sync_get_response(2, 50)
    sync_get_response(3, 4000)
    sync_get_response(4, 50)
    sync_get_response(5, 50)
    sync_get_response(6, 6000)
    sync_get_response(7, 50)
    sync_get_response(8, 50)
    sync_get_response(9, 50)

beginning = time.time()
sync_main()
print('Durée', time.time()-beginning)
Réponse 1 reçue !
Réponse 2 reçue !
Réponse 3 reçue !
Réponse 4 reçue !
Réponse 5 reçue !
Réponse 6 reçue !
Réponse 7 reçue !
Réponse 8 reçue !
Réponse 9 reçue !
Durée 10.367376565933228

On remarque que les requêtes longues ralentissent l’exécution du programme. De plus, les requêtes sont effectuées dans l’ordre.

import asyncio
import time


async def get_response(id, temps_de_reponse)
    await asyncio.sleep(temps_de_reponse/1000)
    print("Réponse {} reçue !".format(id))


async def main():
    req1 = loop.create_task(get_response(1, 50))
    req2 = loop.create_task(get_response(2, 50))
    req3 = loop.create_task(get_response(3, 1000)) # simulons une requete longue
    req4 = loop.create_task(get_response(4, 50))
    req5 = loop.create_task(get_response(5, 50))
    req6 = loop.create_task(get_response(6, 1000)) # une autre
    req7 = loop.create_task(get_response(7, 50))
    req8 = loop.create_task(get_response(8, 50))
    req9 = loop.create_task(get_response(9, 50))
    await asyncio.wait([req1, req2, req3, req4, req5, req6, req7, req8, req9])

if __name__ == '__main__':
    beginning = time.time()
    try:
        loop = asyncio.get_event_loop()
        loop.run_until_complete(main())
    except:
        pass
    finally:
        loop.close()
        print('Durée', time.time()-beginning)
Réponse 1 reçue !
Réponse 7 reçue !
Réponse 9 reçue !
Réponse 8 reçue !
Réponse 2 reçue !
Réponse 5 reçue !
Réponse 4 reçue !
Réponse 3 reçue !
Réponse 6 reçue !
Durée 5.994143724441528
# asyncio.sleep() resquillerait-il ? On lui a pourtant demandé de dormir 6 secondes !

Dans le 2e exemple, le programme n’attend pas de recevoir la réponse pour envoyer les autres requêtes.

Modules à télécharger

virtualenv — Environnements virtuels

Les environnement virtuels sont un bon moyen pour:

  1. Installer des modules sans avoir besoin des droits administrateurs

  2. Avoir plusieurs environnements de travail avec des modules Python de versions différentes. Exemple, j’ai un projet Django 2 et je veux créer un site avec Django-CMS, qui requiert Django 1! Je suis obligé de recourir aux environnements virtuels.

Pour une utilisation basique, on commence par installer virtualenv avec pip.

$ pip install virtualenv # ou pip3 selon votre version de Python

Puis on se place dans le dossier où l’on veut placer les environnements virtuels, par exemple sous Linux dans /home/votre_nom/python_env/, et on crée notre environnement!

$ virtualenv env

Python y place alors les exécutables fondamentaux et quelques modules basiques. Ensuite, pour travailler dans l’environnement créé, il faut lancer la commande:

$ source /home/votre_nom/python_env/env/bin/activate

L’environnement apparaît maintenant entre parenthèses dans la console. Pour désactiver cet environnement, on lance simplement la commande:

(env) $ deactivate

Il existe le module virtualenvwrapper qui permet de naviguer facilement entre les environnements. Après avoir installé ce paquet, il faut ajouter dans le path une variable WORKON_HOME qui correspond au répertoire où seront stockés les environnement virtuels. Ensuite on pourra utiliser les commandes

$ mkvirtualenv env # creation d'un environnement virtuel
$ workon # visualisation des environnements existants
env
(env) $ workon env # selection d'un environnement
(env) $ deactivate # quitter cet environnement

Plus d’informations : Documentation de virtualenv, informations supplémentaires

Flask — Microframework Web

Ce framework minimaliste permet de faire des sites Web sans pour autant imposer une façon de développer.

Plugins utiles:

SQLAlchemy

un ORM pour gérer plus facilement la bdd

Marsmallow

un serializer pour Python

django — Framework Web Full Stack

Ce module permet de créer des sites web en Python. Il est question ici de la version 2. Plus d’informations : Documentation officielle de Django 2.2 Tutoriel de la documentation

Django fonctionne selon l’architecture Model-View-Template (MVT) que l’on peut traduire par Modèle-Vue-Gabarit. Celle-ci s’appuie sur l’architecture Model-View-Controler (MVC):

  • Les modèles structurent de la base de données, là où sont stockées toutes les informations. Ici, ce sont des classes Python dont les attributs correspondent à des champs dans la base de données. On n’écrit jamais de SQL avec Django!

  • Les vues représentent les pages web: elles présentent les informations aux utilisateurs et récupèrent leurs actions. Ici, ce sont des fonctions Python qui prennent en argument la requête (HTTP par exemple) et des informations sur l’URL et qui renvoie, en utilisant les gabarits, la bonne page à l’utilisateur (la bonne réponse HTTP).

  • Les gabarits permettent de structurer facilement les vues. Ce sont des fichiers HTML avec un peu de syntaxe de gabarit Django.

  • Le contrôleur fait l’interface entre les vues et les modèles: il récupère et renvoie les informations nécessaires. Cette partie est gérée de manière autonome par Django.

WSGI

Ce module permet de faire tourner Python sur un serveur comme Apache. On voit ici comment déployer une application Flask ou Django avec Apache 2.4 sur un système d’exploitation Debian 9 (Stretch). On considère qu’Apache est connu. Premièrement, installer le module d’Apache pour Python 3:

$ sudo apt install libapache2-mod-wsgi-py3

Déploiement de Flask

Hôte virtuel

Notre application respecte l’arborescence:

app/
|---flaskapp.wsgi
|---FlaskApp/
    |---__init__.py
    ...

On crée un hôte virtuel pour notre application Flask.

$ cd /etc/apache2/sites-availables
<VirtualHost *:80>
    ServerName domain.com
    ServerAdmin youremail@email.com
    WSGIScriptAlias / /var/www/chemin/votre/app/flaskapp.wsgi

    <Directory /var/www/chemin/votre/app/FlaskApp>
        Require all granted # signifie que toute requête est acceptée
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/FlaskApp-error.log
    LogLevel warn
    CustomLog ${APACHE_LOG_DIR}/FlaskApp-access.log combined
</VirtualHost>

On peut prendre n’importe quel nom pour les logs.

Voici le contenu de notre fichier WSGI :

#!/usr/bin/python
# on dit à Debian d'utiliser python3

import sys
import logging

logging.basicConfig(stream=sys.stderr)
sys.path.insert(0,"/var/www/chemin/votre/app/")

# en assumant que l'on a app=Flask(__name__)
from FlaskApp import app as application

Voilà! Normalemnt ça marche :) À tester avec un Hello World.

pytaglib — Tags de fichiers audio

Ce module premet l’accès et l’écriture aux métadonnées (tags) de fichiers audio. Ce module utilise taglib.

Installation

Il faut au préalable posséder le paquet de développement de Python, python3-devel sur Fedora et le paquet de développement de taglib, taglib-devel sur Fedora. (Pour Debian, il suffit de remplacer devel par dev.)

Utilisation

>>> import taglib
>>> song = taglib.File("chemin/vers/le/fichier.mp3")
>>> song.tags
{'ARTIST': ['Foo'], 'TITLE': ['Bar']}
>>> song.length # durée en secondes
60
>>> song.tags["ARTIST"] = ["Baz"] # toujours sous forme de liste
>>> del song.tags["TITLE"]
>>> song.save()
>>> song.tags
{'ARTIST': ['Baz']}

Principaux tags:

  • TITLE: Titre du morceau

  • ARTIST: Artsite du morceau

  • ALBUM: Album

  • COMPOSER: Compositeur (utilse pour la musique classique)

  • TRACKNUMBER: Numéro de piste

  • DATE: Année de sortie