Recuperando a linha de Comando em Scripts Python
Overview
Neste post, vamos mergulhar no mundo da automação e agilidade com Python, explorando como o módulo argparse torna simples o trabalho com linhas de comando. Através de exemplos claros e concisos, vamos descobrir juntos como tornar nossos scripts ainda mais poderosos e flexíveis, abrindo um leque de possibilidades para nossas tarefas diárias de programação. Prepare-se para adicionar uma ferramenta valiosa ao seu conjunto de habilidades de desenvolvimento Python!
Utilizar linhas de comando em scripts Python é razoavelmente simples. O script abaixo funciona no Python 2.8 ou superior. Existem mais opções e alternativas para ler a linha de comando, mas vamos nos ater ao básico…
import argparse as args
parser = args.ArgumentParser(description='Analyzing commandline...')
parser.add_argument("-b", "--blockfile"
, default="blocklist.txt"
, required=False
, help="File containing the sites that should be blocked. One site per line.")
parsed_args = parser.parse_args()
print(parsed_args.blockfile)
Explicando o fonte acima:
- Primeiro importamos a classe que processa as linhas de comando;
- Depois criamos um Parser para analisar a linha de comando. O atributo “description” será exibido quando esta linha for processada;
- O próximo passo é adicionar os argumentos que você deseja receber no seu script;
- Os dois primeiros atributos são nome e flag do atributo. Qualquer um destes valores poderá ser utilizado na linha de comando;
- default é o valor padrão para este argumento, caso ele seja omitido;
- required define se o argumento é obrigatório ou não. Se ele for obrigatório, o atributo default não é utilizado;
- help é o texto que será exibido quando o script for executado com -h (ou –help);
- Uma vez que todos os argumentos forem declarados, basta utilizar o a função parse_args() para recuperar os valores informados na linha de comando. Esta função vai retornar uma variável com com todas os argumentos que você definiu.
Este seria o resultado do código acima, caso o script seja executado sem argumentos:
python demo.py
blocklist.txt
Ao mudar o atributo required para true…
python demo.py
usage: PyGuestWatcher.py [-h] -b BLOCKFILE
PyGuestWatcher.py: error: the following arguments are required: -b/--blockfile
Executando o script passando a linha de comando com chamando o argumento pelo nome (-b) ou pela flag (–blockfile)…
python demo.py -b 'foo.bar'
'foo.bar'
python demo.py --blockfile 'foo.bar'
'foo.bar'
*Update: 13/09/2018*
Antes de começar com o update de conteúdo deste post, gostaria de acrescentar um breve contexto: O exemplo acima foi de um script que fiz para bloquear acessos a sites. Ele lê o arquivo blocklist.txt e adiciona os sites no arquivo host, apontando eles para localhost.
Ok. Vamos a atualização de conteúdo…
O exemplo anterior funciona bem, mas o argparse tem outras opções que podem ser uteis.
Vamos imaginar um novo script com uma nova linha de comando. A primeira coisa que você deve fazer é instanciar o parser:
# Instanciating commandline argument parser
parser = args.ArgumentParser("Analyzing commandline...")
Agora vamos adicionar alguns argumentos com configurações diferentes. No final, mostro um resumo destas possibilidades de configuração.
Argumento obrigatório do tipo numérico
parser.add_argument("-i", "--number",
required=True,
dest="arg_num",
type=int,
help="This is a required numeric argument.")
No código acima existem dois parâmetros que não foram utilizados no exemplo anterior:
- dest: Indica qual o nome da variável que vai armazenar o valor deste argumento. Se não for informado, o valor é armazenado em uma variável com o nome do argumento. Neste caso, se eu não tivesse informado o parâmetro dest, o valor seria acessado por uma propriedade chamada “number”;
- type: Indica o tipo do valor do argumento. Isso quer dizer a variável arg_num vai possuir um valor numérico e não uma string (que é o padrão);
Argumento obrigatório do tipo string
parser.add_argument("-s", "--string",
required=True,
dest="arg_str",
type=str,
help="This is a required string argument.")
Similar ao argumento anterior, mas com o tipo (type) definido para string (str), que é o padrão.
Argumento opcional do tipo numérico
parser.add_argument("-oi", "--optional-number",
required=False,
dest="arg_opt_num",
type=int,
help="This is an optional numeric argument.")
Argumento opcional do tipo string
parser.add_argument("-oi2", "--optional-number2",
required=False,
dest="arg_opt_num2",
help="This is an optional numeric argument without a type defined.")
Neste argumento eu falo que estou esperando um número, mas como o type não foi definido para int, então o valor dele será sempre uma string.
Outro argumento opcional do tipo string
parser.add_argument("-os", "--optional-string",
required=False,
dest="arg_opt_str",
type=str,
help="This is an optional string argument.")
Este argumento é opcional (required=False) e foi definido explicitamente como string (type=str)
Mais um argumento opcional do tipo string
parser.add_argument("-os2", "--optional-string2",
required=False,
dest="arg_opt_str2",
action="store",
type=str,
help="This is an optional string argument with explicit store action defined.")
Este argumento é similar ao anterior, mas possui um parâmetro a mais, o action. Ele define o que será feito com o argumento informado. O valor padrão é “store”, que simplesmente armazena o valor do argumento em uma variável.
Argumento do tipo flag (define valor para True)
parser.add_argument("-t", "--true",
required=False,
dest="arg_true",
action="store_true",
default=False,
help="This is a flag argument. If informed, will be set to true, otherwise, will be false.")
O argumento acima possui uma action diferente, a store_true. Isso indica que se você utilizar esta flag, o valor armazenado na variável dest será True. O valor padrão para este argumento é (por razões obvias) False.
Por flag eu quero dizer que é um argumento que você utiliza apenas ele. Ao contrário de um argumento do tipo numérico (-i 42), você vai utilizar apenas o argumento em si (-t ou –true)
Argumento do tipo flag (define valor para False)
parser.add_argument("-f", "--false",
required=False,
dest="arg_false",
action="store_false",
default=True,
help="This is a flag argument. If informed, will be set to false, otherwise, will be true.")
Este argumento é similar ao anterior, mas seus valores são invertidos: Por padrão, este argumento é considerado como True e se for informado, muda para False. Isso foi definido na action com valor store_false.
Argumento do tipo flag sem valor default definido
parser.add_argument("-n", "--no-default",
required=False,
dest="arg_flag",
action="store_false",
help="This is a flag argument. If informed, will be set to false. No default configured for this.")
O argumento acima não possui um valor padrão, mas seu action está definido como store_false, ou seja, se for omitido, a variável arg_flag vai ficara com valor True.
Isso demonstra que o argparse é esperto o suficiente para entender que, se você quer armazenar False na variável, caso o argumento seja utilizado, então esta mesma variável deve possuir o valor oposto (True) como padrão.
Argumento do tipo lista
parser.add_argument("-l", "--list",
required=False,
dest="arg_list",
default=[],
action="append",
help="This is an optional list argument with default value defined.")
O argumento acima é do tipo lista, ou seja, você pode utiliza-lo varias vezes na linha de comando, pois todos os valores informados serão adicionados a variável. Este comportamento é definido pelo valor append, informado no parametro action.
Argumento do tipo lista (numérico)
parser.add_argument("-li", "--list-int",
required=False,
dest="arg_list_int",
type=int,
action="append",
help="This is an optional list of numbers argument with no default value defined.")
Este argumento é similar ao anterior. A primeira diferença é que definido um tipo para os valores passados (type=int) e isso implica em dizer que a variável vai possuir uma lista de integers.
A outra diferença é que não definimos um valor padrão (default=[]) para este argumento, ou seja, se este argumento não for utilizado, a variável arg_list_int terá o valor None ao invés de uma lista vazia ([]).
Argumento do tipo lista de constantes
parser.add_argument("-lc1", "--list-const1",
required=False,
dest="arg_list_const",
action="append_const",
const="Flag 1",
help="This is a flag that adds a constant value to a list.")
parser.add_argument("-lc2", "--list-const2",
required=False,
dest="arg_list_const",
action="append_const",
const="Flag 2",
help="This is a flag that adds another constant value to a list.")
Acima estão dois argumentos, mas eles fazem parte do mesmo processo. Ambos estão com a action definida para append_const e isso quer dizer que eles vão adicionar um valor pre-definido a variável, resultando em uma lista de valores padrões.
A diferença entre append e append_const é que o append vai adicionar o valor que o usuário informar para a lista, enquanto o append_const vai adicionar o valor que você definiu.
Para que esta action funcione corretamente, o parametro dest deve ser igual para todos os argumentos relevantes.
Argumento do tipo versão
parser.add_argument("-v", "--version",
action="version",
version="{} | ver {}".format(__file__, __version__),
help="Argument that prints the current version of your application.")
Assim como o argumento que mostra o texto de ajuda (-h ou –help), um argumento com action definido para version vai sobrescrever os outros argumentos e exibir apenas a sua informação, ou seja, você não pode misturar o argumento do tipo versão com os outros na mesma linha de comando.
O que este tipo de argumento faz é padronizar uma forma de exibir a versão da sua aplicação. Quando utilizado, ele vai mostrar o texto definido no parametro version.
Resumindo os parametros da função add_argument
- Primeiro parametro (posicional) recebe o “apelido” do argumento. (Exemplo: -v);
- Segundo parametro (posicional) recebe o nome completo do argumento. Se o parâmetro dest não for informado, este será o nome da variável que armazena o valor do argumento;
- required: Indica se o argumento é ou não obrigatório (True/False);
- dest: Indica o nome da variável que vai receber o valor do argumento;
- action: Indica qual ação será tomada no argumento. Os valores possíveis são:
- store: (padrão) armazena o valor do argumento na variável;
- store_true: Armazena True se o argumento for utilizado. Caso contrário, o valor será False;
- store_false: Armazena False se o argumento for utilizado. Caso contrário, o valor será True;
- append: Adiciona o valor do argumento a uma lista;
- append_const: Adiciona um valor pre-definido a um lista. Devem ser adicionados varios argumentos, um para cada valor que poderá ser adicionado a lista;
- version: Exibe a verão do aplicativo (definido no parametro chamado version);
- const: Utilizado apenas quando o action está definido como append_const. Neste caso, o valor definido neste parametro será adicionado a lista;
- default: Valor padrão do argumento, caso ele não seja informado pelo usuário;
- version: Utilizado apenas quando o action está definido para “version”. Neste caso, o valor informado neste parametro será exibido para o usuário;
Para facilitar, fiz um exemplo no Github onde você pode passar estes valores e ver o resultado no console. Ele vai apenas exibir o nome da variável passada via linha de comando, seu valor e o tipo do valor.
Espero ter ajudado!
Referência: