Самостоятельная ссылка для утверждений во время модульного тестирования

Во-первых, предположим следующую структуру каталогов пакета Python под названием mypackage, которая следует инструкциям руководства Как упаковать код Python. :

mypackage/
mypackage/mypackage/
mypackage/mypackage/__init__.py
mypackage/mypackage/a_function.py
mypackage/scripts/
mypackage/scripts/a_script.py
mypackage/tests/
mypackage/tests/a_function_test.py
mypackage/misc/
mypackage/misc/input.txt
# mypackage/misc/actual_output.txt  ## Not yet generated!
mypackage/misc/expected_output.txt
mypackage/setup.py

Во-вторых, предположим, что сценарий a_script.py импортирует a_function.py, читает файл input.txt, обрабатывает содержимое input.txt и сохраняет последний как actual_output.txt в mypackage/misc/.

В-третьих, предположим, что модуль unittest mypackage/misc/ содержит тестовую функцию для сравнения expected_output.txt с actual_output.txt через self.assertMultiLineEqual(expected, actual).

Наконец, предположим, что я хочу запустить модуль unittest через python2 setup.py test.

Как указать расположение actual_output.txt и expected_output.txt в a_function_test.py без жесткого кодирования их абсолютных путей к файлам (и, следовательно, предотвращения возможности передачи моего пакета)?

Рассмотрение:

Теоретически я могу жестко указать путь внутри пакета к каждому из двух входных файлов. Однако как интерпретатор Python узнает, где искать mypackage, если он еще не установлен в site-packages? У меня была следующая идея, но она терпит неудачу, поскольку mypackage еще не известно:

base_path = os.path.split(inspect.getfile(mypackage))[0]
within_path = mypackage/misc/
expected = open(base_path + within_path + expected_output.txt).read()
actual = open(base_path + within_path + actual_output.txt).read()
self.assertMultiLineEqual(expected, actual)

person Michael G    schedule 16.05.2016    source источник


Ответы (1)


Из a_script.py попасть в основной mypackage можно так:

mypackage_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

or:

mypackage_dir = os.path.dirname(os.path.abspath(__package__))

затем можно построить другие пути, поскольку вы знаете имя подпакета:

misc_dir = os.path.join(mypackage_dir, 'misc')
tests_dir = os.path.join(mypackage_dir, 'tests')
person Moses Koledoye    schedule 16.05.2016
comment
Спасибо, но os.path.abspath(__package__) не работает с AttributeError: 'NoneType' object has no attribute 'startswith'. - person Michael G; 17.05.2016
comment
Являются ли ваши каталоги пакетами Python? Есть ли в них __init__.py. В противном случае это может не сработать - person Moses Koledoye; 17.05.2016
comment
Я только поместил __init__.py в mypackage/mypackage/ (см. отредактированный вопрос). В какие из других подпакетов я должен поместить __init__.py? - person Michael G; 17.05.2016
comment
Чтобы превратить все каталоги, содержащие файлы .py, в пакеты и подпакеты, вы должны добавить файл __init__.py. Таким образом, основной файл mypackage также должен иметь файл __init__.py. - person Moses Koledoye; 17.05.2016
comment
Хорошо, я поместил пустой файл __init__.py в /mypackage/. Тем не менее, я по-прежнему получаю сообщение об ошибке, как показано ниже [Примечание: уценка делает слово package полужирным, если я предшествую ему и после него двумя символами подчеркивания, отсюда и странное написание]: base_path = os.path.abspath(_ _package_ _) File "/usr/lib/python2.7/posixpath.py", line 360, in abspath if not isabs(path): File "/usr/lib/python2.7/posixpath.py", line 54, in isabs return s.startswith('/') AttributeError: 'NoneType' object has no attribute 'startswith' - person Michael G; 17.05.2016
comment
Тогда используйте подход __file__ - person Moses Koledoye; 17.05.2016
comment
Давайте продолжим обсуждение в чате. - person Moses Koledoye; 17.05.2016