web-dev-qa-db-fra.com

Désactiver/Supprimer l'argument dans argparse

Est-il possible de supprimer ou de désactiver un argument dans argparse, de sorte qu'il n'apparaisse pas dans l'aide? Comment?

Il est facile d'ajouter de nouveaux arguments:

parser = argparse.ArgumentParser()
parser.add_argument('--arg1', help='Argument 1')
parser.add_argument('--arg2', help='A second one')

Et je sais que vous pouvez remplacer les arguments par une nouvelle définition en spécifiant le gestionnaire de conflit "résoudre":

#In one script that should stand-alone and include arg1:

parser = argparse.ArgumentParser(conflict_handler='resolve')
parser.add_argument('--arg1', help='Argument 1')
parser.add_argument('--arg2', help='A second one')

#In another script with similar options
parser.add_argument('--arg1', help='New number 1')

Mais cela inclut toujours arg1 dans le message d’aide et les résultats de parse_args Y at-il quelque chose comme:

#Wishful thinking
#In another script with similar options, that shouldn't include arg1
parser.remove_argument('--arg1')

Ou un autre moyen raisonnablement facile d'y parvenir?

Aussi: l'approche serait-elle différente si l'argument était un argument de position?

Remarque: le problème avec la suppression de arg1 après l'analyse comme suggéré ici est que l'argument est toujours affiché dans l'aide.

14
Bryan P

Malgré le problème de bogue que je mentionne ci-dessous, votre utilisation de resolve suggère une méthode possible. Ce n'est pas pour le novice ou quelqu'un qui a besoin de s'en tenir à l'API publique.

La parser a une liste des objets Action (argument) (créés par add_argument).

En utilisant votre deuxième définition d’analyseur, sa liste _actions est:

In [22]: parser._actions
Out[22]: 
[_HelpAction(option_strings=['-h', '--help'], dest='help'...),
 _StoreAction(option_strings=['--arg2'], dest='arg2', nargs=None,
      const=None, default=None, type=None, choices=None, 
      help='A second one', metavar=None),
 _StoreAction(option_strings=['--arg1'], dest='arg1', nargs=None,
      const=None, default=None, type=None, choices=None, 
      help='New number 1', metavar=None)]

Lorsque vous ajoutez une conflit avec resolve, l'action existante en conflit est supprimée. Regardez la méthode _handle_conflict_resolve pour plus de détails. Mais je peux le tromper en supprimant une action sans en ajouter une nouvelle.

In [23]: parser._handle_conflict_resolve(None, [('--arg1',parser._actions[2])])

Examinez _actions et aidez-nous à vérifier que --arg1 est parti.

In [24]: parser._actions
Out[24]: 
[_HelpAction(option_strings=['-h', '--help'], dest='help',....),
 _StoreAction(option_strings=['--arg2'], dest='arg2', nargs=None,...)]

In [25]: parser.print_help()
usage: ipython3 [-h] [--arg2 ARG2]

optional arguments:
  -h, --help   show this help message and exit
  --arg2 ARG2  A second one

resolve gère simplement optionals, ceux où les chaînes de drapeau peuvent entrer en conflit. Et il supprime d'abord les indicateurs en conflit, en supprimant l'action en conflit uniquement s'il ne reste aucun indicateur. Faites donc très attention lorsque vous avez les options courtes et longues.

Et cela ne concerne pas le cas des positions. Ils n'ont pas d'indicateur et peuvent partager des paramètres dest. (bien qu'un seul apparaisse dans le résultat, à moins qu'il s'agisse d'actions ajoutées).

In [27]: foo1 = parser.add_argument('foo',help='foo 1 positional')
In [28]: foo2 = parser.add_argument('foo',help='foo 2 positional')
In [29]: parser.print_help()
usage: ipython3 [-h] [--arg2 ARG2] foo foo
positional arguments:
  foo          foo 1 positional
  foo          foo 2 positional
  ...

En jouant un peu plus, il semble que je puisse supprimer l'un de ces nouveaux positionnels:

In [33]: parser._actions[-1]
Out[33]: _StoreAction(option_strings=[], dest='foo',... help='foo 2 positional', metavar=None)
In [35]: foo2=parser._actions[-1]
In [36]: foo2.container._remove_action(foo2)
In [39]: parser.print_help()
usage: ipython3 [-h] [--arg2 ARG2] foo    
positional arguments:
  foo          foo 1 positional
 ....

