Python & PostgreSQL

E' molto tempo che non scrivo qualcosa su Python... quindi dovevo recuperare. Lo scopo questa paginetta e' descrivere l'accesso al database PostgreSQL con Python utilizzando le versioni piu' recenti di tutti i componenti.

Python e' un un linguaggio di programmazione ad alto livello che supporta diversi paradigmi di programmazione: object-oriented, imperativo e funzionale con una tipizzazione dinamica forte. Python e' Open Source e mantenuto da una grande comunita' di sviluppatori.
Come linguaggio e' semplice e facilmente leggibile perche' i blocchi logici vengono costruiti semplicemente allineando le righe allo stesso modo.
Python e' interpretato e facilmente portabile. Viene sfruttato sopratutto in progetti dove la produttivita' e la leggibilita' del codice sono importanti, ad esempio: sviluppi web, giochi, scripting di sistema, data science, AI, ...

PostgreSQL e' il piu' completo e robusto database realazionale Open Source. Sviluppato attivamente dalla comunita' introduce sempre nuove funzionalita'. L'SQL fornito da PostgreSQL e' molto completo ed aderente agli standard.

Poiche' utilizzo un macOS il primo paragrafo riporta qualche dettaglio sull'installazione dei pacchetti necessari con Homebrew: se lavorate con un diverso sistema operativo potete traquillamente saltarlo!

Homebrew

La gestione degli aggiornamenti su MAC e' semplice ed efficiente ma se si vogliono utilizzare pacchetti Open Source su macOS la Apple non fornisce un gestore analogo all'RPM (Red Hat Package Manager) o all'APT (Advanced Packaging Tool). Homebrew o, piu' semplicemente brew, e' il piu' recente, il piu' completo e sopratutto piu' il piu' semplice gestore di pacchetti per macOS.

Utilizzare Homebrew per installare pacchetti su macOS e' molto semplice:

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" $ brew install postgresql

Il primo comando installa Homebrew (semplicemente brew per gli amici), il secondo installa postgresql che e' uno dei migliaia dei pacchetti disponibili [NdE la formula postgresql ovviamente installa... PostgreSQL].

