Найти - Пользователи
Полная версия: Правильная структура проекта.
Начало » Python для экспертов » Правильная структура проекта.
1 2
SmartBear
Здравствуйте. Никак не могу разобраться со структурой приложения.

Есть приложение, консольная утилита на python. Изначально структура проекта была такой:

(Все имена папок и файлов абстрактные, смысл вопроса от этого не меняется).

project/
├── app.py
├── LICENSE
├── MANIFEST.in
├── project
│   ├── cli.py
│   ├── module1.py
│   └── module2.py
├── pyproject.toml
├── README.md
├── requirements-dev.txt
├── requirements.txt
├── setup.cfg
├── setup.py
└── tox.ini

Смысл был в том, чтобы была возможность собрать пакет, опубликовать его на pypi.org и устанавливать с помощью pip. Далее запускать командой: project с нужными аргументами. Так же, можно просто скачать исходники и:
Либо запускать приложение напрямую:
1. python app.py (он импортирует main() из cli.py, и запускает, cli.py в свою очередь импортирует все что нужно из модулей).
2. Либо командой python setup.py install устанавливать локально, и запускать.

Все работало, и тут я начал читать о правильной структуре python-пакета.

Тогда я изменил структуру на:

project/
├── app.py
├── LICENSE
├── MANIFEST.in
├── pyproject.toml
├── README.md
├── requirements-dev.txt
├── requirements.txt
├── setup.cfg
├── setup.py
├── src
│   └── project
│   ├── cli.py
│   ├── module1.py
│   └── module2.py
└── tox.ini



И вот тут начались проблемы, сломались импорта, тесты перестали импортировать правильно, теперь они просят импорт from src.project.module1, но src это не пакет, а просто папка! Я должен выходит сначала устанавливать пакет локально, потом уже тестировать? Используя импорты такие: from project.module1?

App.py из корневой папки тоже вынуждено импортировать по новому используя from src.project.cli import main

В cli.py импорты так же сломались, если я использую импорт from src.project.module1 это ошибка, тем более после сборки пакета не сработает, если from project.module1это не работает при разработке, так как пакет не установлен.

Приложение:
Консольная утилита. (Cli).


Цели:
Сборка пакета, публикация на pypi.
Возможность установки pip install, и последующий запуск в командной строке.
Возможность запуска без установки, из исходников.

Вопросы:
1. Какова правильная структура такого проекта?
2. Если хранить пакет в папке src, как правильно импортировать в tests (использую pytest), как правильно импортировать между модулями внутри пакета.
3. Какие настройки нужны в setup.cfg для правильной сборки пакета.
4. Какие файлы и папки я должен указывать для добавления в пакет в MANIFEST.in, нужно ли добавлять tests?
5. Нужно ли добавлять тесты в пакет? Проблема в том, что папка tests, подтягивалась автоматически, при 1 варианте структуры пакета, она распаковывалась глобально, если установить второй похожий пакет со структурой 1 варианта, файлы в папке tests заменялись, ну и вообще такая распаковка при установке уже явно неверная.
6. Если я буду использовать верную структуру пакетов как мне импортировать при разработке, тестировании и какие импорты выставлять при сборке, как импортировать между модулями?


Добавлю, что это не просто пакет, а пакет с возможностью запуска его в командной строке. Ну и нужна поддержка запуска без установки, из исходников.

Все это работало, до использования информации с pypi.org о правильной структуре пакетов, но замечал, что пакет при установке распаковывался частично в глобальную папку (так как имел неверную структуру я полагаю). Каждый пакет устанавливается в свою папку (точнее их две), при установке моих пакетов некоторые файлы и папки распаковывалась глобально, заменяя похожие файлы из других пакетов .

При правильной структуре этих проблем нет, но есть куча проблем с импортами при разработке и т.д.

При моем первом варианте, проблем почти нет, только распаковка некоторых файлов глобально, и подтягивается папка tests, я ее в файле MANIFEST.in исключил глобально.

Используя первую структуру проекта, мне удобно разрабатывать, тестировать, собирать, публиковать, запускать.

Используя вторую (правильную) структуру, все ломается, появляется куча проблем и геморроя, в том числе и с импортами, почему же тогда ее считают правильной? Я заметил только незначительные проблемы при установке пакета с глобальной распаковкой некоторых файлов.

Так как же быть?
Rodegast
> Так как же быть?

