Introduction
Les fonctionnalités essentielles à aborder lorsqu’on souhaite apprendre et utiliser très rapidement Python :
- Python - Comprendre et démystifier virtualenv (Publication : Janvier 2020)
- Lire et écrire des fichiers JSON, traiter des données JSON avec Python (Publication : Avril 2020)
- Manipuler les arguments d’un programme Python avec les packages argparse et getopt (Publication : Avril 2020)
- Configuration applicative : variables d’environnement, fichiers ini et YAML (Publication : Avril 2020)
- Gestion des requêtes HTTP avec les packages requests et httplib2 (Publication : Avril 2020)
Dans ce chapître, comment gérer les arguments d’un programme Python.
On veut créer le programme googleindex.py
qui récupère le statut de l’indexation pour une URL donnée, programme avec 2 arguments :
python3 googleindex.py --address <url> [, --jsonauth <path to json auth file> ]
Le premier argument --address
est obligatoire, le second --jsonauth
est optionnel.
Les options courtes doivent être disponibles :
python3 googleindex.py -a <url> [, -j <path to json auth file> ]
Le tableau sys.argv
Le tableau système sys.argv
stocke les informations sur les arguments : l’indice 0 contient le nom du script,
tous les autres indices les arguments.
import sys
print("Script name : %s" % (sys.argv[0]))
print("First argument : %s" % (sys.argv[1]))
print("All arguments : %s" % (sys.argv[1:]))
python3 googleindex.py test.html google.json
Script name : googleindex.py First argument : test.html All arguments : ['test.html', 'google.json']
sys.argv
est une variable publique globale.
Un argument peut être vérifié avec un bloc try
:
import sys
try:
arg = sys.argv[2]
except IndexError:
raise SystemExit("Usage : %s url json" % (sys.argv[0]))
Utiliser sys.argv
est simple, mais nous souhaitons la syntaxe usuelle
python3 googleindex.py --address test.html --jsonauth google.json
python3 googleindex.py -a test.html -j google.json
Avec sys.argv
, ça devient alors un peu plus compliqué, chaque chaîne devenant en effet un argument :
Script name : googleindex.py
First argument : --address
All arguments : ['--address', 'test.html', '--jsonauth', 'google.json']
2 librairies existent pour gérer ces lignes de commandes plus sophistiquées :
- argparse
- getopt
Pas besoin d’installation, ces 2 packages sont dans le cœur du moteur Python.
argparse
Le package argparse
est importé et un objet argparse.ArgumentParser()
est instancié.
import argparse
parser = argparse.ArgumentParser()
Le nom du programme est disponible dans la propriété parser.prog
.
import argparse parser = argparse.ArgumentParser() print(parser.prog)
googleindex.py
Les arguments sont ajoutés avec la méthode add_argument
, très facile à utiliser :
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--address", help="URL to be checked", required=True)
parser.add_argument("--jsonauth", help="JSON Google Authentication file path")
parser.add_argument("--verbosity", help="Verbosity", action="store_false")
- pour spécifier un argument obligatoire :
required=True
- pour appliquer une constante booléenne lorsque l’argument n’est pas spécifié :
action="store_true | store_false"
. Dans l’exemple ci-dessus, la verbosité sera àFalse
si--verbosity
n’est pas donné, sinonTrue
.
Une valeur par défaut peut être définie pour les paramètres optionnels :
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--address", help="URL to be checked", required=True)
parser.add_argument("--jsonauth",
default="/home/sqlpac/google-auth.json",
help="JSON Google Authentication file path")
parser.add_argument("--verbosity", help="Verbosity", action="store_false")
Voyons un premier résultat :
python3 googleindex.py
usage: learn-argparse.py [-h] --address ADDRESS [--jsonauth JSONAUTH] [--verbosity] googleindex.py: error: the following arguments are required: --address
L’option --help
est immédiatement prête à l’emploi :
python3 googleindex.py --help
usage: googleindex.py [-h] --address ADDRESS [--jsonauth JSONAUTH] [--verbosity] optional arguments: -h, --help show this help message and exit --address ADDRESS URL to be indexed --jsonauth JSONAUTH JSON Google Authentication file path, default $HOME/google-auth.json --verbosity Verbosity
Utiliser la méthode parser_args
pour récupérer les valeurs des arguments,
l’objet résultant est un espace de nom (namespace) et chaque propriété est un argument :
args = parser.parse_args()
print(args)
print(args.address)
print(args.jsonauth)
python3 googleindex.py --address 1.html --jsonauth google.json
Namespace(address='1.html', jsonauth='google.json', verbosity=False) 1.html google.json
Le nom de la propriété est modifiable avec dest
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--address", help="URL to be checked", required=True)
parser.add_argument("--jsonauth",
default="/home/sqlpac/google-auth.json",
dest="jfile",
help="JSON Google Authentication file path")
parser.add_argument("--verbosity", help="Verbosity", action="store_false")
print(args)
print(args.jfile)
python3 googleindex.py --address 1.html --jsonauth google.json
Namespace(address='1.html', jfile='google.json', verbosity=False) google.json
Par défaut, le type de données des propriétés est un string. Pour forcer un type de données, utiliser type=<datatype>
lors de la définition de l’argument, cela renforce
automatiquement les règles de validation des types de données des arguments :
import argparse parser = argparse.ArgumentParser() … parser.add_argument("--year", type=int, default=2020, help="Year extraction") …
usage: googleindex.py.py [-h] --address ADDRESS [--jsonauth JFILE] [--verbosity] [--year YEAR] googleindex.py.py: error: argument --year: invalid int value: 'onestring'
Pour combiner les options courtes et longues (-a
, --address
), utiliser simplement add_argument('short-option','long-option',…)
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-a","--address", help="URL to be indexed", required=True)
…
Tout est prêt en très peu de lignes de code :
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-a","--address", help="URL to be indexed", required=True)
parser.add_argument("-j","--jsonauth",
help="JSON Google Authentication file path, default $HOME/google-auth.json",
default="/home/sqlpac/google-auth.json",
dest="jfile")
parser.add_argument("-y","--year",
type=int,
default=2020,
help="Year extraction")
parser.add_argument("-v","--verbosity", help="Verbosity", action="store_false")
args = parser.parse_args()
if args.year :
print('Current year selected')
…
python3 googleindex.py --address 1.html --jsonauth google.json --year 2020
Current year selected
python3 googleindex.py --help
usage: googleindex.py [-h] -a ADDRESS [-j JFILE] [-y YEAR] [-v] optional arguments: -h, --help show this help message and exit -a ADDRESS, --address ADDRESS URL to be indexed -j JFILE, --jsonauth JFILE JSON Google Authentication file path, default $HOME/google-auth.json -y YEAR, --year YEAR Year extraction -v, --verbosity Verbosity
Option nargs
Parfois on a besoin de pouvoir donner de multiples valeurs à un argument, par exemple :
python3 googleindex.py --address url1.html url2.html
Cela peut être réalisé avec l’option nargs='*'
:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-a','--address', nargs='*', help='URLs to be indexed', required=True)
…
args = parser.parse_args()
print(args.address)
print(type(args.address))
Dès lors le type de données de l’argument n’est plus un string, mais une liste :
['url1.html', 'url2.html']
<class 'list'>
Un nombre fixe de valeurs est appliqué avec l’option nargs=<int>
:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-a','--address', nargs=3, help='URLs to be indexed', required=True)
…
args = parser.parse_args()
print(args.address)
print(type(args.address))
Lorsque le nombre de valeurs reçu n’est pas celui attendu :
usage: googleindex.py [-h] -a ADDRESS [-j JFILE] [-y YEAR] [-v]
googleindex.py: error: argument -a/--address: expected 3 arguments
arguments Parent
Souvent des programmes partagent les mêmes arguments "parents" et ajoutent juste des arguments supplémentaires. On va
éviter autant que possible la redondance de code. Utiliser l’argument parents
lors de la création du parser dans le programme "enfant".
googleindex.py (script parent)
import argparse
def get_parser(h):
parser = argparse.ArgumentParser(add_help=h)
parser.add_argument("-a", "--address", nargs='*', help="URLs to be checked", required=True)
parser.add_argument("-j", "--jsonauth",
help="JSON Google Authentication file path, default $HOME/google-auth.json",
default="/home/sqlpac/google-auth.json")
return parser
if (__name__=="__main__"):
p = get_parser(h=True)
args = p.parse_args()
googleindexlang.py (script "enfant" ou child)
import googleindex
import argparse
def main(p):
child_parser = argparse.ArgumentParser(parents=[p], add_help=True)
child_parser.add_argument('-l','--lang', help='Language')
args = child_parser.parse_args()
if (__name__=="__main__"):
p = googleindex.get_parser(h=False)
main(p)
python3 googleindexlang.py --help
-h, --help show this help message and exit -a [ADDRESS [ADDRESS ...]], --address [ADDRESS [ADDRESS ...]] URLs to be checked -j JSONAUTH, --jsonauth JSONAUTH JSON Google Authentication file path, default $HOME/google-auth.json -l LANG, --lang LANG Language
L’option add_help
est à False
lorsqu’on récupère le parser parent dans le programme fils, sinon une erreur de conflit est levée :
argparse.ArgumentError: argument -h/--help: conflicting option strings: -h, --help
getopt
Le package getopt
est moins puissant que le package argparse
, il nécessite plus de code, code qui invoque le tableau système
sys.argv
.
- Les arguments obligatoires et optionnels doivent être vérifiés manuellement
- Les types de données doivent être également vérifiés manuellement
Mais il est bon de savoir comment lire/écrire et utiliser ce package.
import getopt, sys
def usage():
print("Usage : %s --address <url> --jsonauth <json auth file path> --year <year selected> --version --help" % (sys.argv[0]))
exit()
address = False
jsonauth = "/home/sqlpac/google-auth.json"
year = 2020
version = "1.0"
options, args = getopt.getopt(sys.argv[1:], 'a:j:y:h:v', ['address=',
'jsonauth=',
'year=',
'help',
'version'])
for opt, arg in options:
if opt in ('-a', '--address'):
address = arg
elif opt in ('-j', '--jsonauth'):
jsonauth = arg
elif opt in ('-y', '--year'):
year = arg
elif opt in ('-v', '--version'):
print(version)
exit()
elif opt in ('-h', '--help'):
usage()
if not address:
print('Address required')
usage()
Ce morceau de code n’a pas besoin de commentaires, il est facile à lire même pour les débutants en sachant que la liste sys.argv[1:]
stocke les arguments.
Quand on est habitués à la programmation shell ou C, on reconnaît les options courtes dans le second argument donné à la méthode getopt
(a:j:y:h:v
), les options longues sont appliquées dans le troisième argument (['address=','jsonauth=','help'…
) avec l’opérateur =
spécifié lorsqu’une valeur est attendue.
Conclusion
Sans aucun doute, le package argparse
est plus puissant avec moins de code que le package getopt
. Lequel ? Ça dépendra des
préférences, de la complexité du projet…