Corso Python / Creare un pacchetto e verificare la wheel installata

Un progetto Python può dichiarare metadati e configurazione di build in pyproject.toml e produrre file installabili, come una wheel. Per verificarli davvero, installa la wheel in un ambiente pulito ed esegui import e comandi fuori dalla cartella sorgente: così non confondi il codice locale con quello contenuto nel pacchetto.

Distinguere nome della distribuzione e nome di importazione

La distribuzione locale di questo esempio si chiama expensekit-demo, mentre il pacchetto da importare è expensekit. Il nome con trattino usato dagli strumenti di installazione non deve essere identico a un identificatore Python. La cartella src separa il codice importabile dalla radice del progetto, riducendo il rischio che un import riuscito nasconda file mancanti nella distribuzione.

Usa Python 3.12 o successivo, come dichiarato nel progetto, e un ambiente virtuale dedicato. Questa prova costruisce e installa soltanto in locale. Il nome scelto non dimostra disponibilità o proprietà di un nome su PyPI; non serve un account del registro per completare l’esercizio.

La guida ufficiale al packaging Python descrive metadati e costruzione delle distribuzioni. La spiegazione del layout src rispetto al layout flat chiarisce perché verificare la copia installata è diverso dall’importare il sorgente.

Creare tutti i file del progetto

Crea una nuova cartella project con src/expensekit al suo interno. Salva il contenuto completo seguente in src/expensekit/__init__.py:

def total(amounts):
    if any(type(x) is not int or x < 0 for x in amounts):
        raise ValueError("invalid amount")
    return sum(amounts)

La funzione accetta una lista di interi non negativi, restituisce zero per una lista vuota ed esclude booleani e stringhe. Non estendere automaticamente il contratto agli iteratori: il controllo preliminare può consumarli prima della somma. Salva poi questo contenuto completo in src/expensekit/cli.py:

import argparse
from . import total

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("amounts", type=int, nargs="+")
    args = parser.parse_args()
    print(total(args.amounts))

if __name__ == "__main__":
    main()

Infine crea pyproject.toml nella radice project, non dentro src:

[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"

[project]
name = "expensekit-demo"
version = "0.1.0"
description = "Local expense sum example"
requires-python = ">=3.12"

[project.scripts]
expense-total = "expensekit.cli:main"

[tool.setuptools.packages.find]
where = ["src"]

[build-system] sceglie il backend e i suoi requisiti; [project] descrive la distribuzione e la versione minima di Python. [project.scripts] associa il comando expense-total alla funzione main del modulo CLI. La ricerca dei pacchetti parte da src.

Il blocco __main__ del modulo CLI evita di interpretare argomenti durante un semplice import. Il progetto non ha dipendenze di runtime esterne; build e setuptools sono strumenti per costruirlo. Quando una dipendenza è necessaria durante l’esecuzione, dichiarala nella sezione appropriata di project.dependencies, senza aggiungere automaticamente tutti gli strumenti di sviluppo.

Costruire e installare in un ambiente pulito

Dal terminale nella cartella che contiene pyproject.toml, usando l’ambiente di sviluppo, installa il frontend di build e costruisci il progetto:

python -m pip install build
python -m build

Il comando produce in dist una wheel expensekit_demo-0.1.0-py3-none-any.whl e un archivio sorgente expensekit_demo-0.1.0.tar.gz. La build può creare un ambiente isolato e scaricare i requisiti del backend: la riuscita dipende anche dalla disponibilità di quelle dipendenze. Poi crea un ambiente distinto per verificare l’installazione:

python -m venv .venv-check

In PowerShell su Windows installa la wheel con il Python del nuovo ambiente:

.\.venv-check\Scripts\python.exe -m pip install dist/expensekit_demo-0.1.0-py3-none-any.whl

Su macOS o Ubuntu usa il relativo percorso:

.venv-check/bin/python -m pip install dist/expensekit_demo-0.1.0-py3-none-any.whl

Il percorso relativo della wheel vale dalla radice del progetto. Dopo l’installazione attiva .venv-check oppure conserva il percorso assoluto del suo interprete. Spostati in una cartella nuova fuori dal progetto sorgente ed esegui questi controlli usando quel Python:

python -c "from expensekit import total; print(total([3500,8000,2500]))"
python -m expensekit.cli 3500 8000 2500

Entrambi devono stampare 14000. Il comando alias expense-total 3500 8000 2500 deve richiamare lo stesso ingresso quando l’ambiente è attivo. In alternativa usa il percorso completo del launcher dell’ambiente, come .venv-check/Scripts/expense-total.exe su Windows o .venv-check/bin/expense-total su macOS/Linux.

Non usare casualmente il Python dell’ambiente di sviluppo dopo esserti spostato: potrebbe contenere un’installazione precedente e nascondere un problema della nuova wheel. Per una verifica aggiuntiva controlla expensekit.__file__: deve riferirsi al pacchetto installato nel nuovo ambiente, non alla cartella project/src. La lezione su pacchetti e punti di ingresso spiega import e avvio come modulo.

Controllare contenuti, errori e limiti della distribuzione locale

La struttura dopo la build deve includere questi file:

project/
  pyproject.toml
  src/
    expensekit/
      __init__.py
      cli.py
  dist/
    expensekit_demo-0.1.0-py3-none-any.whl
    expensekit_demo-0.1.0.tar.gz

Se un import riesce soltanto nella cartella sorgente, controlla l’interprete selezionato, il pacchetto realmente installato e i file inclusi nella wheel. Il nome del file di distribuzione può usare underscore normalizzati anche quando il nome del progetto contiene un trattino: non rinominare arbitrariamente moduli o metadati per renderli visivamente uguali.

Prova anche zero, un valore negativo, testo non numerico e assenza degli argomenti. Zero è valido. Il testo non numerico e gli argomenti mancanti vengono rifiutati da argparse con codice 2; il negativo viene convertito in intero dal CLI ma rifiutato da total con ValueError e un errore del programma. Questa piccola interfaccia non trasforma ancora tutti gli errori di dominio in messaggi argparse: mantenere chiaro il comportamento è parte della verifica.

La prova locale è completa quando entrambi gli archivi esistono, contengono i moduli previsti e la wheel installata funziona con import, modulo CLI e alias nell’ambiente pulito. Non dimostra compatibilità con ogni sistema operativo o versione futura: verifica gli ambienti che vuoi dichiarare supportati.

Una pubblicazione su un registro richiede ulteriormente controllo del nome, licenza e autore, README, verifica dei file inclusi e dei segreti, autenticazione del registro e una politica di rilascio. I metadati minimi di questo progetto sono adatti alla prova locale; completare l’installazione non pubblica automaticamente il pacchetto su PyPI.