Работает — не трожь!
py.user.next
SmartBear
Все работало, и тут я начал читать о правильной структуре python-пакета.
Тогда я изменил структуру на:
Я думаю, ты просто не врубаешься, что проект и то, что выкладывается в паблик, - это разные вещи абсолютно. У тебя в проекте должен быть сборщик пакета для https://pypi.org . При этом проект ты делаешь так, как нужно тебе одному. И, естественно, никакие тесты не должны идти в паблик. Тесты должны быть в проекте. Ты спросишь "а как же мне сделать так, чтобы у меня был пакет, пригодный для https://pypi.org ?", ответ очень прост - напиши скрипт для создания такого пакета из проектных файлов. Это относится не только к Python'у и https://pypi.org , но и к другим языкам с другими пабликами.
SmartBear
Rodegast
> Так как же быть?Работает — не трожь!
Абсолютно с вами согласен)
SmartBear
py.user.next
Для pypi собираю командой python -m build, или python setup.py sdist bdist_wheel, но есть проблемы о которых я писал выше. Возможно вы имеете ввиду, проект оставить удобным для разработки, а сборщик будет собирать все в правильную структуру?
py.user.next
SmartBear
Возможно вы имеете ввиду, проект оставить удобным для разработки, а сборщик будет собирать все в правильную структуру?
Да. Твоя ошибка в том, что ты пытаешься проектную структуру скопировать в пакетную структуру. А надо собрать пакетную структуру скриптом из файлов проекта и потом из этой пакетной структуры собрать пакет.
SmartBear
py.user.next
А надо собрать пакетную структуру скриптом из файлов проекта и потом из этой пакетной структуры собрать пакет.
Хорошо. С этим немного разобрался. Но встаёт вопрос: а зачем же мне всё таки, все эти заморочки, если всё и так отлично работает. Немного подкорректировал MANIFEST.in and setup.py and setup.cfg, и проблемы вообще исчезли. Почему принято (и об этом сказано в официальной документации) использовать структуру с src? Для удобства сборки deb и им подобных? Или эта папка отсылка к структуре на других языках которым она требуется?
SmartBear
slav0nic
советую начать с
https://packaging.python.org/
https://github.com/audreyfeldroy/cookiecutter-pypackage
https://github.com/pypa/sampleproject

Спасибо большое. Буду ещё читать, так как пробегал по докам мельком на 50-60%, пытаясь найти быстрые ответы на острые вопросы, но думаю надо внимательно читать, чтобы как в моём случае ничего не упустить и вникнуть в суть.
py.user.next
SmartBear
Но встаёт вопрос: а зачем же мне всё таки, все эти заморочки, если всё и так отлично работает.
Потому что завтра оно не будет работать. Завтра тебе нужно будет добавить что-то в программу (расширить её, переделать её, выделить из неё часть куда-нибудь в отдельный проект), ты попробуешь, а там всё поломается. И ты в итоге скажешь “ой, а я не могу это добавить, потому что у меня какие-то там пакеты перестают собираться из-за этого”. У тебя нет свободы, потому что ты сковал проект. А нужно его освободить, наоборот. И для освобождения ты разрываешь связи в проекте, а не создаёшь их. Короче, у тебя проект становится зависимым от того, как у тебя там пакеты собираются какие-то. Хвост начинает вилять собакой.

SmartBear
Почему принято (и об этом сказано в официальной документации) использовать структуру с src?
Это где? Ты не понимаешь, что проект может включать в себя десятки пакетов. И не всегда их все надо собирать. А где-то они вообще взаимоисключающие и их нельзя собирать одновременно. Так что скачивай настоящие проекты, смотри на их структуру, смотри на то, как они обслуживаются внутренне, какие там скрипты и что они делают.

SmartBear
Немного подкорректировал MANIFEST.in and setup.py and setup.cfg, и проблемы вообще исчезли.
Это тебе просто повезло. Но это не правило. А могли не исчезнуть проблемы. Не все эти системы сборок хорошо сделаны, не все они параметризуются хорошо. Иногда они предоставляют очень скудные возможности в плане гибкости конфигурации. При этом система сборки может что-то сделать физически, но через конфигурацию оно не настраивается. Это ситуация, когда ты сам должен конфигурировать своими силами то, что не расчитано на конфигурирование (ну, не доработали программисты, которые там её разрабатывали, поленились сделать что-то, оставили на потом). Ну, и что ты будешь делать тогда? Ты будешь искать другую систему сборки, где есть это конфигурирование. Потому что сам ты себе всё сделать не можешь; тебе дяденьки всё время должны давать библиотечки там всякие, системы сборок и тому подобное.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB