Espandi il percorso di ricerca Python in un'altra origine


106

Ho appena aderito a un progetto con una base di codice esistente piuttosto ampia. Sviluppiamo in linux e non usiamo e IDE. Corriamo attraverso la riga di comando. Sto cercando di capire come fare in modo che Python cerchi il percorso giusto quando eseguo i moduli del progetto. Ad esempio, quando eseguo qualcosa come:

python someprojectfile.py

ottengo

ImportError: no module named core.'somemodule'

Ottengo questo per tutte le mie importazioni presumo sia un problema con il percorso.

TLDR:

Come faccio a far cercare a Python ~/codez/project/e tutti i file e le cartelle per i file * .py durante le istruzioni di importazione.

Risposte:


171

Ci sono alcuni modi possibili per farlo:

  • Imposta la variabile d'ambiente PYTHONPATHsu un elenco di directory separato da due punti per cercare i moduli importati.
  • Nel tuo programma, usa sys.path.append('/path/to/search')per aggiungere i nomi delle directory in cui vuoi che Python cerchi i moduli importati. sys.pathè solo l'elenco delle directory che Python cerca ogni volta che gli viene chiesto di importare un modulo, e puoi modificarlo secondo necessità (anche se non consiglierei di rimuovere nessuna delle directory standard!). Qualsiasi directory che metti nella variabile d'ambiente PYTHONPATHverrà inserita sys.pathall'avvio di Python.
  • Utilizzare site.addsitedirper aggiungere una directory a sys.path. La differenza tra questo e il semplice aggiunta è che quando si utilizza addsitedir, cerca anche i .pthfile all'interno di quella directory e li utilizza per eventualmente aggiungere ulteriori directory in sys.pathbase al contenuto dei file. Vedere la documentazione per maggiori dettagli.

Quale di questi vuoi usare dipende dalla tua situazione. Ricorda che quando distribuisci il tuo progetto ad altri utenti, in genere lo installano in modo tale che i file di codice Python vengano rilevati automaticamente dall'importatore di Python (cioè i pacchetti sono solitamente installati nella site-packagesdirectory), quindi se giochi con il sys.pathtuo codice , ciò potrebbe non essere necessario e potrebbe persino avere effetti negativi quando il codice viene eseguito su un altro computer. Per lo sviluppo, azzardo l'ipotesi che l'impostazione PYTHONPATHsia solitamente il modo migliore per procedere.

Tuttavia, quando si utilizza qualcosa che viene eseguito solo sul proprio computer (o quando si hanno configurazioni non standard, ad esempio a volte in framework di app Web), non è del tutto raro fare qualcosa di simile

import sys
from os.path import dirname
sys.path.append(dirname(__file__))

Quindi, se avessi come dire 15 sottodirectory, dovrei aggiungere singolarmente ciascuna di esse?
themaestro

e potresti fornire un esempio di un argomento della riga di comando per modificare PYTHONPATH?
themaestro

3
Per impostare PYTHONPATH: in .bashrco qualsiasi altro file di avvio utilizzato dalla shell (se non è Bash), scrivi export PYTHONPATH=$PYTHONPATH:$HOME/codez/project. Ma se hai un sacco di sottodirectory, creerei un .pthfile e userei site.addsitedir. Puoi creare un modulo sitecustomizeche possa chiamare la funzione per te; prova a metterlo in ~/.local/lib/python2.6/sitecustomize.py(sostituisci la tua versione di Python) in modo che si spera venga importato automaticamente.
David Z

Ho inserito quanto segue nel mio file .bashrc e non ho ancora fortuna con quelle importazioni. Qualche idea? Come farei comunque un file .pth? export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / project export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez $ PYTHONPATH: $ PYTHONPATH esportazione HOME / adaifotis / codez / project / proxy export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / project / conf
themaestro

Prova ad aprire un terminale e corri echo $PYTHONPATH. Se la variabile d'ambiente è stata impostata correttamente, dovresti vedere un elenco di directory separato da due punti. Per informazioni sui .pthfile, vedere la documentazione del sitemodulo a cui ho collegato nella mia risposta. Ti dice quali dovrebbero essere i contenuti e come usarli.
David Z

13

Dovresti anche leggere i pacchetti python qui: http://docs.python.org/tutorial/modules.html .

Dal tuo esempio, immagino che tu abbia davvero un pacchetto in ~/codez/project. Il file __init__.pyin una directory python mappa una directory in uno spazio dei nomi. Se le tue sottodirectory hanno tutte un __init__.pyfile, devi solo aggiungere la directory di base al tuo PYTHONPATH. Per esempio:

PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / progetto

Oltre a testare la tua variabile d'ambiente PYTHONPATH, come spiega David, puoi testarla in Python in questo modo:

$ python
>>> import project                      # should work if PYTHONPATH set
>>> import sys
>>> for line in sys.path: print line    # print current python path

...


Potresti inserire i tuoi __init__.pybacktick per chiarire che intendi davvero __init__.py, al contrario di init.py. Solo per evitare di confondere i neofiti. :)
antred

4

So che questo thread è un po 'vecchio, ma mi ci è voluto del tempo per arrivare al nocciolo della questione, quindi ho voluto condividerlo.

Nel mio progetto, avevo lo script principale in una directory principale e, per differenziare i moduli, ho messo tutti i moduli di supporto in una sottocartella chiamata "moduli". Nel mio script principale, importa questi moduli in questo modo (per un modulo chiamato report.py):

from modules.report import report, reportError

Se chiamo il mio script principale, funziona. TUTTAVIA, volevo testare ogni modulo includendone uno main()in ciascuno e chiamando ciascuno direttamente, come:

python modules/report.py

Ora Python si lamenta di non riuscire a trovare "un modulo chiamato moduli". La chiave qui è che, per impostazione predefinita, Python include la cartella dello script nel suo percorso di ricerca, MA NON IL CWD. Quindi ciò che questo errore dice, in realtà, è "Non riesco a trovare una sottocartella dei moduli". Il motivo è che non esiste una sottodirectory "moduli" dalla directory in cui risiede il modulo report.py.

Trovo che la soluzione più pulita a questo sia aggiungere il CWD nel percorso di ricerca di Python includendo questo in alto:

import sys

sys.path.append(".")

Ora Python cerca in CWD (directory corrente), trova la sottocartella "moduli" e tutto va bene.


3

Ho letto questa domanda cercando una risposta e non mi è piaciuta nessuna di loro.

Quindi ho scritto una soluzione rapida e sporca. Mettilo da qualche parte nel tuo sys.path e aggiungerà qualsiasi directory sotto folder(dalla directory di lavoro corrente) o sotto abspath:

#using.py

import sys, os.path

def all_from(folder='', abspath=None):
    """add all dirs under `folder` to sys.path if any .py files are found.
    Use an abspath if you'd rather do it that way.

    Uses the current working directory as the location of using.py. 
    Keep in mind that os.walk goes *all the way* down the directory tree.
    With that, try not to use this on something too close to '/'

    """
    add = set(sys.path)
    if abspath is None:
        cwd = os.path.abspath(os.path.curdir)
        abspath = os.path.join(cwd, folder)
    for root, dirs, files in os.walk(abspath):
        for f in files:
            if f[-3:] in '.py':
                add.add(root)
                break
    for i in add: sys.path.append(i)

>>> import using, sys, pprint
>>> using.all_from('py') #if in ~, /home/user/py/
>>> pprint.pprint(sys.path)
[
#that was easy
]

E mi piace perché posso avere una cartella per alcuni strumenti casuali e non farli far parte di pacchetti o altro, e comunque avere accesso ad alcuni (o tutti) di essi in un paio di righe di codice.


3

Il modo più semplice che trovo è creare un file "any_name.pth" e inserirlo nella cartella "\ Lib \ site-packages". Dovresti trovare quella cartella ovunque sia installato python.

In quel file, metti un elenco di directory in cui vuoi mantenere i moduli per l'importazione. Ad esempio, crea una riga in quel file come questa:

C: \ Users \ esempio ... \ esempio

Sarai in grado di dire che funziona eseguendolo in python:

import sys
for line in sys: print line

Vedrai la tua directory stampata, tra le altre da dove puoi anche importare. Ora puoi importare un file "mymodule.py" che si trova in quella directory con la stessa facilità con cui:

import mymodule

Ciò non importerà le sottocartelle. Per questo potresti immaginare di creare uno script Python per creare un file .pth contenente tutte le sottocartelle di una cartella che definisci. Farlo funzionare all'avvio forse.


0

Nuova opzione per la vecchia domanda.
Installando il fail2banpacchetto su Debian, sembra che sia codificato per l'installazione su /usr/lib/python3/dist-packages/fail2banun percorso non su python3 sys.path.


> python3
Python 3.7.3 (v3.7.3:ef4ec6ed12, Jun 25 2019, 18:51:50)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python37.zip', '/usr/lib/python3.7', '/usr/lib/python3.7/lib-dynload', '/usr/lib/python3.7/site-packages']
>>>

quindi, invece di copiare, ho (bash) collegato la libreria alle versioni più recenti.
I futuri aggiornamenti dell'app originale verranno applicati automaticamente anche alle versioni collegate.

 if [ -d /usr/lib/python3/dist-packages/fail2ban ]
   then
      for d in /usr/lib/python3.*
      do
         [ -d ${d}/fail2ban ] || \
            ln -vs /usr/lib/python3/dist-packages/fail2ban ${d}/
      done
   fi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.