TL; DR
Вот пример репозитория, который настроен, как описано в первой диаграмме (ниже): https://github.com/Poddster/package_problems
Если вы могли бы сделать так, чтобы он выглядел как вторая диаграмма с точки зрения организации проекта и все еще может выполнять следующие команды, то вы ответили на вопрос:
$ git clone https://github.com/Poddster/package_problems.git
$ cd package_problems
<do your magic here>
$ nosetests
$ ./my_tool/my_tool.py
$ ./my_tool/t.py
$ ./my_tool/d.py
(or for the above commands, $ cd ./my_tool/ && ./my_tool.py is also acceptable)
Альтернативно: дайте мне другую структуру проекта, которая позволяет мне группировать связанные файлы ( "пакет" ), запускать все файлы по отдельности, импортировать файлы в другие файлы в одном пакете и импортировать пакеты/файлы в другие файлы пакетов.
Текущая ситуация
У меня есть куча файлов python. Большинство из них полезны при вызове из командной строки, то есть все они используют argparse и if __name__ == "__main__"
для создания полезных вещей.
В настоящее время у меня есть эта структура каталогов, и все работает нормально:
.
├── config.txt
├── docs/
│ ├── ...
├── my_tool.py
├── a.py
├── b.py
├── c.py
├── d.py
├── e.py
├── README.md
├── tests
│ ├── __init__.py
│ ├── a.py
│ ├── b.py
│ ├── c.py
│ ├── d.py
│ └── e.py
└── resources
├── ...
Некоторые сценарии import
вещи из других скриптов для выполнения своей работы. Но нет script - это просто библиотека, все они вызываемы. например Я мог бы вызывать ./my_tool.py
, ./a.by
, ./b.py
, ./c.py
и т.д., И они будут полезны для пользователя.
"my_tool.py" является основным script, который использует все другие скрипты.
Что я хочу сделать
Однако я хочу изменить способ организации проекта. Сам проект представляет собой целую программу, используемую пользователем, и будет распространяться как таковой, но я знаю, что части ее будут полезны в разных проектах позже, поэтому я хочу попробовать и инкапсулировать текущие файлы в пакет. В ближайшем будущем я также добавлю другие пакеты в этот же проект.
Чтобы облегчить это, я решил реорганизовать проект примерно так:
.
├── config.txt
├── docs/
│ ├── ...
├── my_tool
│ ├── __init__.py
│ ├── my_tool.py
│ ├── a.py
│ ├── b.py
│ ├── c.py
│ ├── d.py
│ ├── e.py
│ └── tests
│ ├── __init__.py
│ ├── a.py
│ ├── b.py
│ ├── c.py
│ ├── d.py
│ └── e.py
├── package2
│ ├── __init__.py
│ ├── my_second_package.py
| ├── ...
├── README.md
└── resources
├── ...
Однако я не могу понять организацию проекта, которая удовлетворяет следующим критериям:
- Все сценарии invokable в командной строке (либо как
my_tool\a.py
илиcd my_tool && a.py
) - Тесты действительно выполняются:)
- Файлы в пакете2 могут выполнять
import my_tool
Основная проблема заключается в операторах импорта, используемых пакетами и тестах.
В настоящее время все пакеты, включая тесты, просто выполняют import <module>
, и он правильно разрешен. Но когда смещение вокруг не работает.
Обратите внимание, что поддержка py2.7 является требованием, поэтому все файлы имеют from __future__ import absolute_import, ...
вверху.
То, что я пробовал, и катастрофические результаты
1
Если я перемещаю файлы, как показано выше, но оставляю все операторы импорта, как они есть в настоящее время:
-
$ ./my_tool/*.py
работает, и все они работают нормально -
$ nosetests
запустить из верхнего каталога не работает. Тесты не позволяют импортировать сценарии пакетов. - pycharm выделяет операторы импорта красным цветом при редактировании этих файлов: (
2
Если я затем изменил тестовые сценарии, выполните следующие действия:
from my_tool import x
-
$ ./my_tool/*.py
все еще работает, и все они работают нормально -
$ nosetests
запустить из верхнего каталога не работает. Затем тесты могут импортировать правильные сценарии, но импорт самих скриптов терпит неудачу, когда тестовые скрипты импортируют их. - pycharm выделяет операции импорта в красном в основных сценариях: (
3
Если я сохраняю одну и ту же структуру и меняю все на from my_tool import
, тогда:
-
$ ./my_tool/*.py
приводит кImportError
-
$ nosetests
работает нормально. - pycharm ни о чем не жалуется
например. от 1.:
Traceback (most recent call last):
File "./my_tool/a.py", line 34, in <module>
from my_tool import b
ImportError: cannot import name b
4
Я также пробовал from . import x
, но это просто заканчивается ValueError: Attempted relative import in non-package
для прямого запуска скриптов.
Глядя на некоторые другие ответы SO:
Я не могу просто использовать python -m pkg.tests.core_test
как
a) У меня нет main.py. Думаю, у меня может быть один? б) Я хочу, чтобы иметь возможность запускать все скрипты, а не только основные?
Я пробовал:
if __name__ == '__main__' and __package__ is None:
from os import sys, path
sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
но это не помогло.
Я также пробовал:
__package__ = "my_tool"
from . import b
Но получил:
SystemError: Parent module 'loading_tool' not loaded, cannot perform relative import
добавление import my_tool
до from . import b
просто заканчивается на ImportError: cannot import name b
Фикс?
Каков правильный набор магических заклинаний и макета каталога, чтобы все это работало?