Rozwiń ścieżkę wyszukiwania Pythona do innego źródła


107

Właśnie dołączyłem do projektu z dość dużą istniejącą bazą kodu. Rozwijamy się w Linuksie i nie używamy i IDE. Przechodzimy przez wiersz poleceń. Próbuję dowiedzieć się, jak sprawić, by Python szukał właściwej ścieżki, gdy uruchamiam moduły projektu. Na przykład, gdy uruchamiam coś takiego:

python someprojectfile.py

dostaję

ImportError: no module named core.'somemodule'

Dostaję to dla wszystkich moich importów do, zakładam, że jest to problem ze ścieżką.

TLDR:

Jak sprawić, by Python przeszukał ~/codez/project/i wszystkie pliki i foldery dla plików * .py podczas importowania instrukcji.

Odpowiedzi:


172

Można to zrobić na kilka sposobów:

  • Ustaw zmienną środowiskową PYTHONPATHna listę katalogów oddzielonych dwukropkami, aby wyszukać zaimportowane moduły.
  • W swoim programie użyj, sys.path.append('/path/to/search')aby dodać nazwy katalogów, których Python ma wyszukiwać zaimportowane moduły. sys.pathto tylko lista katalogów przeszukiwanych przez Pythona za każdym razem, gdy zostanie poproszony o zaimportowanie modułu, i możesz go zmienić w razie potrzeby (chociaż nie polecałbym usuwania żadnego ze standardowych katalogów!). Wszystkie katalogi, które umieścisz w zmiennej środowiskowej, PYTHONPATHzostaną wstawione sys.pathpodczas uruchamiania Pythona.
  • Służy site.addsitedirdo dodawania katalogu do sys.path. Różnica między tym a zwykłym dołączaniem polega na tym, że kiedy używasz addsitedir, szuka on również .pthplików w tym katalogu i używa ich do ewentualnego dodania dodatkowych katalogów na sys.pathpodstawie zawartości plików. Więcej szczegółów można znaleźć w dokumentacji.

Który z nich chcesz użyć, zależy od Twojej sytuacji. Pamiętaj, że kiedy dystrybuujesz swój projekt do innych użytkowników, zazwyczaj instalują go w taki sposób, że pliki kodu Pythona zostaną automatycznie wykryte przez importera Pythona (tj. Pakiety są zwykle instalowane w site-packageskatalogu), więc jeśli będziesz bałaganić sys.pathw swoim kodzie , może to być niepotrzebne, a nawet może mieć niekorzystne skutki, gdy ten kod zostanie uruchomiony na innym komputerze. Jeśli chodzi o programowanie, zaryzykowałbym przypuszczenie, że ustawienie PYTHONPATHjest zwykle najlepszym sposobem.

Jednak gdy używasz czegoś, co działa tylko na twoim komputerze (lub gdy masz niestandardowe konfiguracje, np. Czasami w ramach aplikacji internetowych), nie jest niczym niezwykłym wykonanie czegoś takiego jak

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

Więc gdybym miał 15 podkatalogów, musiałbym dodawać każdy z nich indywidualnie?
themaestro

i czy możesz podać przykład argumentu wiersza poleceń do zmiany PYTHONPATH?
themaestro

3
Aby ustawić PYTHONPATH: w .bashrclub jakimkolwiek pliku startowym używanym przez powłokę (jeśli nie jest to Bash), napisz export PYTHONPATH=$PYTHONPATH:$HOME/codez/project. Ale jeśli masz kilka podkatalogów, zrobiłbym .pthplik i użył site.addsitedir. Możesz utworzyć moduł, sitecustomizektóry może wywołać tę funkcję za Ciebie; spróbuj umieścić go w ~/.local/lib/python2.6/sitecustomize.py(zastąp swoją wersję Pythona), aby mieć nadzieję, że zostanie automatycznie zaimportowany.
David Z

Umieściłem następujący w moim pliku .bashrc i nadal nie mam szczęścia z tym importem. Jakieś pomysły? Jak mimo wszystko utworzyłbym plik .pth? export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / project export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / PYTHONPATH = $ PYTHON / projekt HOME / adaifotis / codez / project / proxies export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / project / conf
themaestro

Spróbuj otworzyć terminal i uruchomić echo $PYTHONPATH. Jeśli zmienna środowiskowa została ustawiona poprawnie, powinieneś zobaczyć listę katalogów oddzielonych dwukropkami. Aby uzyskać informacje o .pthplikach, zapoznaj się z dokumentacją sitemodułu, do którego dołączyłem w mojej odpowiedzi. Informuje, jaka powinna być zawartość i jak z niej korzystać.
David Z

