« Python » : différence entre les versions

De Banane Atomic
Aller à la navigationAller à la recherche
Ligne 1 074 : Ligne 1 074 :


# lister les paquets installés avec pip seulement
# lister les paquets installés avec pip seulement
find /usr/lib/python3.6/site-packages -maxdepth 2 -name __init__.py | xargs pacman -Qo | grep 'No package'
find /usr/lib/python3.9/site-packages -maxdepth 2 -name __init__.py | xargs pacman -Qo | grep 'No package'
# Ubuntu
# Ubuntu
find /usr/local/lib/python3.6/dist-packages -maxdepth 2 -name __init__.py | xargs realpath | xargs dpkg -S 2>&1 | grep 'no path found'
find /usr/local/lib/python3.6/dist-packages -maxdepth 2 -name __init__.py | xargs realpath | xargs dpkg -S 2>&1 | grep 'no path found'

Version du 16 octobre 2021 à 12:48

Liens

Astuces

Python.svg
# Définit l'interpréteur à utiliser
#!/usr/bin/env python

""" Docstring
Multi-lignes """

# Quitte le script
exit("texte")

# déclarer une variable nulle
variable1 = None

# Mettre le programme en attente pendant N secondes
import time
time.sleep(1)

# Exécute un autre script
execfile(r'chemin vers le fichier de script')

# test si sudo a été utilisé pour lancer le script
import os
if os.getuid() == 0:
    # ok
else:
    print("Lancer le script avec sudo.")

Conventions de nommage

Package et modules (fichiers *.py) lower_case_with_underscores
Classes CapWords (PascalCase, UpperCamelCase)
Fonctions lower_case_with_underscores
Méthodes “privées” _start_with_underscores

Console I/O

Python.svg
# Affiche le texte et attend une saisie
nombre = input('Entrez un nombre > ')
print(nombre)

# Effacer la console
os.system('cls')

# Afficher du texte dans la console. %r est remplacé par la variable correspondante.
print('Texte ', variable1, ' suite')
print('Texte ' + str(variable1) + ' suite')
print('Texte {} suite'.format(variable1))

# Afficher du texte sans retour à la ligne mais avec un espace à la fin
print("Texte", end="")

# Afficher du texte sans retour à la ligne et sans espace à la fin
import sys
sys.stdout.write("Texte")

Arguments passés au script

optparse est obsolète, utiliser argparse
Python.svg
from argparse import ArgumentParser

parser = ArgumentParser(prog='myprogram', description='Courte description du programme')
# prog permet de redéfinir le nom du programme (défaut: sys.argv[0])

# argument positionnel
parser.add_argument('action')

# argument optionnel avec une valeur
parser.add_argument('-f', '--file')

# argument optionnel associé à une constante booléenne
parser.add_argument("-r", "--recursive", action="store_true", help="description de l'argument. [default: %(default)s]"))

# -h est déjà inclus par défaut
parser.add_argument('-v', '--version', action='version', version='%(prog)s v1.0 (2017-07-03)')

# Process arguments
args = parser.parse_args()

file = args.file            # -f file.txt → file.txt
recursive = args.recursive  # -r → True
usage: myprogram [-h] [-f FILE] [-r] [-v] action

Courte description du programme

positional arguments:
  action

optional arguments:
  -h, --help             show this help message and exit
  -f FILE, --file FILE
  -r, --recursive        description de l'argument. [default: False]
  -v, --version          show program's version number and exit

sys.argv

Python.svg
import sys

# nombre d'arguments (+1 pour le nom du script)
if len(sys.argv) != 2:
    exit('Utilisation: {} argument1'.format(os.path.basename(sys.argv[0])))

sys.argv[0]    # nom du script
sys.argv[1]    # premier argument

String

Python 3 utilise la table unicode pour les string.
Python.svg
# longueur de la chaîne
longueur = len(string1)  # 2

# r : raw string literals. \ n'est pas interprété
print(r'test \n test')  # test \n test

# rechercher un sous-élément, retourne l'index du sous-élément sinon -1
string2.find('deux')

# remplacer les . par des !
string2 = string1.replace(".", "!")

Concatenation and interpolation

Fichier:Py.svg
# concatenation
string1 = 'un'
string2 = string1 + ' - deux'

# l'opérateur += est déjà optimisé, un StringBuilder est inutile
string2 += ';'

# interpolation
string2 = f'{string1} - deux'

Comparison

Fichier:Py.svg
string3 = ''
# test si une chaîne est vide: empty strings are "falsy"
if not string3:
    # chaine1 est vide

# comparaison de string en ignorant la casse
if string1.lower() == string2.lower():

if string1.endswith('xxx'):

Split

Fichier:Py.svg
# split et rsplit
url = http://www.domain.fr/fichier.txt
url.split('/')      # ['http:', '', 'www.domain.fr', 'fichier.txt']
url.split('/')[-1]  # fichier.txt

# maxsplit = 1. Nb de groupes: maxsplit + 1 (le reste)
url.split('/', 1)   # ['http:', '/www.domain.fr/fichier.txt']
url.rsplit('/', 1)  # ['http://www.domain.fr', 'fichier.txt']
url.rsplit('/', 1)[1]  # fichier.txt

Nombres

Python.svg
entier = 1
décimal = 2.0

somme = entier + décimal  # 3.0
int(décimal)   # 2
float(entier)  # 1.0

Booléen

Python.svg
vrai = True
faux = False

int(vrai)  # 1
int(faux)  # 0

datetime

Python.svg
import datetime
from dateutil.parser import parse

ma_variable = f'text-{datetime.date.today()}-text}'  # text-yyyy-mm-dd-text
ma_variable = "text-%s-text" % ( datetime.date.today() )

parse('03/08/2017')                 # 2017-03-08 00:00:00
parse('03/08/2017', dayfirst=True)  # 2017-08-03 00:00:00

Python: Get Today’s Current Date and Time

If else

Python.svg
if a == b and a == c or b != c:
    commande1
    commande2
elif not b == c:
    commande3
else:
    commande4

if myInteger:
    print('myInteger is defined and not equal to 0')
if myString:
    print('myString is defined and not an empty string')

# sur un ligne
commande1 if a == b else commande2

Liste / Tableau / Array

Python.svg
myList = []
# une liste peut contenir des éléments hétérogènes: int, string
myList = ['zéro', 1, 'deux', 'trois']

myList[1]      # 1
myList[1] = 'un'
myList[:2]     # éléments 0 ≤ index < 2: zéro 1
myList[2:]     # éléments 2 ≤ index : deux trois
myList[1:3]    # éléments 1 ≤ index < 3: 1 deux
myList[-1]     # dernier élément: trois
myList[-2:]    # 2 derniers éléments: deux trois
myList[-3:-1]  # 3 derniers éléments moins le dernier: 1 deux
myList[0:4:2]  # 1 élément sur 2: zéro deux

myList.append(4)  # ['zéro', 'un', 'deux', 'trois', 4]

del myList[1]  # supprime l'élément à l'index 1
myList.pop(1)  # supprime et retourne l'élément à l'index 1
myList.remove('deux')  # supprime la première valeur correspondante

# nombre d'éléments dans myList
len(myList)  # 5

# test si myList contient 4
if 4 in myList:

# trie de la liste
myList.sort()
myList.sort(reverse=True)
# trier des caractère utf-8
import locale
# forcer la locale
locale.setlocale(locale.LC_ALL, '')
#print(locale.getlocale())
myList.sort(key=locale.strxfrm)

# concaténation des éléments d'une liste
''.join(myList)

# générer une liste d'entier
range(6)         # [0, 1, 2, 3, 4, 5]
range(5, 11)     # [5, 6, 7, 8, 9, 10]
range(0, 11, 2)  # [0, 2, 4, 6, 8, 10]

