Esecuzione di script Python dalla riga di comando e spiegazione delle opzioni

Python è ampiamente utilizzato per la sua flessibilità e facilità d’uso in molteplici applicazioni. Tra queste, la possibilità di eseguire script dalla riga di comando è particolarmente utile in numerosi contesti. Ad esempio, è possibile eseguire script di elaborazione dei dati con argomenti o utilizzarli come parte di attività di automazione. Inoltre, utilizzando gli argomenti della riga di comando, è possibile modificare il comportamento degli script e creare soluzioni più generiche e versatili. In questo articolo, esploreremo come gestire gli argomenti della riga di comando in Python, coprendo sia le tecniche di base che quelle avanzate.

Indice

Fondamenti degli argomenti della riga di comando


Quando si esegue uno script Python dalla riga di comando, è possibile passare degli argomenti per controllarne il comportamento. Il modo più semplice per farlo è utilizzare sys.argv.

Cosa è sys.argv


sys.argv è un elenco fornito dal modulo sys, che fa parte della libreria standard di Python, e contiene gli argomenti passati alla riga di comando. Il primo elemento della lista (sys.argv[0]) è il nome dello script, mentre gli elementi successivi rappresentano gli argomenti passati.

Esempio base di utilizzo


Il seguente script è un esempio semplice che visualizza gli argomenti passati:

import sys

if __name__ == "__main__":
    print("Nome dello script:", sys.argv[0])
    print("Argomenti:", sys.argv[1:])

Quando esegui lo script con python script.py arg1 arg2, otterrai il seguente output:

Nome dello script: script.py
Argomenti: ['arg1', 'arg2']

Le difficoltà nell’analisi degli argomenti


Anche se sys.argv è un modo semplice per acquisire gli argomenti, presenta alcune difficoltà:

  • È necessario validare manualmente il numero e il tipo degli argomenti.
  • La gestione delle opzioni (ad esempio --help) diventa complicata.
  • Il codice per la gestione di una lunga lista di argomenti diventa complesso.

Per risolvere questi problemi, Python offre moduli come argparse, che semplificano l’analisi degli argomenti. Nel prossimo paragrafo vedremo come usare argparse.

Panoramica sul modulo argparse


Il modulo argparse fa parte della libreria standard di Python ed è uno strumento potente per analizzare facilmente gli argomenti della riga di comando. Usando questo modulo, è possibile definire argomenti e opzioni in modo semplice e analizzarli al momento dell’esecuzione dello script.

Struttura di base di argparse


La sequenza base per usare argparse è la seguente:

  1. Creazione dell’oggetto ArgumentParser
    Creare un oggetto di base per analizzare gli argomenti.
  2. Definizione degli argomenti
    Specifica gli argomenti e le opzioni che lo script può ricevere.
  3. Analisi degli argomenti
    Analizza gli argomenti passati e usa i valori per controllare l’esecuzione del programma.

Esempio base di utilizzo


Il seguente script mostra un esempio di come analizzare gli argomenti utilizzando argparse:

import argparse

if __name__ == "__main__":
    # Creazione dell'oggetto ArgumentParser
    parser = argparse.ArgumentParser(description="Esempio base di analisi degli argomenti")

    # Aggiunta degli argomenti
    parser.add_argument("name", help="Specifica il nome utente")
    parser.add_argument("--age", type=int, help="Specifica l'età")

    # Analisi degli argomenti
    args = parser.parse_args()

    # Visualizzazione dei risultati
    print(f"Ciao, {args.name}!")
    if args.age:
        print(f"La tua età è {args.age}.")

Per eseguire questo script, usa il seguente comando:

python script.py Alice --age 30


L’output sarà il seguente:

Ciao, Alice!  
La tua età è 30.  

Vantaggi principali di argparse

  • Verifica automatica del tipo degli argomenti: è possibile verificare automaticamente il tipo di valori passati, come numeri o stringhe.
  • Messaggi di aiuto predefiniti: aggiunge automaticamente l’opzione --help e genera messaggi che spiegano come usare lo script.
  • Gestione di configurazioni complesse: supporta vari tipi di argomenti, come obbligatori, facoltativi, flag, e sottocomandi.

Nel prossimo paragrafo vedremo come configurare gli argomenti opzionali in modo più avanzato.

Configurazione degli argomenti opzionali


Utilizzando il modulo argparse, è possibile configurare gli argomenti della riga di comando in modo flessibile e gestire opzioni specifiche. Gli argomenti opzionali sono quelli che possono essere specificati facoltativamente per modificare il comportamento dello script, e solitamente iniziano con -- o -.

Configurazione base degli argomenti opzionali


Gli argomenti opzionali possono essere aggiunti utilizzando il metodo add_argument, specificando il nome con -- o -.

Ecco un esempio base di configurazione di argomenti opzionali:

import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Esempio base di argomenti opzionali")

    # Aggiunta di argomenti opzionali
    parser.add_argument("--verbose", action="store_true", help="Abilita la modalità verbose")
    parser.add_argument("--output", type=str, help="Specifica il nome del file di output")

    args = parser.parse_args()

    if args.verbose:
        print("Modalità verbose abilitata")
    if args.output:
        print(f"File di output: {args.output}")

Per eseguire questo script, usa il comando:

python script.py --verbose --output result.txt


L’output sarà:

Modalità verbose abilitata  
File di output: result.txt  

Principali opzioni di configurazione


Quando si personalizzano gli argomenti opzionali, i principali parametri da configurare sono i seguenti:

1. Specifica del tipo


Utilizzando il parametro type, è possibile specificare il tipo del valore che l’argomento accetta.

parser.add_argument("--count", type=int, help="Specifica il numero di iterazioni")

2. Valori di default


Il parametro default permette di impostare un valore predefinito per un argomento se non viene specificato durante l’esecuzione.

parser.add_argument("--level", type=int, default=1, help="Specifica il livello di elaborazione (predefinito: 1)")

3. Argomenti obbligatori


Impostando required=True, è possibile rendere un argomento opzionale obbligatorio.

parser.add_argument("--config", required=True, help="Specifica il file di configurazione")

Gestione dei flag


Alcuni argomenti opzionali non richiedono valori, ma modificano il comportamento dello script quando specificati. Per questi, si utilizza action="store_true":

parser.add_argument("--debug", action="store_true", help="Abilita la modalità di debug")


Quando esegui lo script con --debug, args.debug sarà impostato su True.

Riepilogo


Utilizzando argparse, è possibile creare facilmente argomenti opzionali flessibili e facili da usare. Nel prossimo paragrafo, esploreremo come gestire gli argomenti obbligatori e i valori di default.

Utilizzo degli argomenti obbligatori e dei valori di default


Con argparse, è possibile rendere alcuni argomenti obbligatori o configurare valori di default che vengono utilizzati se un argomento non viene specificato. Queste opzioni consentono di creare script più flessibili e robusti.

Configurazione degli argomenti obbligatori


Per impostazione predefinita, gli argomenti opzionali (quelli che iniziano con --) sono facoltativi. Tuttavia, se si desidera rendere un argomento obbligatorio, è necessario impostare required=True.

Esempio di utilizzo


Nel seguente esempio, l’opzione --config è obbligatoria:

import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Esempio di argomento obbligatorio")

    # Aggiunta di un argomento obbligatorio
    parser.add_argument("--config", required=True, help="Specifica il file di configurazione")

    args = parser.parse_args()
    print(f"File di configurazione: {args.config}")

Se esegui lo script senza specificare l’argomento, verrà generato un errore:

python script.py
usage: script.py --config CONFIG
script.py: error: the following arguments are required: --config


Se esegui lo script specificando --config, funzionerà correttamente:

python script.py --config settings.json
File di configurazione: settings.json

Impostazione dei valori di default


È possibile configurare un valore di default per un argomento, in modo che venga utilizzato se l’argomento non è stato specificato durante l’esecuzione.

Esempio di utilizzo


Nel seguente esempio, l’opzione --log-level ha un valore di default:

import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Esempio di valori di default")

    # Aggiunta di un'opzione con valore di default
    parser.add_argument("--log-level", default="INFO", help="Livello di dettaglio dei log (default: INFO)")

    args = parser.parse_args()
    print(f"Livello di log: {args.log_level}")

Se esegui lo script senza specificare alcun argomento, verrà utilizzato il valore di default:

python script.py
Livello di log: INFO


Se invece specifichi --log-level, il suo valore avrà la precedenza:

python script.py --log-level DEBUG
Livello di log: DEBUG

Combinazione di argomenti obbligatori e valori di default


È anche possibile combinare argomenti obbligatori e valori di default, anche se normalmente si evita di usare valori di default per argomenti di posizione e si preferisce richiederli esplicitamente all’utente.

Esempio di utilizzo

parser.add_argument("filename", help="Specifica il nome del file di destinazione")


In questo caso, filename è obbligatorio e deve essere sempre specificato durante l’esecuzione dello script.

Riepilogo


Impostando correttamente gli argomenti obbligatori e i valori di default, è possibile migliorare la flessibilità e l’usabilità dello script. Nel prossimo paragrafo, esploreremo come argparse può generare automaticamente i messaggi di aiuto per gli utenti.

Generazione automatica dei messaggi di aiuto


Il modulo argparse è in grado di generare automaticamente messaggi di aiuto per gli argomenti della riga di comando. Questo permette di fornire una guida intuitiva agli utenti su come utilizzare lo script.

Messaggi di aiuto di base


Quando si crea un ArgumentParser, l’opzione --help o -h viene aggiunta automaticamente e fornisce una descrizione degli argomenti disponibili.

Esempio: Messaggio di aiuto generato automaticamente


Il seguente script genera automaticamente un messaggio di aiuto quando viene eseguito con l’opzione --help:

import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Esempio di messaggio di aiuto")
    parser.add_argument("--input", help="Specifica il file di input")
    parser.add_argument("--output", help="Specifica il file di output")
    parser.add_argument("--verbose", action="store_true", help="Abilita la modalità verbose")

    args = parser.parse_args()

Quando esegui lo script con l’opzione --help, otterrai il seguente messaggio:

python script.py --help
usage: script.py [-h] [--input INPUT] [--output OUTPUT] [--verbose]

Esempio di messaggio di aiuto

options:
  -h, --help       Mostra questo messaggio di aiuto e termina
  --input INPUT    Specifica il file di input
  --output OUTPUT  Specifica il file di output
  --verbose        Abilita la modalità verbose

Il messaggio di aiuto include i nomi degli argomenti e una descrizione di ciascuno. È possibile utilizzare sia -h che --help per ottenere lo stesso risultato.

Personalizzazione del messaggio di aiuto


Con argparse, è possibile personalizzare la descrizione degli argomenti e dei messaggi di aiuto.

1. Impostazione della descrizione dello script


Usando il parametro description di ArgumentParser, è possibile fornire una descrizione generale dello script:

parser = argparse.ArgumentParser(description="Questo script elabora i file")

2. Descrizione per ciascun argomento


Con il parametro help di add_argument, è possibile aggiungere una descrizione per ogni argomento:

parser.add_argument("--input", help="Specifica il file di input da elaborare")

3. Aggiunta di esempi personalizzati


Usando il parametro epilog, è possibile aggiungere esempi di utilizzo o altre informazioni aggiuntive alla fine del messaggio di aiuto:

parser = argparse.ArgumentParser(
    description="Esempio di messaggio di aiuto",
    epilog="Esempio: python script.py --input file.txt --output result.txt"
)

