externally-managed-environment su Linux: perché il venv non è opzionale
Perché pip su Debian risponde externally-managed-environment, cosa prevede PEP 668 e come uscirne con una .venv senza rompere il Python di sistema.
Su Debian lanci python3 -m pip install tabulate e, invece di installare, pip si ferma con error: externally-managed-environment. Non è un guasto e non lo risolvi con un altro comando di pip: la guida agli ambienti virtuali Python (venv) in 5 minuti lo accenna come PEP 668. Il Python di sistema è gestito da apt: pip non deve scriverci dentro. La soluzione è lavorare in una .venv, dove pip è libero di installare ciò che vuole.
La risposta breve: python3 -m venv .venv, poi source .venv/bin/activate, poi python -m pip install tabulate. Nella prova, su Debian 13, il comando fuori dall’ambiente è stato bloccato, anche con --user; dentro la .venv la stessa libreria si è installata alla versione 0.10.0, mentre il pacchetto Debian equivalente è alla 0.9.0. L’opzione che scavalca il blocco esiste e la spiego, ma non la consiglio.
ℹ️ Nota / Prerequisito operativo: questo articolo riguarda Linux, e l’ho provato solo su Debian 13. Su altre distribuzioni, su macOS e su Windows non l’ho verificato. Ti servono Python 3 e un terminale; i comandi sono per bash. I percorsi assoluti negli output (per esempio
/workspace/mt3b/.venv) sono quelli della mia macchina di prova: sul tuo computer saranno diversi.
Che cosa dice davvero l’errore
Il messaggio completo, copiato dal terminale della prova:
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
sure you have python3-full installed.
If you wish to install a non-Debian packaged Python application,
it may be easiest to use pipx install xyz, which will manage a
virtual environment for you. Make sure you have pipx installed.
See /usr/share/doc/python3.13/README.venv for more information.
note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.
Il messaggio indica tre strade, nell’ordine: apt install python3-xyz per i pacchetti che Debian distribuisce, un ambiente virtuale per tutto il resto, pipx per le applicazioni da riga di comando. Poi avvisa che esiste un’opzione per forzare, con il rischio di rompere Python o il sistema. Il percorso README.venv è un file del pacchetto python3.13, ma sulla macchina di prova non c’era: l’installazione era ridotta. Il testo che ti serve, quindi, è questo.
.venv pip si ferma con questo avviso (la riga più lunga è tagliata a destra, il testo completo è nel blocco sopra). Screenshot: ai riparoPerché esiste: PEP 668 in due paragrafi
Il problema, come lo descrive l’introduzione di PEP 668, sono i conflitti tra il gestore di pacchetti del sistema e strumenti come pip: sia tra librerie Python incompatibili, sia sulla proprietà dei file. Se pip sostituisse una libreria installata da apt, apt non ne saprebbe nulla. Per questo PEP 668, oggi mantenuto come specifica sul sito della Python Packaging Authority, permette a chi distribuisce Python di segnalare che l’installazione è «gestita dall’esterno».
Il segnale è un file di testo, EXTERNALLY-MANAGED, nella cartella della libreria standard. La specifica dice che l’installer deve fermarsi con un errore quando due condizioni sono vere insieme: non sei in un ambiente virtuale (sys.prefix == sys.base_prefix) e quel file esiste. Nella prova esisteva: /usr/lib/python3.13/EXTERNALLY-MANAGED. Dentro c’è una sezione [externally-managed] con un campo Error= il cui testo coincide con il corpo del messaggio che hai letto sopra. Il messaggio, quindi, non è inventato da pip: lo scrive Debian, e pip si limita a mostrarlo.
La .venv è fuori dal blocco perché ha i suoi percorsi. Nella prova, con l’ambiente attivo, Python indicava:
/workspace/mt3b/.venv | /usr
Il primo valore è sys.prefix (la .venv), il secondo sys.base_prefix (il Python di sistema da cui è nata). Quando i due sono diversi sei dentro un ambiente virtuale, e pip installa nella .venv senza toccare /usr.
Cosa succede se provi a forzare
Prima di scegliere la strada giusta, ecco cosa ho provato.
| Tentativo | Esito nella prova | Note |
|---|---|---|
python3 -m pip install tabulate |
Bloccato | È l’errore completo che hai letto sopra. |
python3 -m pip install --user tabulate |
Bloccato | Stesso error: externally-managed-environment: installare «solo per il tuo utente» non basta. |
python3 -m pip install --dry-run --break-system-packages tabulate |
Simulato | Con --dry-run pip non installa nulla: ha scritto Would install tabulate-0.10.0. Non ho eseguito la versione vera del comando. |
python -m pip install tabulate dentro una .venv |
Riuscito | Ha chiuso con Successfully installed tabulate-0.10.0. |
--break-system-packages fa quello che dice: ignora il blocco. Il messaggio stesso lo definisce un rischio per Python e per il sistema, e PEP 668 prevede che l’opzione porti un nome che ne richiami la pericolosità. Il dry-run mi ha mostrato dove sarebbe finita la libreria: nel Python di sistema, accanto ai pacchetti di apt. Per una libreria in più, il rischio non vale: una .venv costa tre comandi.
⚠️ Attenzione —
--break-system-packages: usalo solo se sai già cosa stai sostituendo e come tornare indietro. Per uno script o un piccolo progetto non serve: la.venvfa lo stesso lavoro senza toccare il sistema.
La soluzione: una .venv per il progetto
Dalla cartella del progetto, su Linux:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install tabulate
.venv tiene le librerie lontane dall’officina del sistema. Foto: Anastasia Shuraeva · PexelsIl terzo comando, che fuori dall’ambiente veniva bloccato, qui si è chiuso con Successfully installed tabulate-0.10.0, e tabulate.__file__ indicava un percorso dentro .venv/lib/python3.13/site-packages/. Il file pyvenv.cfg della .venv creata nella prova conteneva:
home = /usr/bin
include-system-site-packages = false
version = 3.13.5
executable = /usr/bin/python3.13
command = /usr/bin/python3 -m venv /workspace/mt3b/.venv
La riga include-system-site-packages = false significa che la .venv parte vuota: non vede i pacchetti installati nel sistema. Nella prova, requests era importabile con il Python di sistema; in una .venv appena creata import requests rispondeva ModuleNotFoundError: No module named 'requests'. È un comportamento voluto, e la .venv di un progetto si riempie con i suoi pacchetti, che poi puoi salvare in un file: lo spiega l’articolo su requirements.txt: congelare e ripristinare i pacchetti del venv.
Il messaggio di Debian chiede di avere python3-full installato. Sulla macchina di prova c’era python3-venv (versione 3.13.5-1) e python3 -m venv ha funzionato. Non ho provato una macchina senza quel pacchetto.
Una rete di sicurezza: --require-virtualenv
Il blocco di Debian scatta solo sulle installazioni gestite dal sistema. pip ha anche un’opzione che chiede un ambiente virtuale attivo, a prescindere dalla distribuzione. Nella prova, fuori dalla .venv:
python3 -m pip install --require-virtualenv tabulate
ERROR: Could not find an activated virtualenv (required).
Il comando è uscito con codice 3 e senza installare nulla. Lo stesso risultato si ottiene con la variabile d’ambiente PIP_REQUIRE_VIRTUALENV=true, che ho provato su un singolo comando. Con la .venv attiva, la stessa opzione non ha dato errori. Nella prova il controllo di --require-virtualenv è scattato prima di quello di externally-managed-environment: è un modo semplice per ricordarti di attivare l’ambiente anche dove il blocco di sistema non c’è. Per capire quale ambiente è attivo c’è il comando sys.prefix spiegato in più progetti, più .venv.
Errori tipici
error: externally-managed-environmentappena apri un nuovo terminale → l’attivazione vale solo per il terminale in cui l’hai fatta, e il nuovo terminale usa il Python di sistema → rilanciasource .venv/bin/activatenella cartella del progetto.--usernon risolve → nella provapython3 -m pip install --user tabulateè stato bloccato con lo stesso errore → non cercare scorciatoie: crea la.venv.ModuleNotFoundErrordentro la.venvper un pacchetto che «con Python funziona» → la.venvnon vede i pacchetti del sistema (include-system-site-packages = false) → installa il pacchetto dentro la.venvconpython -m pip install.ERROR: Could not find an activated virtualenv (required).→ hai attivato--require-virtualenv(o la variabile) senza attivare la.venv→ attiva l’ambiente e riprova.- Hai installato con
apte non trovi la versione che ti serve → Debian distribuisce versioni diverse da quelle di PyPI: pertabulate,apt-cache policy python3-tabulateindicava come candidata la 0.9.0, mentre PyPI aveva la 0.10.0 → se ti serve una versione precisa, installala nella.venv.
Domande Frequenti (FAQ)
L’errore compare anche su Windows e macOS?
Dipende dal Python installato: il blocco c’è quando l’installazione contiene il file EXTERNALLY-MANAGED, e lo decide chi distribuisce Python. Su Debian 13 c’era. Sugli altri sistemi non l’ho verificato, quindi non ti dico che lì non compaia.
Meglio apt install python3-xyz o la .venv?
Per le librerie del tuo progetto, la .venv: ti dà la versione che scegli tu e non tocca il sistema. apt ha senso per gli strumenti che usa il sistema stesso. Su tabulate, Debian proponeva la 0.9.0 come candidata mentre PyPI aveva la 0.10.0. Non ho installato il pacchetto Debian.
A cosa serve pipx, che compare nel messaggio?
Il messaggio lo propone per installare applicazioni Python da riga di comando in un ambiente isolato, non per le librerie di uno script. Non l’ho installato né provato. Per gli script di ai riparo basta una .venv per progetto.
--break-system-packages è davvero così pericoloso?
Il messaggio di Debian dice che puoi rompere Python o il sistema, e pip stesso lo mette in guardia. Nella prova l’ho usato solo con --dry-run, che non installa niente. Non ho provato gli effetti reali, e non ho motivo di farlo quando la .venv risolve lo stesso problema.
Devo creare una .venv anche per uno script che usa solo la libreria standard?
No: se lo script importa solo moduli già inclusi in Python, non installi nulla e il blocco non ti riguarda. Appena serve una libreria esterna, crea la .venv.
Come faccio a sapere se sto dentro un ambiente virtuale?
Confronta sys.prefix con sys.base_prefix: se sono diversi, sei dentro un ambiente virtuale. Nella prova indicavano /workspace/mt3b/.venv e /usr.
Il blocco come promemoria
Il blocco di Debian non ti vieta di installare: ti ricorda di farlo nel posto giusto. Il flusso è questo: cartella del progetto, .venv, attivazione, poi python -m pip install. Per la creazione e l’attivazione passo per passo torna agli ambienti virtuali Python (venv) in 5 minuti; per ricreare l’ambiente su un altro computer, requirements.txt: congelare e ripristinare i pacchetti del venv. Se hai uno script che devi far girare su un server Linux con il suo ambiente già preparato, è il tipo di lavoro che realizzo su richiesta.