List Comprehensions: filtre et projection

Python.svg
# filtre des nombres pair à partir de [0, 1, 2, 3, 4, 5]
[x for x in range(6) if x%2 == 0]  # [0, 2, 4]
# équivalent avec filter
filter(lambda x: x%2 == 0, range(6))

# projection de [0, 1, 2, 3, 4, 5] où chaque élément est multiplié par 2 (x*2)
[x*2 for x in range(6)]  # [0, 2, 4, 6, 8, 10]
# équivalent avec map
map(lambda x: x*2, range(6))

yield

Avec yield, le code n'est pas exécuté à l'appel de la méthode mais à la demande.

Python.svg
def my_method(max_value):
    for i in range(max_value)
        yield i*2

my_generator = my_method(10)  # le code de my_method n'est pas exécuté ici
for i in my_generator:        # mais ici, à la demande

Affiche multi-colonnes

Python.svg
for a,b,c in zip(myList[::3], myList[1::3], myList[2::3]):
    print('{:<30}{:<30}{:<}'.format(a,b,c))

Tuple

Python.svg
# équivalent d'une liste mais
# - on ne peut ni ajouter ni supprimer des éléments
# - les valeurs des éléments ne peuvent être modifiées
myTuple = ('un', 'deux', 'trois')

Dictionnaires

Python.svg
dico = {}
dico = {'key a': 'value a', 'key b': 'value b'}

dico['key a']  # value a
dico['key c']  # KeyError: 'key c'
dico.get('key c')  # None
dico.get('key c', 'Unknown')  # Unknown

dico['key c'] = 'value c'
del dico['key b']
    
for k, v in dico.items():
    print(k, v)

Set

Collection d'éléments unique indexés. Utilisé pour les opérations telles que intersection ou difference

Fichier:Py.svg
my_set = set(my_list)

diff = my_set.difference(my_other_set)

For

Python.svg
animaux = ['chat', 'serpent']
for animal in animaux:
    print(animal)
    break # sort de la boucle for
    continue # passe à l'itération suivante
else:
    # on entre dans else une fois toutes les itérations parcourues
    # donc pas si break a été utilisé
    print("fin sans break")

# for avec une condition if
list = ['aa', 'ab', 'ac']

[print(x[1]) for x in list if x.endswith('b')]

for y in (x[1] for x in list if x.endswith('b')):
    print(y)

# for avec une condition lambda expression
z = lambda x: print(x[1]) if x.endswith('b') else None
[z(x) for x in list]

for folder in filter(lambda folder: os.path.isdir(os.path.join(cwd, folder)), os.listdir()):

While

Python.svg
i = 0
while i < 10:
    i += 1

list = [1, 2, 3]
while 3 in list:

Exceptions

Python.svg
try:
    raise Exception('EEE')
except ImportError:  # capture les exceptions de type ImportError
    pass
except (RuntimeError, TypeError, NameError):  # capture les exceptions de type RuntimeError, TypeError et NameError
    pass
except Exception as e:  # permet d’accéder à l'instance de l'exception
    print(e)  # affiche le message d'erreur
except:  # capture toutes les exceptions restantes
    raise  # relance l'exception précédemment capturée
else:  # contient le code qui sera exécuté si aucune exception n'est lancée dans le bloc try
    pass

Expressions rationnelles

Méthodes
match() Determine if the RE matches at the beginning of the string.
search() Scan through a string, looking for any location where this RE matches.
findall() Find all substrings where the RE matches, and returns them as a list.
finditer() Find all substrings where the RE matches, and returns them as an iterator.
split() Split the string into a list, splitting it wherever the RE matches
sub() Find all substrings where the RE matches, and replace them with a different string
subn() Does the same thing as sub(), but returns the new string and the number of replacements
Compilation Flags
DOTALL, S Make . match any character, including newlines
IGNORECASE, I Do case-insensitive matches
MULTILINE, M Multi-line matching, affecting ^ and $
^ devient le début de ligne au lieu du début du texte
$ devient la fin de ligne au lieu de la fin du texte