Esempio: Messaggio di aiuto personalizzato

import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Questo script elabora i file",
        epilog="Esempio: python script.py --input in.txt --output out.txt"
    )
    parser.add_argument("--input", required=True, help="Specifica il file di input")
    parser.add_argument("--output", required=True, help="Specifica il file di output")
    parser.add_argument("--verbose", action="store_true", help="Abilita la modalità verbose")

    args = parser.parse_args()
usage: script.py [-h] --input INPUT --output OUTPUT [--verbose]

Questo script elabora i file

options:
  -h, --help       Mostra questo messaggio di aiuto e termina
  --input INPUT    Specifica il file di input
  --output OUTPUT  Specifica il file di output
  --verbose        Abilita la modalità verbose

Esempio: python script.py --input in.txt --output out.txt

Vantaggi del messaggio di aiuto

  1. Facilità d’uso: Gli utenti possono comprendere rapidamente come utilizzare lo script.
  2. Coerenza: Tutte le descrizioni degli argomenti vengono presentate in un formato uniforme.
  3. Manutenibilità: I messaggi di aiuto vengono aggiornati automaticamente quando vengono apportate modifiche al codice.

Nel prossimo paragrafo, esamineremo come introdurre i sottocomandi in uno script per supportare più azioni.

Introduzione ai sottocomandi


Gli script con più funzionalità possono dividere le azioni in comandi separati, utilizzando la funzionalità di sottocomandi di argparse. Questo approccio aiuta a organizzare lo script e rende l’uso più chiaro.

Struttura base di un sottocomando


Per utilizzare i sottocomandi, si usa il metodo add_subparsers. Questo metodo consente di definire i sottocomandi e di associare loro argomenti e opzioni specifiche.

Esempio: Struttura di un sottocomando


Il seguente esempio mostra uno script con due sottocomandi: add e delete:

import argparse

if __name__ == "__main__":
    # Creazione dell'ArgumentParser principale
    parser = argparse.ArgumentParser(description="Esempio di sottocomandi")

    # Creazione di subparsers per i sottocomandi
    subparsers = parser.add_subparsers(dest="command", help="Comandi disponibili")

    # Definizione del sottocomando 'add'
    parser_add = subparsers.add_parser("add", help="Aggiungi un elemento")
    parser_add.add_argument("item", help="Nome dell'elemento da aggiungere")

    # Definizione del sottocomando 'delete'
    parser_delete = subparsers.add_parser("delete", help="Elimina un elemento")
    parser_delete.add_argument("item", help="Nome dell'elemento da eliminare")

    # Analisi degli argomenti
    args = parser.parse_args()

    # Azioni in base al sottocomando scelto
    if args.command == "add":
        print(f"Elemento '{args.item}' aggiunto")
    elif args.command == "delete":
        print(f"Elemento '{args.item}' eliminato")
    else:
        parser.print_help()

Per eseguire questo script, usa i seguenti comandi:

python script.py add "Task 1"

Output:

Elemento 'Task 1' aggiunto
python script.py delete "Task 1"

Output:

Elemento 'Task 1' eliminato

Argomenti e opzioni nei sottocomandi


Ogni sottocomando può avere i propri argomenti e opzioni. Ad esempio, è possibile aggiungere un’opzione di descrizione per il sottocomando add o una flag di conferma per il sottocomando delete.

Esempio di sottocomando espanso

# Aggiunta di un'opzione di descrizione per il sottocomando 'add'
parser_add.add_argument("--description", help="Descrizione dell'elemento")

# Aggiunta di un flag di conferma per il sottocomando 'delete'
parser_delete.add_argument("--force", action="store_true", help="Elimina senza conferma")

Per eseguire questo script, puoi usare i seguenti comandi:

python script.py add "Task 2" --description "Questo è un nuovo task"
python script.py delete "Task 2" --force