13

Przeczytaj również o pakietach Pythona tutaj: http://docs.python.org/tutorial/modules.html .

Z twojego przykładu domyślam się, że naprawdę masz paczkę pod adresem ~/codez/project. Plik __init__.pyw katalogu języka Python mapuje katalog na przestrzeń nazw. Jeśli wszystkie Twoje podkatalogi mają __init__.pyplik, wystarczy dodać katalog podstawowy do pliku PYTHONPATH. Na przykład:

PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / project

Oprócz testowania zmiennej środowiskowej PYTHONPATH, jak wyjaśnia David, możesz przetestować ją w Pythonie w następujący sposób:

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

...


Możesz wstawić __init__.pyznaki odwrotne, aby było jasne, że naprawdę masz na myśli __init__.py, w przeciwieństwie do init.py. Tylko po to, aby uniknąć mylących nowicjuszy. :)
antred

4

Wiem, że ten wątek jest trochę stary, ale zajęło mi trochę czasu, zanim dotarłem do jego sedna, więc chciałem się nim podzielić.

W moim projekcie główny skrypt miałem w katalogu nadrzędnym i aby rozróżnić moduły, umieściłem wszystkie moduły pomocnicze w podfolderze o nazwie „moduły”. W moim głównym skrypcie importuję te moduły w następujący sposób (dla modułu o nazwie report.py):

from modules.report import report, reportError

Jeśli zadzwonię do mojego głównego skryptu, to działa. JEDNAK chciałem przetestować każdy moduł, dodając jeden main()do każdego i wywołując każdy bezpośrednio, jako:

python modules/report.py

Teraz Python skarży się, że nie może znaleźć „modułu o nazwie moduły”. Kluczowe jest tutaj to, że Python domyślnie zawiera folder skryptu w swojej ścieżce wyszukiwania, ALE NIE CWD. Tak więc ten błąd mówi tak naprawdę: „Nie mogę znaleźć podfolderu modułów”. Dzieje się tak, ponieważ w katalogu, w którym znajduje się moduł report.py, nie ma podkatalogu „modules”.

Uważam, że najlepszym rozwiązaniem jest dołączenie CWD w ścieżce wyszukiwania Pythona, umieszczając to na górze:

import sys

sys.path.append(".")

Teraz Python przeszukuje CWD (katalog bieżący), znajduje podfolder „modules” i wszystko jest w porządku.


3

Przeczytałem to pytanie, szukając odpowiedzi, i nie podobało mi się żadne z nich.

Napisałem więc szybkie i brudne rozwiązanie. Po prostu umieść to gdzieś w sys.path, a doda dowolny katalog w folder(z bieżącego katalogu roboczego) lub w 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
]

I podoba mi się to, ponieważ mogę mieć folder dla niektórych losowych narzędzi i nie mogą być częścią pakietów ani czegokolwiek, a mimo to uzyskać dostęp do niektórych (lub wszystkich) z nich w kilku wierszach kodu.


3

Najłatwiejszym sposobem jest utworzenie pliku „any_name.pth” i umieszczenie go w folderze „\ Lib \ site-packages”. Powinieneś znaleźć ten folder wszędzie tam, gdzie jest zainstalowany Python.

W tym pliku umieść listę katalogów, w których chcesz przechowywać moduły do ​​importu. Na przykład utwórz wiersz w tym pliku w następujący sposób:

C: \ Users \ example ... \ example

Będziesz mógł stwierdzić, że działa, uruchamiając to w Pythonie:

import sys
for line in sys: print line

Zobaczysz swój katalog wydrukowany, między innymi skąd możesz również importować. Teraz możesz zaimportować plik „mymodule.py”, który znajduje się w tym katalogu tak łatwo, jak:

import mymodule

Nie spowoduje to zaimportowania podfolderów. W tym celu można sobie wyobrazić tworzenie skryptu w języku Python w celu utworzenia pliku .pth zawierającego wszystkie podfoldery zdefiniowanego folderu. Być może uruchom go podczas uruchamiania.


0

Nowa opcja dla starego pytania.
Instalowanie fail2banpakietu na Debianie wygląda na to, że jest zakodowane na stałe do zainstalowania na /usr/lib/python3/dist-packages/fail2banścieżce nie na 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']
>>>

więc zamiast tylko kopiować, połączyłem (bash) bibliotekę z nowszymi wersjami.
Przyszłe aktualizacje oryginalnej aplikacji będą również automatycznie stosowane w połączonych wersjach.

 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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.