search

Python.svg
import re

# compiler l'expression rationnelle si elle est utilisée plusieurs fois
regex = re.compile('expression rationnelle')
match = re.search(regex, 'texte')
if match:
	print('Une correspondance a été trouvée: ', match.group(0))
else:
	print "l'expression %r n'a pas été trouvée" % (regex)

# Utilisation des groupes
match = re.search(r"(\w+) (\w+)", "John Smith")
print match.group(0) # 'John Smith', retourne la correspondance complète
print match.group(1) # 'John', retourne la correspondance avec le groupe 1
print match.group(2) # 'Smith', retourne la correspondance avec le groupe 2

finditer

Python.svg
for match in re.finditer('(?P<groupe1>\d+) (?P<groupe2>\d+)', texte):
    # regroupe les résultats dans un dictionnaire au lieu d'un tableau
    match.groupdict()
    # match.group('groupe1')

Substitution

Python.svg
import re

nouveauTexte = re.sub('expression rationnelle', 'substitution', 'texte')

# Avec le drapeau MULTILINE
nouveauTexte = re.sub(re.compile('expression rationnelle', re.MULTILINE), 'substitution', 'texte')
# Normalement avec Python 2.7 on devrait pouvoir écrire
nouveauTexte = re.sub('expression rationnelle', 'substitution', 'texte', flags=re.MULTILINE)
# mais ça ne marche pas avec IronPython 2.7

# Exemple avec les groupes
re.sub('(texte) (intéressant)', '\g<2> \g<1>', 'un texte intéressant')
# un intéressant texte

Fonctions

Python.svg
def my_function(arg1, arg2):
    '''
    Description de la fonction.
    :param arg1: Description de l'argument.
    :param arg2: Description de l'argument.
    :return: Description du contenu retourné par la fonction.
    '''
    return f'{arg1} - {arg2}'

# type hinting, permet d'informer sur les types attendus des arguments des fonctions ainsi que du type de retour
def my_function(arg1: str, arg2: str) -> str:
    return f'{arg1} - {arg2}'

# appel de la méthode
my_function('start', 'end')  # start - end

# argument optionnel
def my_function(arg1, arg2 = 'end'):
    return f'{arg1} - {arg2}'

# appel de la méthode
my_function('start')  # start - end
my_function('start', 'next')  # start - next

# liste d'arguments. args est un tuple.
def my_function(*args):
    return ' - '.join(args)

# appel de la méthode
my_function('start', 'next', 'end')  # start - next - end

# dictionnaire d'arguments (keywords arguments).
def my_function(**kwargs):
    for k, v in kwargs.items():
        yield f'{k} - {v}'

# appel de la méthode
'\n'.join(my_function(un = 1, deux = 2))
# un - 1
# deux - 2

Modules et Packages

  • Les modules sont des fichiers *.py
  • Les packages sont des dossiers qui représentent les namespaces. Ils contiennent un fichiers __init__.py
__init__.py
# par défaut tous les modules d'un package sont accessible
# pour rendre des modules inaccessibles, il faut redéfinir __all__ en listant seulement les modules accessibles
__all__ = ["module1"]

POO

Classe

my_class.py
class MyClass(object):  # hérite de object
    """ documentation pour la classe
    multi-lignes """

    # accessible depuis la classe et ses instances.
    # tant que l'instance ne modifie pas la valeur elle est égale à celle de la classe
    # l'instance peut modifier la valeur sans que la valeur de la classe soit modifiée
    classAttribute = 0

    # Initialiseur
    def __init__(self, someValue):
        """ documentation du constructeur """
        self.MyAttribute = someValue

    # méthode d'instance, self représente l'instance de l'objet courant
    def myMethod(self, Arg1, Arg2 = 0):
        self.MyAttribute = Arg1
        return Arg2

    # méthode de classe, cls représente la classe de l'objet courant
    @classmethod
    def myClassMethod(cls):
        cls.classAttribute += 1

    # méthode statique
    @staticmethod
    def myStaticMethod():
        MaClass.classAttribute += 1
