Для моего проекта Python 3 у меня есть следующая структура каталогов:
├── myapp
│ ├── compute
│ │ └── compute.py
│ └── mymain.py
├── setup.py
└── tests
└── compute
└── compute_test.py
Моя цель состоит в том, чтобы иметь возможность выполнить код здесь тремя способами:
- Unitтесты.Я случайно выбрал
pytest
для них, но какой бы ни был фреймворк; python myapp/mymain.py <arguments>
для того, когда я хочу сделать быстрый "ручной тест"; - Что-то вроде
pip install
и / или образ Docker для правильного развертывания.
Теперь, первый и третий из них, похоже, не проблема, но у меня проблемы с серединой.
Вот содержимое файлов:
compute.py
:
import math
class MyComputation:
# performs an extremely difficult and relevant computation
@staticmethod
def compute(i: int) -> float:
return math.sqrt(abs(i))
compute_test.py
:
import pytest
from myapp.compute.compute import MyComputation
def test_computation_normal_case():
ins = [-4, 9, -36, 121]
outs = list(map(lambda i: MyComputation.compute(i), ins))
expected = [2.0, 3.0, 6.0, 11.0]
assert outs == expected
mymain.py
:
import random
from myapp.compute.compute import MyComputation
class MyApp:
@staticmethod
def main():
print("Loading data...")
i = random.randint(1, 100000)
print("Input: {}".format(i))
print("Computing...")
f = MyComputation.compute(i)
print("Output: {}".format(f))
print("Done!")
if __name__ == "__main__":
MyApp.main()
Когда я запускаю, скажем, pytest
из командной строки, он работает нормально: находит тест, запускает его, тест проходит.
Однако, когда я пытаюсь запустить основной класс:
$ python myapp/mymain.py
Traceback (most recent call last):
File "myapp/mymain.py", line 8, in <module>
from myapp.compute.compute import MyComputation
ImportError: No module named myapp.compute.compute
Не имеет значения, добавляю ли я __init__.py
файлы в каталоги или нет.
Но если я добавлю следующее в mymain.py
, его можно будет запустить из командыстрока, как и ожидалось:
import os
import sys
root_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../'))
sys.path.insert(0, root_path)
Итак, вопросы:
1) Как правильно, Pythonic, идиоматический способ сделать основной класс?По сути, я хочу «запустить этот код здесь, на месте, как есть».Где я могу поставить свой основной класс?Нужно ли мне pip install
мои вещи сначала локально?Нужно ли делать импорт по-другому?
2) Конечно, материал sys.path.insert()
не может быть "официальным" способом выполнения того, что я хочу сделать здесь?Должен быть менее нелепый способ ... верно?
3) Почему юнит-тесты работают просто отлично, а основной класс - нет?Есть ли в модуле модульного тестирования что-то похожее на sys.path.insert()
под крышками?Или есть лучший способ обработки импорта?