A Practical Guide to Using Setup.py

Data & AI Training Guide 2021

Scaricate la brochure di GoDataDriven per una panoramica completa delle sessioni di formazione disponibili e dei percorsi di apprendimento di data engineering, data science, data analyst e analytics translator.

Quando usi python in modo professionale è utile impostare i tuoi progetti
in modo coerente. Questo aiuta i tuoi collaboratori a capire rapidamente la
struttura di un progetto, e rende più facile per loro impostare il progetto
sulla loro macchina. La chiave per impostare il tuo progetto è il file setup.py.
In questo blog entrerò nei dettagli di questo file.

Da dove cominciamo

Qui assumo che tu abbia già un pacchetto che vuoi impostare.
Non è necessario che sia un pacchetto finito – idealmente dovresti creare il
setup.py molto prima che il tuo progetto sia finito. Potrebbe anche essere un pacchetto vuoto;
assicurati solo che la cartella del pacchetto esista
e contenga un file chiamato init.py (che potrebbe essere vuoto).

Se segui la struttura del mio collega Henk
per il tuo progetto, la tua situazione di partenza dovrebbe assomigliare a questa:

example_project/├── exampleproject/ Python package with source code.│ ├── __init__.py Make the folder a package.│ └── example.py Example module.└── README.md README with info of the project.

Puoi avere altri file o cartelle nella tua struttura, per esempio
cartelle chiamate notebooks/, tests/ o data/, ma queste non sono necessarie.

Il caso di un setup.py

Una volta che hai creato un pacchetto come questo, allora è probabile che tu
utilizzi parte del codice in altri posti. Per esempio, potreste voler
fare questo in un quaderno:

from exampleproject.example import example_function

Questo funzionerebbe se la vostra directory di lavoro corrente è example_project/, ma in
tutti gli altri casi python vi darà output come:

ModuleNotFoundError: No module named 'exampleproject'

Si potrebbe dire a python dove cercare il pacchetto impostando la variabile PYTHONPATH
ambiente o aggiungendo il percorso a sys.path,
ma questo è lontano dall’ideale: richiederebbe azioni diverse su diverse
piattaforme, e il percorso che dovete impostare dipende dalla posizione del vostro codice.
Un modo molto migliore è installare il tuo pacchetto usando un setup.py e pip,
perché pipè il modo standard per installare tutti gli altri pacchetti, ed è destinato
a funzionare allo stesso modo su tutte le piattaforme.

Un esempio minimo

Come è fatto un file setup.py? Ecco un esempio minimo0:

from setuptools import setup, find_packagessetup( name='example', version='0.1.0', packages=find_packages(include=))

Qui specifichiamo tre cose:

  • Il nome del pacchetto, che è il nome che pip userà per il tuo pacchetto.
    Non deve essere lo stesso del nome della cartella in cui il pacchetto vive
    , sebbene possa confondere se non lo è. Un esempio di dove il nome del pacchetto
    e la cartella non corrispondono è Scikit-Learn: lo si installa
    usando pip install scikit-learn, mentre lo si usa importando da sklearn.
  • La versione del tuo pacchetto. Questa è la versione che pip riporterà, ed è usata
    per esempio quando pubblichi il tuo pacchetto su PyPI1.
  • Quali pacchetti includere; nel nostro caso questo è solo exampleproject/.
    Qui lasciamo che setuptools lo capisca
    automaticamente2. Mentre si potrebbe in linea di principio usare find_packages()
    senza alcun argomento, questo può potenzialmente risultare in pacchetti indesiderati da
    includere. Questo può accadere, per esempio,
    se hai incluso un __init__.py nella tua tests/
    directory. In alternativa, puoi anche usare l’argomento excludeper prevenire esplicitamente
    l’inclusione di test nel pacchetto, ma questo è leggermente
    meno robusto.

Ora tutto ciò che devi fare per installare il tuo pacchetto è eseguire il seguente
da dentro la example_project/ directory3:

pip install -e .

Il . qui si riferisce alla directory di lavoro corrente, che presumo sia la directory
dove si trova il setup.py. Il flag -e specifica che vogliamo installare
in modalità modificabile, il che significa
che quando modifichiamo i file nel nostro pacchetto non abbiamo bisogno di reinstallare il
pacchetto prima che le modifiche abbiano effetto. Sarà necessario riavviare
python o ricaricare il pacchetto!

Quando si modificano informazioni nel setup.py stesso sarà necessario reinstallare
il pacchetto nella maggior parte dei casi, e anche se si aggiungono nuovi (sotto)pacchetti.
In caso di dubbio, non fa mai male reinstallare. Basta eseguire di nuovo pip install -e ..