main.py
from my_class import MyClass

if __name__ == '__main__':
    
    myObject = MyClass("Arg1")
    
    # Afficher tous les attributs d'un objet
    print(dir(myObject))
    
    print(myObject.MyAttribute)  # Arg1
    
    print(myObject.classAttribute)  # 0
    print(MyClass.classAttribute)  # 0
    
    retour = myObject.myMethod("Arg2", 10)
    print(myObject.MyAttribute)  # Arg2
    print(retour)  # 10

    MyClass.myClassMethod()
    print(MyClass.classAttribute)  # 1
    
    MyClass.myStaticMethod()
    print(MyClass.classAttribute)  # 2
Tous les arguments sont passés par référence

Héritage

Python.svg
class A():
    def __init__(self):
        self.Attribute1 = 10
    
    def Who(self):
        print("A")

class B():
    def Who(self):
        print("B")

# il est possible d'hériter de plusieurs classes, l'héritage se fait dans l'ordre d'écriture A puis B
class C(A, B):
    # si aucun constructeur n'est définit, c'est celui de la première classe parente qui est appelé (A)
    def __init__(self):
        # appel explicite du constructeur de la classe parente A
        A.__init__(self)
        # code équivalent
        super(B).__init__(type(self))

    # surcharge de la méthode Who
    def Who(self):
        # A.Who(self)
        print("B")

Variables globales

Python.svg
globvar = 0

def modifyGlobvar1():
    # globvar est ici zûne variable locale à la fonction modifyGlobvar1
    globvar = 1

def modifyGlobvar2():
    # pour pouvoir modifier la variable globale, il faut utiliser le mot-clé global
    global globvar
    globvar = 2

def printGlobvar():
    # comme aucune variable globvar n'existe au niveau de la fonction, on va chercher un niveau plus haut pour l'accès en lecture
    print(globvar)

printGlobvar()  # 0

modifyGlobvar1()
printGlobvar()  # 0

modifyGlobvar2()
printGlobvar()  # 2

Fichiers

Création - suppression - copie

Python.svg
import os

# déplacer un fichier, le fichier de destination est écrasé s'il existe
os.rename('/dossier1/fichier1', '/dossier2/fichier2')

# supprimer un fichier
os.remove(r'chemin vers le fichier')

Lecture - écriture

Python.svg
# mode d'ouverture:
# r → read
# w → write, écrase le contenu du fichier
# a → append, ajoute à la fin du fichier, s'il n'existe pas le fichier est créé
with open('chemin vers le fichier', 'r') as fichier:

    # lit tout le contenu du fichier et renvoie une chaîne de caractères unique
    contenuFichier = fichier.read()

    # lecture ligne par ligne
    for line in fichier.read_lines():
    
    fichier.write('texte')

Télécharger un fichier

Python.svg
import requests
import shutil

url = 'http://www.doamin.fr/file.zip'

local_filename = url.split('/')[-1]  # file.zip

r = requests.get(url, stream=True)
    
with open(local_filename, 'wb') as f:
    shutil.copyfileobj(r.raw, f)

Répertoires

Création - suppression - copie

Python.svg
import os, shutil
# création d'un répertoire
os.mkdir(r'chemin vers un dossier')
# supprimer un dossier et son contenu récursivement
shutil.rmtree(r'chemin vers le dossier')
# copier un dossier et son contenu récursivement
shutil.copytree('source', 'destination')
# ignore permet de filtrer les fichiers et dossiers à ne pas copier
shutil.copytree('source', 'destination', ignore=shutil.ignore_patterns('*.log', '*.py'))

Parcourt

Python.svg
import os, glob