Considerazioni sull’uso dei sottocomandi

  1. Progettazione coerente
    Quando si utilizzano più sottocomandi, è importante mantenere una progettazione coerente dei nomi dei comandi e degli argomenti.

Riepilogo

L’uso dei sottocomandi consente di implementare in modo compatto più funzionalità all’interno dello stesso script. Questo è particolarmente utile per strumenti complessi come gestori di task o client API. Nel prossimo paragrafo, esploreremo come il modulo click può rendere l’analisi degli argomenti ancora più flessibile.

Analisi delle opzioni con la libreria click

Il modulo argparse è potente, ma per creare strumenti a riga di comando più semplici e intuitivi, la libreria click è una scelta eccellente. click consente di definire l’analisi degli argomenti e la generazione automatica dei messaggi di aiuto in modo conciso.

Fondamenti di click

click utilizza i decoratori di funzione per definire argomenti e opzioni. Questo approccio rende il codice più leggibile e consente di separare le funzionalità in modo naturale.

Installazione di click

Inizia installando la libreria:

pip install click

Esempio base di utilizzo

Il seguente esempio mostra come usare click per analizzare gli argomenti della riga di comando:

import click

@click.command()
@click.option("--name", prompt="Your name", help="Specifica il nome utente")
@click.option("--age", default=25, help="Specifica l'età (default: 25)")
def greet(name, age):
    """Mostra un messaggio di saluto"""
    click.echo(f"Ciao, {name}! Hai {age} anni.")

if __name__ == "__main__":
    greet()

Per eseguire questo script, usa il comando:

python script.py --name Alice --age 30

Output:

Ciao, Alice! Hai 30 anni.

--name e --age se non specificati richiederanno l’inserimento da parte dell’utente tramite il prompt.

Strumenti con più comandi

Con click, è facile gestire più comandi in uno stesso script. Si può usare il decoratore @click.group() per raccogliere più comandi in un unico programma.

Esempio: Più comandi

import click

@click.group()
def cli():
    """Gestisce più comandi"""
    pass

@click.command()
@click.argument("item")
def add(item):
    """Aggiungi un elemento"""
    click.echo(f"Elemento '{item}' aggiunto")

@click.command()
@click.argument("item")
def delete(item):
    """Elimina un elemento"""
    click.echo(f"Elemento '{item}' eliminato")

cli.add_command(add)
cli.add_command(delete)

if __name__ == "__main__":
    cli()

Questo script consente di eseguire i comandi nel seguente modo:

python script.py add "Task 1"
python script.py delete "Task 1"

Output:

Elemento 'Task 1' aggiunto  
Elemento 'Task 1' eliminato  

Vantaggi di click

  1. Codice conciso: La definizione degli argomenti e delle opzioni è intuitiva grazie ai decoratori.
  2. Generazione automatica dell’aiuto: --help è generato automaticamente.
  3. Prompt per l’input: con il parametro prompt, l’utente può inserire un valore quando non specificato.
  4. Decorazioni e colori: Con click.echo() è possibile aggiungere facilmente decorazioni e colori ai messaggi di output.

Esempio di gestione degli errori

click semplifica anche la gestione degli errori. Ad esempio, è possibile personalizzare i messaggi di errore:

@click.command()
@click.argument("number", type=int)
def square(number):
    """Calcola il quadrato del numero specificato"""
    if number < 0:
        raise click.BadParameter("Specifica un numero positivo")
    click.echo(f"Il quadrato di {number} è {number**2}")

if __name__ == "__main__":
    square()

Riepilogo

click è una libreria flessibile che consente di creare sia strumenti semplici a riga di comando che applicazioni complesse con strutture a sottocomando. Nel prossimo paragrafo, esploreremo le migliori pratiche per lo sviluppo di strumenti a riga di comando.

Migliori pratiche per lo sviluppo di strumenti a riga di comando

