2009-08-27 4 views
9

Хорошо, я думаю, что я делаю неправильно, это, вероятно, ослепительно очевидно, но я не могу понять это. Я прочитал и перечитал раздел руководства по пакетам, и единственное, что я могу понять, это то, что это не сработает, потому что я выполняю его напрямую. Вот настройки каталога:Пакеты Python?

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

Вот содержание testeuler12.py (первый тестовый модуль я написал):

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() 

Теперь, когда я исполню это от IDLE и от команды линии в то время как в каталоге, я получаю следующее сообщение об ошибке:

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 

Я думаю, что проблема в том, что, так как я бегу это прямо, я не могу сделать относительно импорта (потому что __name__ изменения, и мой смутное понимание описания пакетов состоит в том, что __name__ является частью того, как он сообщает, в каком пакете он находится), но в этом случае, что вы, ребята, предлагаете для того, чтобы импортировать код 'production', сохраненный на 1 уровне от тестового кода?

+0

Просто выберите и нажмите кнопку с образцом кода. Или оберните его в '' –

ответ

8

Как правило, у вас будет каталог, имя которого является вашим именем пакета, где-то на вашем PYTHONPATH. Например:

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

Затем вы можете либо установить эту общесистемный или убедитесь, что параметр PYTHONPATH=/path/to/eulerproject/:$PYTHONPATH при вызове вашего скрипта.

Абсолютный импорт, как это будет работать:

from euler import euler1 

Редактировать:

Согласно документации Python, «модули, предназначенные для использования в качестве основного модуля приложения Python всегда следует использовать абсолютный импорт ". (Cite)

Так испытательный жгут как nose, упомянутый другим ответом, работает, потому что он импортирует пакеты, а не запускает их из командной строки.

Если вы хотите, чтобы делать вещи вручную, ваш запускаемым скрипт должен находиться вне иерархии пакетов, например:

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

Теперь runtests.py может сделать from euler.tests.testeulern import TestCase и testeulern.py может сделать from .. import euler1

+2

Да, но тогда ваш проект больше не будет использовать относительный импорт. Хорошая вещь относительно относительного импорта заключается в том, что он делает ваш пакет самодостаточным.Он не зависит от его имени основной папки и не может неправильно импортировать устройство, например, из устаревшей версии пакета, где-то в PYTHONPATH. –

+0

Итак, как бы установить PYTHONPATH перед вызовом скрипта? Как если бы я захотел запустить это из двух разных мест на одном компьютере? ps: Я также изучаю, как обращаться с клонированием/слиянием с mercurial, поэтому он находится в двух местах. – Jonathanb

+0

Добавлена ​​заметка о том, как относительный импорт может работать, если модуль импортируется из сценария, расположенного вне иерархии пакетов. В противном случае используйте проверочный жгут. Настройка переменных окружения зависит от того, с чем вы работаете. Если вы используете bash, просто сделайте PYTHONPATH = foo python scriptname.py –

10

У меня была такая же проблема. Теперь я использую nose для выполнения моих тестов, и относительный импорт правильно обрабатывается.

Да, вся эта относительная импортная вещь сбивает с толку.

+2

. Я принимаю другой ответ только потому, что он позволяет мне делать то, что я пытался сделать с относительным импортом. Тем не менее, я также загружаю нос, чтобы использовать его в качестве тестового жгута, так как он выглядит намного мощнее, чем все, что я мог бы объединить самостоятельно. – Jonathanb

+0

только то, что я искал, спасибо – Copperfield

Смежные вопросы