# renvoie la liste des noms des dossiers du répertoire passé en paramètre
folder_names = [x.name for x in os.scandir('/media/data') if x.is_dir()]
# renvoie la liste des chemins des fichiers du répertoire passé en paramètre
file_names = [x.path for x in os.scandir('/media/data') if x.is_file()]

# renvoie la liste des noms des fichiers et dossiers du répertoire passé en paramètre
for name in os.listdir('/path/folder'):

# utilisation des caractères * et ? dans le chemin
for path in glob.glob(r'/chemin/vers/un/dossier/*.ext'):

# parcourt récursif du dossier passé en paramètre
#  root contient le chemin complet vers le dossier parcourut
#  dirs contient la liste des sous-répertoires du dossier parcourut
#  files contient la liste des fichiers du dossier parcourut
# le paramètre topdown=False permet de parcourir l'arbre de bas en haut
for root, dirs, files in os.walk(r'chemin vers un dossier'):

Path

Python.svg
import os, os.path

# test si le chemin correspond à un fichier ou à un dossier
if os.path.exists(r'chemin vers un dossier'):
# test si le chemin correspond à un fichier
if os.path.isfile(r'chemin vers un fichier'):
# test si le chemin correspond à un dossier
if os.path.isdir(r'chemin vers un dossier'):

# obtient le chemin vers le répertoire contenant le fichier spécifié
directoryPath = os.path.dirname(r'chemin vers le fichier')
# obtient uniquement le nom du fichier spécifié
fileName = os.path.basename(r'chemin vers le fichier')
# obtenir l'extension d'un fichier.
# splitext renvoit : "fichier" et ".ext" dans un tableau
os.path.splitext(r'chemin vers un fichier')[1]

# donne le chemin courant
os.getcwd()
# change le chemin courant
os.chdir('/path')
# concatène intelligemment deux chemins
os.path.join('/path', 'file-name.ext')
# renvoit le chemin courant concaténé au chemin spécifié
os.path.abspath('/path')
os.path.realpath('/path')
# renvoit le chemin vers le dossier personnel de l'utilisateur courant (C:\Users\Nicolas)
os.path.expanduser('~')
# teste si le chemin est un point de montage
os.path.ismount('/path')

# chemin vers le script courant tel qu'il a été passé dans la ligne de commande
__file__
sys.argv[0]

logging

Logger objet qui permet d'appeler les méthodes de log
Handler envoie le message de log vers une destination: console, fichier
Filter filtre les messages de log
Formatter décrit la mise en forme du message de log
Python.svg
import logging

logging.basicConfig(
  # changement du format d'affichage
  format = '%(asctime)s %(levelname)s - %(filename)s,%(funcName)s,%(lineno)d: %(message)s',
  # changement du format de date
  datefmt = '%d/%m/%Y %H:%M:%S'
  # changement du niveau de log (défaut: WARNING)
  level = logging.DEBUG,
  # log dans un fichier (défaut: console)
  filename = 'app.log')
# 06/08/2017 17:46:30 WARNING - main.py,<module>,15: LOG !!!

# logging représente le logger root
logging.warning('LOG !!!')  # WARNING:root:LOG !!!

try:
    # ...
except Exception, e:
    logging.error('Failed', exc_info=True)  # affiche la Traceback

Handlers

Permet de loguer dans plusieurs destinations en même temps.

Python.svg
import logging.handlers

logger = logging.getLogger()  # logger root
logger.setLevel(logging.NOTSET)  # par défaut à WARNING

filehandler = logging.handlers.RotatingFileHandler('main.log', maxBytes=1024, backupCount=1)
filehandler.setLevel(logging.ERROR)
filehandler.setFormatter(
	logging.Formatter(
		'%(asctime)s %(levelname)s - %(name)s,%(filename)s,%(funcName)s,%(lineno)d: %(message)s',
		datefmt = '%d/%m/%Y %H:%M:%S'))
logger.addHandler(filehandler)

