2009-08-27 41 views
9

OK, myślę, że cokolwiek robię źle, to prawdopodobnie oślepiająco oczywiste, ale nie mogę tego rozgryźć. Przeczytałem i ponownie przeczytałem sekcję samouczka na temat pakietów i jedyne, co mogę sobie wyobrazić, to to, że to nie zadziała, ponieważ wykonuję ją bezpośrednio. Oto konfiguracja katalogu:Pakiety w języku Python?

eulerproject/ 
    __init__.py 
    euler1.py 
    euler2.py 
    ... 
    eulern.py 
    tests/ 
    __init__.py 
    testeulern.py 

Oto treść testeuler12.py (pierwszy moduł testowy pisałem):

import unittest 
from .. import euler12 

class Euler12UnitTests(unittest.TestCase): 


    def testtriangle(self): 
     """ 
     Ensure that the triangle number generator returns the first 10 
     triangle numbers. 

     """ 
     self.seq = [1,3,6,10,15,21,28,36,45,55] 
     self.generator = euler12.trianglegenerator() 
     self.results = [] 
     while len(self.results) != 10: 
      self.results.append(self.generator.next()) 
     self.assertEqual(self.seq, self.results) 

    def testdivisors(self): 
     """ 
     Ensure that the divisors function can properly factor the number 28. 

     """ 
     self.number = 28 
     self.answer = [1,2,4,7,14,28] 
     self.assertEqual(self.answer, euler12.divisors(self.number)) 


if __name__ == '__main__': 

    unittest.main() 

Teraz, kiedy mogę wykonać to z IDLE iz polecenia linia natomiast w katalogu, pojawia się następujący błąd:

Traceback (most recent call last): 
    File "C:\Documents and Settings\jbennet\My Documents\Python\eulerproject\tests\testeuler12.py", line 2, in <module> 
    from .. import euler12 
ValueError: Attempted relative import in non-package 

Myślę, że problemem jest to, że ponieważ używam go bezpośrednio, nie mogę zrobić import względne (bo __name__ zmiany, a mój niejasne zrozumienie opisu pakietów jest takie, że __name__ jest częścią tego, jak określa, w jakim pakiecie się znajduje), ale w takim razie co sugerują ci ludzie, jak zaimportować kod "produkcyjny" przechowywany 1 poziom wyżej od kodu testowego?

+0

Wystarczy wybrać kliknij i kliknij przycisk przykładowego kodu. Lub zawiń go w '' –

Odpowiedz

8

Generalnie miałbyś katalog, którego nazwa jest nazwą twojego pakietu, gdzieś w twojej PYTHONPATH. Na przykład:

eulerproject/ 
    euler/ 
     __init__.py 
     euler1.py 
     ... 
     tests/ 
      ... 
    setup.py 

Następnie można albo zainstalować ten systemowy, lub upewnij się, aby ustawić PYTHONPATH=/path/to/eulerproject/:$PYTHONPATH podczas wywoływania skryptu.

Absolutna import jak to będzie wtedy działać:

from euler import euler1 

Edycja:

Zgodnie z docs Pythona, „modułów przeznaczonych do użycia jako główny moduł aplikacji Pythona zawsze powinny wykorzystać bezwzględny przywóz. " (Cite)

Tak więc uprząż testowa, taka jak nose, wymieniona przez inną odpowiedź, działa, ponieważ importuje pakiety, zamiast uruchamiać je z wiersza poleceń.

Jeśli chcesz robić rzeczy ręcznie, Twój uruchamialny skrypt musi być spoza hierarchii pakietu, tak:

eulerproject/ 
    runtests.py 
    euler/ 
     __init__.py 
     euler1.py 
     ... 
     tests/ 
      __init__.py 
      testeulern.py 

Teraz runtests.py może zrobić from euler.tests.testeulern import TestCase i testeulern.py może zrobić from .. import euler1

+2

Tak, ale wtedy twój projekt nie wykorzystuje już względnego importu. Zaletą importu względnego jest to, że pakiet jest samowystarczalny.Nie jest zależny od głównej nazwy folderu i nie może błędnie zaimportować jednostki z, na przykład, przestarzałej wersji pakietu, zakopanej gdzieś w PYTHONPATH. –

+0

OK, więc jak ustawić PYTHONPATH przed wywołaniem skryptu? Tak jakby chciałem móc uruchomić to z dwóch różnych lokalizacji na tym samym komputerze? ps: Uczę się także obsługi klonowania/łączenia z merkurialnym, dlatego jest w dwóch miejscach. – Jonathanb

+0

Dodano notatkę o sposobie importowania względnego, jeśli moduł jest importowany ze skryptu znajdującego się poza hierarchią pakietów. W przeciwnym razie użyj uprzęży testowej. Ustawienia zmiennych środowiskowych zależą od tego, nad czym pracujesz. Jeśli używasz bash, po prostu wykonaj PYTHONPATH = foo python scriptname.py –

10

Miałem ten sam problem. Teraz używam nose do uruchamiania moich testów, a import względny jest poprawnie obsługiwany.

Ta cała relacja względna jest dezorientująca.

+2

Przyjmuję drugą odpowiedź tylko dlatego, że pozwala mi to, co próbowałem zrobić z importem względnym. Jednakże, pobieram też nos, aby wykorzystać go jako moją uprząż do testowania, ponieważ wygląda o wiele mocniej niż wszystko, co mógłbym zrobić samodzielnie. – Jonathanb

+0

właśnie to, czego szukałem, dziękuję – Copperfield