Abbiamo installato il PostgreSQL... abbiamo dimenticato il Python?
A seconda delle versioni di macOS puo' il Python essere gia' presente. Per controllare basta il comando python --version dal Terminal. Per installare la versione piu' recente e' comunque possibile scaricarlo dal sito ufficiale oppure utilizzare Homebrew.
Nel seguito utilizzeremo la versione 3 di Python [NdA l'ultima versione disponibile e' la 3.12, e' sconsigliabile utilizzare la 2.x perche' non piu' supportata].

Quanto visto in questo paragrafo vale solo per macOS. Con una sistema Linux bastera' utilizzare i comandi di gestione dei pacchetti per installare il database Postgres e l'interprete Python (che in realta' nella distribuzioni piu' recenti e' quasi sempre presente).
Una volta installato il linguaggio Python ed avendo a disposizione un database Postgres in locale o sulla rete, il sistema operativo ospite non ha piu' importanza. Continuate a leggere!

Psycopg

Per accedere a PostgreSQL da Python e' necessario utilizzare una libreria per la connessione. La piu' completa e diffusa libreria Python per accedere a Postgres e' Psycopg di cui installeremo la versione piu' recente. Psycopg implementa le specifiche di accesso ai database, che per Python sono state stabilite da tempo nel PEP 249 – Python Database API Specification v2.0, agganciandosi alla libreria libpq di Postgres.

L'ultima versione di Psycopg disponibile e' la 3.1 [NdA 2022-08] che rispetto alla precedente versione 2, ancora supportata e comunque molto diffusa, introduce nuove funzionalita': Asynchronous support, COPY support, Redesigned connection pool, Static typing, Server-side parameters binding, Prepared statements, Statements pipeline, Binary communication, Direct access to the libpq functionalities, ... alcune delle quali sfruttano le piu' recenti features della libpq di PostgreSQL.
Le differenze tra le versioni di Psycopg sono comunque limitate e sono sopratutto relative al binding dei parametri ed all'esecuzione degli statement multipli.
Poiche' Psycopg implementa in modo completo la PEP-0249 (Python Enhancement Proposals) sono anche relativamente limitate le differenze tra Postgres ed altri database.

L'installazione della libreria Psycopg e' particolarmente semplice:

pip install psycopg

Curiosamente la versione precedente si installava con psycopg2.

Gia' fatto... possiamo iniziare a programmare!

Connessione

Come primo esempio creiamo un programma p0.py che esegue una semplice SELECT sul database:

import psycopg

conn = psycopg.connect(dbname="pgbench",
                        host="localhost",
                        user="postgres",
                        password="xxx",
                        port="5432")

cursor = conn.cursor()
cursor.execute("SELECT version()")
print(cursor.fetchone())

conn.commit()

Eseguire una connessione e' banale: si utilizza la connect(). Non vi sono parametri obbligatori ma abbiamo riportato i piu' comuni.

Per effettuare una SELECT abbiamo bisogno di creare un cursore, eseguire lo statement e raccogliere i valori.

Un'ultima indicazione sull'ultima istruzione: le connessioni aprono sempre una transazione e non e' attivo l'autocommit. E' un requisito del PEP 249 diverso dal default di Postgres; e' quindi molto importante ricordare di chiudere le transazioni con il commit().

Per eseguirlo? Semplice!

me@MacBook ~ % python p0.py ('PostgreSQL 15.5 (Homebrew) on x86_64-apple-darwin23.0.0, compiled by Apple clang version 15.0.0 (clang-1500.0.40.1), 64-bit',)

Cursori

Abbiamo gia' visto un cursore ma vi sono altri dettagli importanti da descrivere.
Con fetchone() si raccoglie un record, con fetchmany(size=10) si raccolgono 10 record e con fetchall() si raccolgono tutti i record.

Nell'esempio seguente utilizziamo un loop:

import psycopg

conn = psycopg.connect(dbname="pgbench",
                        host="localhost",
                        user="postgres",
                        password="xxx",
                        port="5432")

cursor = conn.cursor()
cursor.execute("SELECT tid, tbalance FROM pgbench_tellers order by tid")
for record in cursor:
    print( "Teller ID: %s  Balance: %s" % (record[0], record[1]) )

cursor.close()
conn.commit()

Nell'esempio e' utilizzata una tabella di pgbench.

Parametri

Vi sono diversi modi per passare i parametri alle query. In generale psycopg utilizza il server binding ovvero invia le query ed i parametri alla libpq. Ecco due esempi di passaggio dei parametri:

i=7
cursor.execute("SELECT tid, tbalance FROM pgbench_tellers WHERE tid = %s", (i,))

i=7
sql=("SELECT tid, tbalance "
     "  FROM pgbench_tellers "
     " WHERE tid = %(id)s")
cursor.execute(sql, dict(id=i))

Il secondo esempio utilizza le String Literal Concatenation e segue la style guide SQL che preferisco...

Varie ed eventuali

Molti altri aspetti andrebbero descritti: gestione delle eccezioni, logging, transazioni, errori tipici, ... ma non era possibile vederli tutti in questa breve pagina introduttiva.

Vi sono molteplici piccole differenze tra psycopg3 e psycopg2 e vi sono grandi differenze tra Python2 e Python3.
Il mio consiglio e' di utilizzare solo le nuove versioni o almeno costrutti validi anche per le nuove versioni.

Ho trovato una vecchia traduzione del PEP-0249 in italiano [NdA l'originale inglese e' del secolo scorso ma non mi risulta sia cambiato].

Psycopg non e' l'unica libreria utilizzabile per collegarsi a PostgreSQL da Python... pg8000, asyncpg, PostgREST, SQLAlchemy sono tra le alternative piu' note. Ma tra tutte Psycopg e' quella piu' utilizzata.


Titolo: Python & PostgreSQL
Livello: Medio (2/5)
Data: 31 Ottobre 2023 🎃
Versione: 1.0.1 - 31 Ottobre 2023
Autore: mail [AT] meo.bogliolo.name