consolehandler = logging.StreamHandler()
consolehandler.setLevel(logging.INFO)
consolehandler.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
logger.addHandler(consolehandler)

logger.error('Test !!!')

Loggers

Sélectionne le logger à utiliser en fonction du besoin.

Python.svg
# __name__ correspondant à Package.Module, permet de récupérer le logger du module courant
logger = logging.getLogger(__name__)
# si aucun logger ne correspond à Package.Module, on cherche son parent Package, sinon root

Fichier de configuration

Python.svg
import yaml  # installer python-yaml

with open('logging_configuration.yaml', 'rt') as f:
    config = yaml.safe_load(f.read())

logging.config.dictConfig(config)
logging_configuration.yaml
version: 1  # obligatoire
disable_existing_loggers: False  # True par défaut, désactive les loggers définis avant l'appel dictConfig
formatters:
    file_formatter:
        format: "%(asctime)s %(levelname)s - %(name)s,%(filename)s,%(funcName)s,%(lineno)d: %(message)s"
    console_formatter:
        format: "%(levelname)s - %(message)s"

handlers:
    console:
        class: logging.StreamHandler
        level: INFO
        formatter: console_formatter
        stream: ext://sys.stdout

    file_handler:
        class: logging.handlers.RotatingFileHandler
        level: ERROR
        formatter: file_formatter
        filename: info.log
        maxBytes: 1024
        backupCount: 1
        encoding: utf8

root:
    level: NOTSET  # par défaut à WARNING, ignore donc DEBUG et INFO
    handlers: [console, file_handler]

coloredlogs

Bash.svg
pip install coloredlogs
# Installe coloredlogs et sa dépendance humanfriendly
logging_configuration.yaml
formatters:
    colored_console_formatter:
        (): coloredlogs.ColoredFormatter
        level_styles:  # black, blue, cyan, green, magenta, red, white, yellow
            debug:
                color: green
            verbose:
                color: magenta
            info:
                color: cyan
            warning:
                color: yellow
            error:
                color: red
            critical:
                color: red
                bold: True
        field_styles:
            hostname:
                color: magenta
            programname:
                color: cyan
            name:
                color: blue
            levelname:
                color: white
                bold: True
            asctime:
                color: green
        format: "%(levelname)s - %(message)s"

python-sh

Permet d'appeler les commandes bash sous forme de méthodes python.

Python.svg
from sh import pgrep

print(pgrep('firefox'))
Bash.svg
# installation
pacman -S python-sh

Appel système

Python.svg
import subprocess

# appel d'une commande bash
subprocess.run(["ls", "-a", "-l"])  # permet de gérer les espaces dans les arguments
subprocess.run("ls -a -l", shell=True)
# redirige stdout
subprocess.run(["ls", "-l"], stdout=subprocess.DEVNULL)

# appel d'un script bash, inutil d'ajouter shell=True si le script contient #!/usr/bin/bash
completedProcess = subprocess.run("./my-script.sh")
print(completedProcess.returncode)

# lance une exception si le script retourne une valeur ≠ de 0
try:
    subprocess.run("./my-script.sh", check=True)
except Exception as e:
    print(e)  # Command './my-script.sh' returned non-zero exit status 127.

# enregister stdout dans une variable
completedProcess = subprocess.run("./my-script.sh", stdout=subprocess.PIPE, encoding='utf-8')
sortie = completedProcess.stdout

Pipe

Python.svg
import subprocess
from subprocess import PIPE

ls = subprocess.Popen(['ls', '/path'], stdout=PIPE, stderr=PIPE)
tail = subprocess.Popen(['tail', '-n', '+5'], stdin=ls.stdout, stdout=PIPE, stderr=PIPE)

xargs = subprocess.run(['xargs'], stdin=tail.stdout, stdout=PIPE, stderr=PIPE)
print(xargs.stdout)
print(xargs.stderr)

check_call

Si le code de retour n'est pas 0, lève une CalledProcessError.

