2013-04-03 5 views
5

La prima voce di sys.path è la directory dello script corrente, in base allo docs. Nella seguente configurazione, vorrei cambiare questa impostazione predefinita. Immaginate la seguente struttura di directory:Inizializzazione corretta di sys.path quando lo script principale si trova in un sottomodulo

src/ 
    core/ 
     stuff/ 
     tools/ 
      tool1.py 
      tool2.py 
    gui/ 
     morestuff/ 
     gui.py 

Gli script tool*.py e gui.py sono destinati ad essere eseguito come script, come la seguente:

python src/core/tools/tool2.py 
python src/gui/gui.py 

Ora tutti gli strumenti di importazione da src.core.stuff, e la GUI ha bisogno gui.morestuff. Ciò significa che sys.path[0] dovrebbe puntare a src/, ma punta a src/core/tools/ o src/gui/ per impostazione predefinita.

posso regolare sys.path[0] in tutti gli script (con un costrutto come il seguente, ad esempio, all'inizio del gui.py):

if __name__ == '__main__': 
    if sys.path[0]: sys.path[0] = os.path.dirname(os.path.abspath(sys.path[0])) 

Tuttavia, questa è una sorta di ridondante, e diventa noioso per un maturo codice base con migliaia di script. So anche l'interruttore -m:

python -m gui.gui 

ma questo richiede la directory corrente per essere src/.

Esiste un modo migliore per ottenere il risultato desiderato, ad es. modificando i file __init__.py?

EDIT: Questo è per Python 2.7:

~$ python -V 
Python 2.7.3 
+0

Per i principianti c'è 'python -m core.tools.tool1' – Kos

+0

Quale versione di Python stai usando? – filmor

+0

@filmor: modificato. – krlmlr

risposta

4

Hai tre opzioni di base qui. Ho passato tutti e tre in un ambiente di produzione e in progetti personali. In molti modi si costruiscono l'uno sull'altro. Tuttavia, il mio consiglio è di saltare all'ultima.

Il problema fondamentale è che è necessario che la directory ./src si trovi nel percorso di ricerca python. Questo è davvero ciò che riguarda la confezione Python.

PYTHONPATH

Il, definito dall'utente modo più diretto per regolare il vostro percorso pitone è attraverso la variabile di ambiente PYTHONPATH. È possibile impostare in fase di esecuzione, fare qualcosa di simile:

PYTHONPATH=/src python src/gui/gui.py 

Ovviamente si può anche impostare questa funzione nel vostro ambiente globale così si spera tutti i processi che ne hanno bisogno troverà la corretta PYTHONPATH. Ma ricorda, ne dimenticherai sempre uno. Di solito alle 3 del mattino quando l'attività cron viene finalmente eseguita.

Pacchetti sito

evitare Ha bisogno di una variabile d'ambiente, le opzioni sono praticamente per includere il software in una voce esistente nel percorso di origine, o trovare qualche altro modo per aggiungere un nuovo percorso di ricerca.Pertanto, ciò può significare eliminare il contenuto della directory src in /usr/lib/python2.7/site-packages o ovunque si trovi il sistema site-packages.

Poiché potresti non voler includere effettivamente il codice nei pacchetti del sito, puoi creare un link simbolico per i tuoi due sotto-pacchetti.

Questo è ovviamente meno che ideale per una serie di motivi. Se non si presta attenzione ai nomi, all'improvviso ogni programma python sulla macchina viene esposto a potenziali conflitti di nome. Stai esponendo il tuo software a tutti gli utenti della macchina. Potresti incorrere in problemi se python get viene aggiornato. Se aggiungi un nuovo sotto-pacchetto, ora devi creare un nuovo link simbolico.

Un approccio leggermente migliore consiste nell'includere un file .pth da qualche parte nei pacchetti del sito. Quando Python incontra questi file, aggiunge il contenuto (che dovrebbe essere il nome di una directory) al percorso di ricerca. Ciò evita il problema di dover ricordare di aggiungere un nuovo link simbolico per ogni nuovo sottoprogetto.

virtualenv e confezionamento

La soluzione migliore è quella di mordere solo i denti e fare confezionamento pitone reale. Questo, combinato con ottimi strumenti come virtualenv and pip ti consente di avere un ambiente python isolato (o semi-isolato).

Sotto virtualenv, si avrebbe un site-packages personalizzato per il proprio progetto in cui è possibile installare facilmente il software in esso, evitando tutti i problemi delle soluzioni precedenti. virtualenv semplifica inoltre la manutenzione degli script eseguibili in modo che l'ambiente Python in cui viene eseguito sia esattamente come previsto.

Uno svantaggio è che è necessario scrivere e mantenere un setup.py che istruirà pip (il programma di installazione python) per includere il software in virtualenv. Il contenuto sarebbe qualcosa di simile:

 
!/usr/bin/env python 
# -*- coding: utf-8 -*- 

from distutils.core import setup 


setup(
    name='myproject', 
    package_dir={'myproject': 'src'}, 
    scripts=['src/gui/gui.py', 'src/core/tools/tool1.py', 'src/core/tools/tool2.py'] 
) 

Quindi, per impostare questo ambiente, che sta per essere simile a questa:

virtualenv env 
env/bin/pip install -e setup.py 

per eseguire lo script, allora si sarebbe solo fare qualcosa di simile:

env/bin/tool1.py 
+0

Grazie per la tua risposta molto dettagliata. Sfortunatamente, la confezione non è un'opzione, il software è in fase di sviluppo in una copia di lavoro SVN. Tuttavia, mi chiedevo se potessi usare il secondo approccio con la mia copia di lavoro SVN in connessione con virtualenv: Inserisci un file '.pth' opportunamente formattato nella sottodirectory' lib/python2.X/site-packages' dell'ambiente virtuale . qualche idea? – krlmlr

+0

La terza opzione non fornirebbe quello che ti serve?L'installazione di un pacchetto con 'pip install -e' installa il pacchetto con i suoi script, collegandolo al tuo codice di sviluppo (invece di installarne una copia), quindi qualsiasi modifica al codice nel repository sarebbe automaticamente disponibile nel virtualenv. –

+0

L'inserimento di un file .pth appropriato in virtualenv è essenzialmente ciò che 'pipe install -e' fa per te (come da risposta di Josh) Scrive anche segnaposto nella directory bin che lo collega all'istanza appropriata di python. – rhettg

5

L'unico modo ufficialmente approvato per eseguire uno script che si trova in un pacchetto è quello di utilizzare il flag -m. Mentre è possibile eseguire direttamente uno script e provare a eseguire le manipolazioni sys.path in ogni script, è probabile che sia un grosso problema. Se si sposta uno script tra cartelle, potrebbe essere necessario modificare la logica per riscrivere sys.path in modo da riflettere la nuova posizione. Anche se ottieni sys.path a destra, le importazioni relative esplicite non funzioneranno correttamente.

Ora, effettuare il lavoro python -m mypackage.mymodule richiede che si sia nella cartella di livello superiore del progetto (src nel caso) o che la cartella di livello superiore si trovi sul percorso di ricerca Python. Richiedere di essere in una cartella specifica è imbarazzante e hai detto che non lo vuoi. Ottenere src nel percorso di ricerca è il nostro obiettivo allora.

Penso che l'approccio migliore sia utilizzare la variabile di ambiente PYTHONPATH per indirizzare l'interprete nella cartella src del progetto in modo che possa trovare i pacchetti da qualsiasi luogo.

Questa soluzione è semplice da configurare (la variabile di ambiente può essere impostata automaticamente nel tuo .profile, .bashrc o in un altro posto equivalente) e funzionerà per qualsiasi numero di script. Se sposti il ​​tuo progetto, aggiorna le impostazioni dell'ambiente e sarai pronto, senza dover lavorare di più per ogni script.

+0

Grazie per la risposta. Volevo fare questo per evitare di dover impostare 'PYTHONPATH' in primo luogo ... – krlmlr

1

ho voluto fare questo per evitare di dover impostare PYTHONPATH in primo luogo

Ci sono altri luoghi che si possono collegare in sys.path inizializzazione di Python, utilizzando il modulo site, che è (per impostazione predefinita) importato automaticamente quando Python viene inizializzato.

Sulla base del presente codice site.py ...

# Prefixes for site-packages; add additional prefixes like /usr/local here 
PREFIXES = [sys.prefix, sys.exec_prefix] 

... Sembra come se l'intenzione era che questo file è stato progettato per essere modificato dopo l'installazione, che è una possibilità, anche se anche fornisce altri modi in cui è possibile influenzare sys.path, ad es posizionando un file .pth da qualche parte all'interno della directory site-packages.

Supponendo che il risultato desiderato sia far funzionare il codice 'out of the box', questo funzionerebbe, ma solo per tutti gli utenti su un singolo sistema.

Se è necessario che funzioni su più sistemi, è necessario applicare le stesse modifiche a tutti i sistemi.

Per la distribuzione, questo non è un grosso problema. In effetti, molti pacchetti Python già fanno qualcosa del genere. per esempio. su Ubuntu ...

~$ dpkg -L python-imaging | grep pth 
/usr/share/pyshared/PIL.pth 
/usr/lib/python2.7/dist-packages/PIL.pth 

... ma se la vostra intenzione è quella di rendere più facile per gli sviluppatori più concorrenti, ognuno con un proprio sistema, si può essere meglio attaccare con l'attuale opzione di aggiungere un po 'boilerplate 'codice per ogni modulo Python che deve essere eseguito come script.

Potrebbe esserci un'altra opzione, ma dipende esattamente da cosa si sta cercando di ottenere.

Problemi correlati