Tenho usado argparse
para um programa Python que pode -process
, -upload
ou ambos:
parser = argparse.ArgumentParser(description='Log archiver arguments.')
parser.add_argument('-process', action='store_true')
parser.add_argument('-upload', action='store_true')
args = parser.parse_args()
O programa não tem sentido sem pelo menos um parâmetro. Como posso configurar argparse
para forçar a escolha de pelo menos um parâmetro?
ATUALIZAR:
Seguindo os comentários: Qual é a maneira Pythônica de parametrizar um programa com pelo menos uma opção?
-x
é universalmente uma bandeira e opcional. Corte o-
se for necessário.process
o comportamento padrão (sem a necessidade de especificar nenhuma opção) e permitir que o usuário altere paraupload
se essa opção estiver definida? Normalmente, as opções devem ser opcionais, daí o nome. As opções obrigatórias devem ser evitadas (isso também está nosargparse
documentos).Respostas:
fonte
argparse
não houver opção embutida para isso.fonte
vars()
, que também é útil para passar opções nomeadas com cuidado para um construtor com **.vars
. Eu apenas fiz.__dict__
e me senti idiota antes.Se não for a parte 'ou ambas' (inicialmente não percebi isso), você poderia usar algo assim:
Porém, provavelmente seria uma ideia melhor usar subcomandos .
fonte
--process
OR--upload
, não XOR. Isso evita que as duas opções sejam definidas ao mesmo tempo.-x
e--xxx
são parâmetros normalmente opcionais.Eu sei que isso é muito antigo, mas a maneira de exigir uma opção, mas proibir mais de uma (XOR) é assim:
Resultado:
fonte
Revisão de Requisitos
argparse
(vou ignorar este)Existem também alguns requisitos implícitos ao viver na linha de comando:
Solução de amostra usando
docopt
(arquivomanagelog.py
):Tente executá-lo:
Mostre a ajuda:
E use-o:
Alternativa curta
short.py
Pode haver uma variante ainda mais curta:
O uso é parecido com este:
Observe que, em vez de valores booleanos para as chaves de "processo" e "upload", existem contadores.
Acontece que não podemos evitar a duplicação dessas palavras:
Conclusões
Projetar uma boa interface de linha de comando pode ser um desafio às vezes.
Existem vários aspectos do programa baseado em linha de comando:
argparse
oferece muito, mas restringe cenários possíveis e pode se tornar muito complexo.Com as
docopt
coisas ficam muito mais curtas, preservando a legibilidade e oferecendo alto grau de flexibilidade. Se você consegue obter argumentos analisados do dicionário e faz algumas conversões (para inteiro, abrindo arquivos ..) manualmente (ou por outra biblioteca chamadaschema
), você pode achar umdocopt
bom ajuste para análise de linha de comando.fonte
Se você precisar que um programa python seja executado com pelo menos um parâmetro, adicione um argumento que não tenha o prefixo de opção (- ou - por padrão) e defina
nargs=+
(mínimo de um argumento necessário). O problema com esse método que descobri é que, se você não especificar o argumento, argparse gerará um erro de "poucos argumentos" e não imprimirá o menu de ajuda. Se você não precisa dessa funcionalidade, veja como fazê-lo no código:Eu acho que quando você adiciona um argumento com os prefixos de opção, nargs governa todo o analisador de argumento e não apenas a opção. (O que quero dizer é que, se você tiver um
--option
sinalizador comnargs="+"
, o--option
sinalizador espera pelo menos um argumento. Se você tiveroption
comnargs="+"
, ele espera pelo menos um argumento geral.)fonte
choices=['process','upload']
a esse argumento.Para http://bugs.python.org/issue11588 , estou explorando maneiras de generalizar o
mutually_exclusive_group
conceito para lidar com casos como este.Com este desenvolvimento
argparse.py
, https://github.com/hpaulj/argparse_issues/blob/nested/argparse.py eu sou capaz de escrever:que produz o seguinte
help
:Isso aceita entradas como '-u', '-up', '--proc --up' etc.
Ele acaba executando um teste semelhante a https://stackoverflow.com/a/6723066/901925 , embora a mensagem de erro precise ser mais clara:
Eu me pergunto:
são os parâmetros
kind='any', required=True
claros o suficiente (aceitar qualquer um do grupo; pelo menos um é necessário)?é uso
(-p | -u)
claro? Um mutually_exclusive_group necessário produz a mesma coisa. Existe alguma notação alternativa?é usar um grupo como este mais intuitivo do que
phihag's
um teste simples?fonte
add_usage_group
a nesta página: docs.python.org/2/library/argparse.html ; você poderia fornecer um link para a documentação para isso?A melhor maneira de fazer isso é usando o módulo embutido python add_mutually_exclusive_group .
Se você quiser que apenas um argumento seja selecionado pela linha de comando, use apenas required = True como um argumento para o grupo
fonte
Talvez use sub-analisadores?
Agora
--help
mostra:Você também pode adicionar opções adicionais a esses subanalisadores. Além disso, em vez de usar isso,
dest='subparser_name'
você também pode vincular funções a serem chamadas diretamente em um determinado subcomando (consulte a documentação).fonte
Isso atinge o objetivo e também será afetado na
--help
saída gerada automaticamente do argparse , que é o que a maioria dos programadores sãos desejam (também funciona com argumentos opcionais):Documentos oficiais sobre isso: https://docs.python.org/3/library/argparse.html#choices
fonte
Use append_const para uma lista de ações e, em seguida, verifique se a lista está preenchida:
Você pode até especificar os métodos diretamente nas constantes.
fonte