Próbuję śledzić PEP 328 , o następującej strukturze katalogów:
pkg/
__init__.py
components/
core.py
__init__.py
tests/
core_test.py
__init__.py
W core_test.py
Mam następującą instrukcję import
from ..components.core import GameLoopEvents
Jednak po uruchomieniu pojawia się następujący błąd:
tests$ python core_test.py
Traceback (most recent call last):
File "core_test.py", line 3, in <module>
from ..components.core import GameLoopEvents
ValueError: Attempted relative import in non-package
Podczas wyszukiwania znalazłem „ ścieżkę względną nie działa nawet z __init__.py ” i „ Importuj moduł ze ścieżki względnej ”, ale nie pomogły.
Czy czegoś tu brakuje?
python
package
python-import
importerror
init
skytreader
źródło
źródło
unittest
projektów, więc napisałem ten dość wyczerpujący przykładowy projekt, który obejmuje głębokie zagnieżdżanie modułów, import względny i absolutny (tam, gdzie działa i nie działa) oraz odnośniki względne i absolutne z wewnątrz pakiet, a także import klas, pojedynczo, podwójnie i na poziomie pakietu. Pomogło jasne rzeczy aż do mnie!no module named myimports.foo
kiedy je uruchomię.cd
doPyImports
i runpython -m unittest tests.test_abs
, na przykład.Odpowiedzi:
Tak. Nie używasz go jako pakietu.
źródło
__init__.py
s aż do końca, i__package__
sztuczka modyfikująca (opisana poniżej przez BrenBarn) musiała umożliwić te importowanie skryptów wykonywalnych (np. Przy użyciu shebang i./my_script.py
przydałoby się to w powłoce uniksowej). Cały ten problem był dla mnie dość trudny do znalezienia lub znalezienia zwięzłej i zrozumiałej dokumentacji.pkg
w punkcie, w którym wywołujesz tę linię z CLI. Następnie powinno działać zgodnie z oczekiwaniami. Jeśli jesteś w środkupkg
i dzwoniszpython -m tests.core_test
, to nie zadziała. Przynajmniej nie dla mnie.__init__.py
pliki, ale wciąż pojawia sięValueError: Attempted relative import in non-package
błąd. Zapłaciłbym naprawdę dobre pieniądze komuś, gdzieś, by w końcu wyjaśnić prostym językiem angielskim, jak to wszystko działa.Aby rozwinąć odpowiedź Ignacio Vazquez-Abramsa :
Mechanizm importu Python działa w stosunku do
__name__
bieżącego pliku. Gdy plik jest wykonywany bezpośrednio, nie ma on swojej zwykłej nazwy, ale"__main__"
zamiast tego ma swoją nazwę. Dlatego import względny nie działa.Możesz, jak zasugerował Igancio, wykonać go za pomocą
-m
opcji. Jeśli masz część pakietu, która ma być uruchamiana jako skrypt, możesz również użyć tego__package__
atrybutu, aby powiedzieć temu plikowi, jaką ma mieć nazwę w hierarchii pakietów.Szczegółowe informacje można znaleźć na stronie http://www.python.org/dev/peps/pep-0366/
źródło
python -m core_test
ztests
podkatalogu - musi to być od rodzica lub musisz dodać rodzica do ścieżki.__package__
tego, aby pliki wykonywalne skryptów mogły względnie importować inne moduły z tego samego pakietu. Nie ma sposobu na względny import z „całego systemu”. Nie jestem nawet pewien, dlaczego chcesz to zrobić.__package__
symbol jest ustawiony na „parent.child”, to możesz zaimportować „parent.other_child”. Być może nie powiedziałem tego zbyt dobrze.script.py
w pakieciepack.subpack
, a następnie ustawienie to__package__
abypack.subpack
pozwoli Ci zrobićfrom ..module import something
, aby coś z importupack.module
. Pamiętaj, że zgodnie z dokumentacją nadal musisz mieć pakiet najwyższego poziomu na ścieżce systemowej. W ten sposób działają już importowane moduły. Jedyne, co można__package__
zrobić, to zezwolić na użycie tego zachowania również do skryptów wykonywanych bezpośrednio.__package__
w skrypcie, który jest wykonywany bezpośrednio, ale niestety pojawia się następujący błąd: „Moduł macierzysty„ xxx ”nie został załadowany, nie może wykonać importu względnego”Możesz użyć
import components.core
bezpośrednio, jeśli dołączysz bieżący katalog dosys.path
:źródło
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
to też zadziałafrom os import sys
wygląda jak oszustwo :)sys.path
- element nadrzędny katalogu, w którym znajduje się bieżący plik.import sys, os.path as path
.import os; os.sys.path.append(os.path.dirname(os.path.abspath('.')))
. Wtedyimport components.core
działa dla mnie prosta , importując z katalogu nadrzędnego notebooka według potrzeb.To zależy od tego, jak chcesz uruchomić skrypt.
Jeśli chcesz uruchomić swój test UnitTest z wiersza poleceń w klasyczny sposób, to znaczy:
Następnie, ponieważ w tym przypadku „elementy” i „testy” są rodzeństwem foldery, można importować względnego modułu albo stosując wkładkę lub append sposobu sys.path modułu. Coś jak:
W przeciwnym razie możesz uruchomić skrypt za pomocą argumentu „-m” (zwróć uwagę, że w tym przypadku mówimy o pakiecie, a zatem nie możesz podać rozszerzenia „.py” ), to znaczy:
W takim przypadku możesz po prostu użyć importu względnego, tak jak robiłeś:
Możesz w końcu wymieszać oba podejścia, aby skrypt działał bez względu na to, jak się nazywa. Na przykład:
źródło
python -m pdb myscript.py
do uruchomienia sesji debugowania.import pdb; pdb.set_trace()
do kodu (wbudowany).insert
zamiastappend
? Oznacza to, żesys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
W core_test.py wykonaj następujące czynności:
źródło
Jeśli Twój przypadek użycia służy do uruchamiania testów i wydaje się, że tak jest, możesz wykonać następujące czynności. Zamiast uruchamiać skrypt testowy,
python core_test.py
użyj środowiska testowego, takiego jakpytest
. Następnie w wierszu poleceń możesz wprowadzićTo uruchomi testy w twoim katalogu. To omija kwestię
__name__
bycia__main__
wskazaną przez @BrenBarn. Następnie umieść pusty__init__.py
plik w katalogu testowym, dzięki czemu katalog testowy stanie się częścią pakietu. Wtedy będziesz w stanie to zrobićJeśli jednak uruchomisz skrypt testowy jako program główny, sytuacja znów się nie powiedzie. Więc po prostu użyj testera. Może działa to również z innymi testerami, takimi jak,
nosetests
ale nie sprawdziłem tego. Mam nadzieję że to pomoże.źródło
Moją szybką poprawką jest dodanie katalogu do ścieżki:
źródło
Problem dotyczy twojej metody testowania,
próbowałeś
python core_test.py
wtedy pojawi się ten błąd ValueError: Próba importu względnego w pakiecie innym niż pakiet
Powód: testujesz swoje opakowanie ze źródła innego niż pakiet.
więc przetestuj moduł ze źródła pakietu.
jeśli to jest struktura twojego projektu,
cd pkg
lub z zewnątrz pkg /
pojedynczy,
.
jeśli chcesz importować z folderu w tym samym katalogu. dla każdego kroku wstecz dodaj jeszcze jeden.w
how.py
incase, jeśli chcesz zaimportować jak z hello.py
źródło
from .. import how
, w jaki sposób importujesz określoną klasę / metodę z pliku „how”. kiedy robię ekwiwalentfrom ..how import foo
wtedy otrzymuję „próbę względnego importu poza pakiet najwyższego poziomu”Stary wątek Dowiedziałem się, że dodanie
__all__= ['submodule', ...]
do pliku __init__.py , a następnie użyciefrom <CURRENT_MODULE> import *
w celu działa dobrze.źródło
Możesz użyć
from pkg.components.core import GameLoopEvents
, na przykład, używam pycharm, poniżej jest obraz struktury mojego projektu, po prostu importuję z pakietu głównego, a następnie działa:źródło
Jak powiedział Paolo , mamy 2 metody wywoływania:
Jedną różnicą między nimi jest ciąg sys.path [0]. Ponieważ interpretacja przeszukuje sys.path podczas importowania , możemy zrobić z
tests/core_test.py
:I więcej po tym, możemy uruchomić core_test.py innymi metodami:
Uwaga, testowany tylko py36.
źródło
To podejście działało dla mnie i jest mniej zagracone niż niektóre rozwiązania:
Katalog nadrzędny znajduje się w mojej PYTHONPATH, aw
__init__.py
katalogu nadrzędnym i tym katalogu znajdują się pliki.Powyższe zawsze działało w Pythonie 2, ale Python 3 czasami uderzał w ImportError lub ModuleNotFoundError (ten ostatni jest nowy w Pythonie 3.6 i podklasie ImportError), więc następująca poprawka działa dla mnie zarówno w Pythonie 2, jak i 3:
źródło
Spróbuj tego
źródło
Jeśli ktoś szuka obejścia, natknąłem się na jedno. Oto trochę kontekstu. Chciałem przetestować jedną z metod, które mam w pliku. Kiedy uruchomię to od wewnątrz
zawsze skarżyło się na względny przywóz. Próbowałem zastosować powyższe rozwiązania, ale nie działałem, ponieważ było wiele zagnieżdżonych plików, każdy z wieloma importami.
Oto co zrobiłem. Właśnie stworzyłem program uruchamiający, zewnętrzny program, który importuje niezbędne metody i wywołuje je. Chociaż nie jest to świetne rozwiązanie, działa.
źródło
Oto jeden sposób, który wkurzy wszystkich, ale zadziała całkiem nieźle. W trakcie testów:
Następnie po prostu zaimportuj komponenty, jak zwykle.
źródło
Jest to bardzo mylące, a jeśli używasz IDE jak pycharm, jest to trochę bardziej mylące. Co działało dla mnie: 1. Wprowadź ustawienia projektu pycharm (jeśli uruchamiasz Pythona z VE lub z katalogu python) 2. Nie ma nic złego w tym, co zdefiniowałeś. czasami współpracuje z klasą importu folder1.file1
jeśli to nie działa, użyj import folder1.file1 3. Zmienna środowiskowa powinna być poprawnie wymieniona w systemie lub podać ją w argumencie wiersza poleceń.
źródło
Ponieważ Twój kod zawiera elementy
if __name__ == "__main__"
, których nie można zaimportować jako pakiet, lepiej użyjsys.path.append()
tego rozwiązania.źródło
if __name__ == "__main__"
w twoim pliku miało wpływ na cokolwiek związanego z importowaniem.