J'ai passé quelques temps sur la documentation argparse, mais je continue de me battre avec ce module pour une option dans mon programme:
parser.add_argument("-r", "--rmsd", dest="rmsd", nargs=2,
help="extract the poses that are close from a ref according RMSD",
metavar=("ref","rmsd"))
Je voudrais que le premier argument soit une chaîne (type str
) et obligatoire, tandis que le deuxième argument devrait avoir le type int
, et si aucune valeur n'est donnée, en avoir un par défaut (disons dire default=50
). Je sais comment faire cela quand il n'y a qu'un seul argument attendu, mais je ne sais pas comment procéder lorsque nargs = 2 ... Est-ce même possible?
Vous pouvez effectuer les opérations suivantes. Le mot clé required
définit le champ obligatoire et le default=50
définit la valeur par défaut de l'option à 50 si non spécifié:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-s", "--string", type=str, required=True)
parser.add_argument("-i", "--integer", type=int, default=50)
args = parser.parse_args()
print args.string
print args.integer
Production:
$ python arg_parser.py -s test_string
test_string
50
$ python arg_parser.py -s test_string -i 100
test_string
100
$ python arg_parser.py -i 100
usage: arg_parser.py [-h] -s STRING [-i INTEGER]
arg_parser.py: error: argument -s/--string is required
J'ai tendance à être d'accord avec la solution de Mike, mais voici une autre façon. Ce n'est pas idéal, car la chaîne utilisation/aide indique à l'utilisateur d'utiliser un ou plusieurs arguments.
import argparse
def string_integer(int_default):
"""Action for argparse that allows a mandatory and optional
argument, a string and integer, with a default for the integer.
This factory function returns an Action subclass that is
configured with the integer default.
"""
class StringInteger(argparse.Action):
"""Action to assign a string and optional integer"""
def __call__(self, parser, namespace, values, option_string=None):
message = ''
if len(values) not in [1, 2]:
message = 'argument "{}" requires 1 or 2 arguments'.format(
self.dest)
if len(values) == 2:
try:
values[1] = int(values[1])
except ValueError:
message = ('second argument to "{}" requires '
'an integer'.format(self.dest))
else:
values.append(int_default)
if message:
raise argparse.ArgumentError(self, message)
setattr(namespace, self.dest, values)
return StringInteger
Et avec ça, vous obtenez:
>>> import argparse
>>> parser = argparse.ArgumentParser(description="")
parser.add_argument('-r', '--rmsd', dest='rmsd', nargs='+',
... action=string_integer(50),
... help="extract the poses that are close from a ref "
... "according RMSD")
>>> parser.parse_args('-r reference'.split())
Namespace(rmsd=['reference', 50])
>>> parser.parse_args('-r reference 30'.split())
Namespace(rmsd=['reference', 30])
>>> parser.parse_args('-r reference 30 3'.split())
usage: [-h] [-r RMSD [RMSD ...]]
: error: argument -r/--rmsd: argument "rmsd" requires 1 or 2 arguments
>>> parser.parse_args('-r reference 30.3'.split())
usage: [-h] [-r RMSD [RMSD ...]]
: error: argument -r/--rmsd: second argument to "rmsd" requires an integer
Désolé d'avoir sauté trop tard. J'utiliserais une fonction de type à appeler.
def two_args_str_int(x):
try:
return int(x)
except:
return x
parser.add_argument("-r", "--rmsd", dest="rmsd", nargs=2, type=two_args_str_int
help="extract the poses that are close from a ref according RMSD",
metavar=("ref","rmsd"))
Je recommanderais d'utiliser deux arguments:
import argparse
parser = argparse.ArgumentParser(description='Example with to arguments.')
parser.add_argument('-r', '--ref', dest='reference', required=True,
help='be helpful')
parser.add_argument('-m', '--rmsd', type=int, dest='reference_msd',
default=50, help='be helpful')
args = parser.parse_args()
print args.reference
print args.reference_msd
J'ai eu un problème similaire, mais l'approche "utiliser deux arguments" n'a pas fonctionné pour moi car j'ai besoin d'une liste de paires: parser.add_argument('--replace', nargs=2, action='append')
et si j'utilise des arguments séparés, je devrais valider la longueur des listes, etc. . Voici ce que j'ai fait:
Tuple
pour metavar
pour afficher correctement l'aide: Tuple=('OLD', 'NEW')
entraîne l'affichage de la chaîne d'aide sous la forme --replace OLD NEW
. Il est documenté mais je ne l'ai pas trouvé avant d'avoir essayé différentes options.parse_args
, Validez les éléments de la liste résultante et appelez parser.error()
si quelque chose ne va pas. C'est parce qu'ils ont différents types de données.