Python.svg
import subprocess
from subprocess import CalledProcessError, DEVNULL

try:
    subprocess.check_call(['ping', '-c', '1', 'remote'], stdout=DEVNULL)
except CalledProcessError as e:
    print(f'{e.returncode} - {e.cmd} - {e.output} - {e.stdout} - {e.stderr}')
    exit(f'{e.cmd[3].upper()} is not reachable.')

JSON

Fichier:Py.svg
import json

# load json content from a file
with open('/path/file.json') as my_file:
    my_dict = json.load(my_file)

# load json content from a string
my_dict = json.loads(json_content)

# access content
my_dict['my_key']

Process

Fichier:Py.svg
while ('firefox' in (p.name() for p in psutil.process_iter())):
    input('Close Firefox to continue.')

ASQ - LINQ

Préférer l'utilisation native de List Comprehensions

Équivalent de LINQ pour Python.

Bash.svg
pip install asq
Python.svg
from asq.initiators import query

words = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"]

# premier mot commençant par f: four
query(words).first(lambda w: w.startswith('f'))

SSH avec Fabric

Python.svg
from fabric import Connection

result = Connection('remote-hostname').run('ls', hide=True)
msg = "Ran {0.command!r} on {0.connection.host}, got stdout:\n{0.stdout}"
print(msg.format(result))

# ferme la connection à la sortie du with
with Connection('remote-hostname', user='usr', password='pwd') as c:
    c.get('/path/file.ext', local='/path/folder')

Archives

zip

Python.svg
import zipfile

# extraire tous le contenu de l'archive dans le dossier courant
with zipfile.ZipFile(path) as z:
    z.extractall()

gzip

Python.svg
import gzip

with gzip.open('/chemin/fichier.gz', 'rb') as f:
    content_in_bytes = f.read()
content = content_in_bytes.decode("utf-8")

CSV

Python.svg
with open(path, newline='') as csvfile:
    reader = csv.reader(csvfile, delimiter=';')
    for row in reader:
        print(row)

    # utilise la première ligne comme clés pour le dictionnaire
    reader = csv.DictReader(csvfile, delimiter=';')
    for row in reader:
        print(row['nom_colonne_1'], row['nom_colonne_5'])

pip

Gestionnaire de paquets pour python.

Il est déconseiller d'installer des paquets avec sudo.
Use python3 -m pip instead of pip
Bash.svg
# chercher un paquet
pip search "query"

# installer un paquet
pip install paquet
# désinstaller un paquet
pip uninstall paquet

# mettre à jour un paquet
pip install -U paquet
# lister les paquets à mettre à jour
pip list --outdated


# lister tous les paquets installés avec pacman et pip
pip list --format=columns

# lister les paquets installés avec pip seulement
find /usr/lib/python3.9/site-packages -maxdepth 2 -name __init__.py | xargs pacman -Qo | grep 'No package'
# Ubuntu
find /usr/local/lib/python3.6/dist-packages -maxdepth 2 -name __init__.py | xargs realpath | xargs dpkg -S 2>&1 | grep 'no path found'

# afficher des infos sur un paquet
pip show [package_name]

# lister les paquets et leurs dépendances
pipdeptree
# afficher pourquoi un paquet est installé
pipdeptree --reverse --packages [package_name]
Ubuntu:

Les paquets sont téléchargés dans $HOME/.cache/pip

Les paquets sont installés dans $HOME/.local/lib/pythonX.X/site-packages ou /usr/local/lib/python3.6/dist-packages
ArchLinux:

Les paquets à installer se nomment python-pip ou python2-pip
Et les commandes sont pip ou pip2.

Les paquets sont installés dans /usr/lib/pythonX.X/site-packages

Erreurs

TypeError: '>' not supported between instances of 'Version' and 'Version'

Désinstaller la version pip du système et installer celle fournie par pypa.

Bash.svg
# upgrade pip (ubuntu)
pip3 install --upgrade pip