Requisiti

La maggior parte dei progetti ha alcune dipendenze. Molto probabilmente hai usato
un file requirements.txt
prima, o un environment.yml
se stai usando conda. Ora che stai creando un setup.py, puoi specificare le tue
dipendenze nell’argomento install_requires.
Per esempio, per un tipico progetto di scienza dei dati potresti avere:

setup( name='example', version='0.1.0', packages=find_packages(include=), install_requires=)

Puoi specificare i requisiti senza una versione (PyYAML), fissare una versione (pandas==0.23.3), specificare una versione minima ('numpy>=1.14.5) o impostare un intervallo di versioni (matplotlib>=2.2.0,<3.0.0). Questi
requisiti saranno automaticamente installati da pip quando si installa il pacchetto.

Extras-require

A volte si possono avere dipendenze che sono richieste solo in certe situazioni. Come scienziato dei dati
faccio spesso pacchetti che uso per addestrare un modello. Quando lavoro su tale modello in modo interattivo
potrei aver bisogno di avere matplotlib e jupyter installati per lavorare in modo interattivo con i
dati e per creare visualizzazioni
delle prestazioni del modello. D’altra parte, se il modello gira in produzione non voglio installare matplotlibjupyter sulla macchina (o contenitore) dove mi alleno
o faccio inferenza. Fortunatamente setuptools permette di specificare dipendenze opzionali in extras_require:

setup( name='example', version='0.1.0', packages=find_packages(include=), install_requires=, extras_require={ 'interactive': , })

Ora se installiamo il pacchetto normalmente (pip install example da PyPI o pip install -e . localmente)
installerà solo le dipendenze PyYAML, pandas e numpy. Tuttavia, quando specifichiamo
che vogliamo le dipendenze interactive opzionali (pip install example
o pip install -e .),
allora anche matplotlib e jupyter saranno installate.

Scripts e entry points

Il caso d’uso principale della maggior parte dei pacchetti python che si installano da PyPI è di fornire funzionalità
che possono essere usate in altro codice python. In altre parole, è possibile importda quei pacchetti.
Come scienziato dei dati spesso creo pacchetti che non sono destinati ad essere usati da altro codice python ma
sono destinati a fare qualcosa, per esempio addestrare un modello. Come tale, ho spesso uno script python che
voglio eseguire dalla linea di comando.

Il modo migliore4 per esporre le funzionalità del tuo pacchetto alla linea di comando è quello di definire
un entry_point così:

setup( # ..., entry_points={ 'console_scripts': })

Ora puoi usare il comando my-command dalla linea di comando, che a sua volta eseguirà la main
funzione dentro exampleproject/example.py. Non dimenticare di reinstallare – altrimenti il comando
non sarà registrato.

Test

Ogni volta che scrivi del codice, ti incoraggio fortemente a scrivere anche dei test per questo codice. Per i test
con python ti suggerisco di usare pytest. Naturalmente non vuoi aggiungere pytest alle tue dipendenze
in install_requires: non è richiesto dagli utenti del tuo pacchetto. Per averlo installato
automaticamente quando esegui i test puoi aggiungere quanto segue al tuo setup.py:

setup( # ..., setup_requires=, tests_require=,)

Inoltre dovrai creare un file chiamato setup.cfg con il seguente contenuto:

test=pytest

Ora puoi semplicemente eseguire python setup.py test e setuptools si assicurerà che le dipendenze necessarie
siano installate ed eseguirà pytest per te! Dai un’occhiata qui se
vuoi fornire argomenti o impostare opzioni di configurazione per pytest.

Se hai dei requisiti aggiuntivi per i test (per esempio pytest-flask) puoi aggiungerli a tests_require.

Flake8

Personalmente penso sia una buona idea eseguire Flake8 per
controllare la formattazione del tuo codice. Proprio come con pytest, non vuoi aggiungere flake8 alle
install_requires dipendenze: non ha bisogno di essere installato per usare il tuo
pacchetto. Invece, puoi aggiungerlo a setup_requires:

setup( # ..., setup_requires=)

Ora puoi semplicemente eseguire python setup.py flake8. Naturalmente puoi anche appuntare la versione
di flake8 (o qualsiasi altro pacchetto) in setup_requires.

Se vuoi cambiare alcuni dei parametri di configurazione di Flake8 puoi aggiungere una sezione a
il tuo setup.cfg. Per esempio:

max-line-length=120

Dati del pacchetto

A volte potresti voler includere alcuni file non-python nel tuo pacchetto. Questi
possono essere per esempio file di schema o una piccola tabella di ricerca. Siate consapevoli che tali file
saranno impacchettati insieme al vostro codice, quindi è in generale una cattiva idea includere
qualsiasi file di grandi dimensioni.

Supponiamo di avere un schema.json nel nostro progetto, che mettiamo in exampleproject/data/schema.json.
Se vogliamo includerlo nel nostro pacchetto, dobbiamo usare l’argomento package_data di setup:

setup( # ..., package_data={'exampleproject': })

Questo farà sì che il file sia incluso nel pacchetto. Possiamo anche scegliere di includere
tutti i file sulla base di uno schema, per esempio:

setup( # ..., package_data={'': })

Questo aggiungerà tutti i file *.json in qualsiasi pacchetto che incontra.

Non cercate di capire da soli la posizione dei file installati, perché
pkg_resources ha alcune funzioni molto utili:

  • pkg_resources.resource_stream ti darà un flusso del file, molto simile all’oggetto
    che ottieni quando chiami open(),
  • pkg_resources.resource_string ti darà il contenuto del file come una stringa,
  • pkg_resources.resource_filename ti darà il nome del file (e lo estrarrà
    in un file temporaneo se è incluso in un pacchetto zippato) se le due opzioni
    di cui sopra non soddisfano le tue esigenze.

Per esempio, potremmo leggere il nostro schema usando:

from json import loadfrom pkg_resources import resource_streamschema = load(resource_stream('exampleproject', 'data/schema.json'))

Metadata

Se stai per pubblicare il tuo pacchetto, allora probabilmente vuoi dare ai tuoi
potenziali utenti qualche informazione in più sul tuo pacchetto, inclusa una descrizione,
il nome dell’autore o del manutentore, e l’url della pagina iniziale del pacchetto.
Puoi trovare una lista completa di tutti i metadati consentiti nei setuptools
docs.

Inoltre, se hai intenzione di pubblicare su PyPI, allora potresti voler
caricare automaticamente il contenuto del tuo README.md
nel long_description,
e fornire dei classificatori per dire pip ancora
di più sul tuo pacchetto.

Wrap-up

Questo blog dovrebbe essere un buon punto di partenza per impostare la maggior parte dei vostri progetti python.
Se volete leggere di più sul packaging di python date un’occhiata
alla documentazione. Ecco un esempio setup.py
che combina tutte le parti mostrate in questo blog:

from setuptools import setup, find_packagessetup( name='example', version='0.1.0', description='Setting up a python package', author='Rogier van der Geer', author_email='[email protected]', url='https://blog.godatadriven.com/setup-py', packages=find_packages(include=), install_requires=, extras_require={'plotting': }, setup_requires=, tests_require=, entry_points={ 'console_scripts': }, package_data={'exampleproject': })

e l’accompagnamento setup.cfg:

test=pytestmax-line-length=120

Migliora le tue competenze Python, impara dagli esperti!

A GoDataDriven offriamo una serie di corsi Python da principiante a esperto, tenuti dai migliori professionisti del settore. Unisciti a noi e migliora il tuo gioco con Python:

  • Python Essentials – Ottimo se hai appena iniziato con Python.
  • Certified Data Science with Python Foundation – Vuoi fare il passo dall’analisi e visualizzazione dei dati alla vera scienza dei dati? Questo è il corso giusto.
  • Advanced Data Science with Python – Impara a produrre i tuoi modelli come un professionista e ad usare Python per l’apprendimento automatico.
Note

0: In questo blog ho usato setuptools
per impostare il mio progetto di esempio. In alternativa
potresti anche usare distutils,
che è lo strumento standard per il packaging in python, ma manca di caratteristiche
come la funzione find_packages()e entry_points.
Siccome l’uso di setuptools è molto comune al giorno d’oggi e molte delle sue caratteristiche
possono essere particolarmente utili, vi suggerisco di usare setuptools.

1: Se volete che la versione del vostro pacchetto sia disponibile anche dentro python,
date un’occhiata qui.

2: Potresti anche elencare i tuoi pacchetti manualmente, ma questo è particolarmente soggetto a errori.

3: In alternativa potresti eseguire python setup.py install, ma usare pip ha
molti benefici, tra cui l’installazione automatica delle dipendenze e la
possibilità di disinstallare o aggiornare il tuo pacchetto.

4: Potresti anche usare l’argomento scripts (vedi per
esempio qui)
ma siccome questo richiede la creazione di uno script di shell python potrebbe non funzionare
altrettanto bene (o affatto) su Windows.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.