Si j'avais choisi _actions[-2], j'aurais supprimé la première foo. Si j’assigne la valeur que add_argument renvoie à une variable, par ex. foo1, je peux l'utiliser au lieu de rechercher la valeur dans la liste parser._actions. Il peut être utile d'exécuter un exemple d'analyse dans un shell interactif (j'utilise IPython) et d'examiner ces objets.

Là encore, cela semble fonctionner sur un exemple simple, mais il nécessite des tests minutieux s'il est utilisé avec quelque chose de plus complexe (ou pour la production).


Le sujet a été abordé sur les problèmes/problèmes de Python il y a quelques années:

http://bugs.python.org/issue19462Add remove_argument() method to argparse.ArgumentParser

J'ai discuté des difficultés d'élimination complète et suggéré quelques alternatives. argparse.SUPPRESS peut être utilisé pour masquer des aides. optionals peut être ignoré s’ils ne sont pas obligatoires. positionals sont plus compliqués, bien que j’ai suggéré de modifier leurs attributs (nargs et default). Mais cela fait longtemps, je dois donc passer en revue ces publications.

=============================

J'étais curieux de connaître le problème @2rs2ts (voir le commentaire).

J'ai créé un analyseur, puis je l'ai utilisé comme parent d'un autre analyseur (inutile d'utiliser le mécanisme subparser). Ensuite, j'ai enlevé un argument d'un analyseur et j'ai examiné les modifications apportées à l'autre analyseur. 

Créez un analyseur parent avec un argument:

In [59]: p=argparse.ArgumentParser()
In [60]: p.add_argument('--foo')
Out[60]: _StoreAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)

Faites un autre avec parents:

In [61]: p1=argparse.ArgumentParser(parents=[p],add_help=False)
In [62]: p1._actions
Out[62]: 
[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None),
 _StoreAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)]

Notez que la 2ème action est la même pour les deux analyseurs (même id). parents vient de copier une référence à l'action --foo d'origine, elle n'a pas été copiée.

In [63]: id(p._actions[1])
Out[63]: 3000108652
In [64]: id(p1._actions[1])
Out[64]: 3000108652

Supprimez maintenant '--foo' d'un analyseur, en utilisant le truc que j'ai développé précédemment:

In [65]: p1._handle_conflict_resolve(None,[('--foo',p1._actions[1])])
In [66]: p1._actions
Out[66]: [_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None)]

'--foo' n'est plus dans la liste p1, mais est toujours présent dans la liste p. Mais option_strings est maintenant vide.

In [67]: p._actions
Out[67]: 
[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None),
 _StoreAction(option_strings=[], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)]

Le code resolve a supprimé le option_strings en conflit de l'action --foo, puis l'a supprimé de la liste p1._actions. Mais changer option_strings pour la référence p1 a également changé la référence p.

argparse utilise deux méthodes pour distinguer positionals de optionals, mais celle utilisée le plus souvent dans l'analyse consiste à déterminer si l'attribut option_strings est vide ou non. En vidant cet attribut, resolve a effectivement transformé une optional en une positional.

Oups, ma mémoire n'est pas ce qu'elle devrait être. :) Il y a un an, j'ai répondu à une question similaire concernant parents et resolve

https://stackoverflow.com/a/25821043/901925argparse conflict resolver for options in subcommands turns keyword argument into positional argument

3
hpaulj

Est-il possible de supprimer ou de désactiver un argument dans argparse, tel que N'apparaisse pas dans l'aide?

Définissez help sur argparse.SUPPRESS lorsque vous ajoutez l'argument, comme ceci:

parser.add_argument('--arg1', help=argparse.SUPPRESS)

Cela empêchera l'argument d'apparaître dans la sortie d'aide par défaut.

8
Burhan Khalid

Fonction pour supprimer les options argparse:

def remove_options(parser, options):
    for option in options:
        for action in parser._actions:
            if vars(action)['option_strings'][0] == option:
                parser._handle_conflict_resolve(None,[(option,action)])
                break
3
Santi Oliveras

Bien que la réponse de hpaulj soit excellente, dans mon cas, utiliser simplement parser._remove_action(action) ne supprimait pas les "arguments de position" pour aider l'action supprimée. Ma solution de contournement consistait à le supprimer également du _action_group

def remove_option(parser, arg):
    for action in parser._actions:
        if (vars(action)['option_strings']
            and vars(action)['option_strings'][0] == arg) \
                or vars(action)['dest'] == arg:
            parser._remove_action(action)

    for action in parser._action_groups:
        vars_action = vars(action)
        var_group_actions = vars_action['_group_actions']
        for x in var_group_actions:
            if x.dest == arg:
                var_group_actions.remove(x)
                return
0
Lorenzo