Quando si sviluppano strumenti a riga di comando in Python, è fondamentale considerare la facilità d'uso e l'espandibilità del design. In questa sezione, esploreremo alcune delle migliori pratiche per creare strumenti di comando efficaci.

1. Interfaccia intuitiva e coerente

Progettare un'interfaccia semplice e coerente è cruciale per evitare confusione tra gli utenti.

Punti consigliati

  • Utilizzare nomi di comandi e opzioni chiari e comprensibili (ad esempio, --verbose).
  • Definire abbreviazioni per opzioni lunghe (ad esempio, --help e -h).
  • Organizzare i sottocomandi e le opzioni in modo gerarchico, in modo che siano logicamente raggruppati.

Esempio

tool.py add "task name" --priority high
tool.py delete "task name" --force

2. Utilizzo dell'aiuto generato automaticamente

Aggiungere descrizioni appropriate per ogni argomento e opzione migliora la qualità dei messaggi di aiuto, rendendo il comando facilmente comprensibile per gli utenti.

Approccio consigliato

  • Aggiungere descrizioni appropriate per ogni argomento usando help.
  • Fornire una descrizione generale dello script e esempi d'uso tramite description ed epilog.

Esempio: Impostazione di argparse

parser = argparse.ArgumentParser(
    description="Strumento di gestione dei task",
    epilog="Uso: python tool.py add 'task' --priority high"
)

3. Implementazione della gestione degli errori

Fornire messaggi di errore chiari e precisi quando l'utente fornisce argomenti non validi migliora la robustezza dello script.

Esempio di gestione degli errori

@click.command()
@click.argument("number", type=int)
def square(number):
    if number < 0:
        raise click.BadParameter("I numeri negativi non sono supportati")
    click.echo(f"Il quadrato di {number} è {number**2}")

4. Strutturazione del tool in moduli

Quando lo script diventa complesso, è utile dividerlo in moduli separati per semplificarne la gestione.

Esempio di struttura

project/
├── cli.py        # Interfaccia a riga di comando
├── commands/
│   ├── add.py    # Comando 'add'
│   ├── delete.py # Comando 'delete'
│   └── __init__.py
├── utils.py      # Funzioni di utilità
└── main.py       # Punto di ingresso

5. Implementazione dei test unitari

Aggiungere test ai comandi a riga di comando assicura una maggiore affidabilità dello strumento.

Esempio di test

Usa pytest per testare gli script a riga di comando:

from click.testing import CliRunner
from my_tool import cli

def test_add_command():
    runner = CliRunner()
    result = runner.invoke(cli, ["add", "Task 1"]])
    assert result.exit_code == 0
    assert "Task 1 aggiunto" in result.output

6. Compatibilità cross-platform

Progettare il tool per essere compatibile con Windows, macOS e Linux assicura che possa essere utilizzato su diverse piattaforme.

Considerazioni

  • Utilizzare os.path o pathlib per gestire i percorsi dei file.
  • Utilizzare subprocess per chiamare comandi esterni o programmi.

7. Semplificazione della distribuzione e installazione

Per rendere il tool facilmente utilizzabile su altri ambienti, è fondamentale pianificare la sua imballatura e installazione.

Metodi consigliati

  • Usare setuptools per impacchettare lo strumento in un pacchetto Python.
  • Definire i entry_points per rendere lo strumento installabile come un comando da terminale.

from setuptools import setup

setup(
    name="my_tool",
    version="1.0",
    py_modules=["tool"],
    install_requires=["click"],
    entry_points={
        "console_scripts": [
            "tool=tool:cli",
        ],
    },
)

Riepilogo

Quando sviluppi strumenti a riga di comando, è importante concentrarsi su facilità d'uso, espandibilità e manutenibilità. Progettando con attenzione, sarà possibile creare strumenti intuitivi sia per gli utenti che per gli sviluppatori.

Indice