Какова лучшая структура проекта для приложения Python?
Представьте, что вы хотите разработать нетривиальное настольное (не веб) приложение для конечного пользователя на Python. Каков наилучший способ структурировать иерархию папок проекта?
Желаемыми функциями являются простота обслуживания, удобство IDE, пригодность для ветвления / слияния управления исходным кодом и простота создания инсталляционных пакетов.
Особенно:
- Где вы положили источник?
- Где вы размещаете сценарии запуска приложения?
- Куда вы кладете проект IDE?
- Где вы положили блок / приемочные испытания?
- Где вы размещаете не-Python данные, такие как файлы конфигурации?
- Где вы размещаете не-Python исходники, такие как C++ для бинарных модулей расширения pyd/so?
8 ответов
Не имеет большого значения. Все, что делает тебя счастливым, сработает. Существует не так много глупых правил, потому что проекты Python могут быть простыми.
/scripts
или же/bin
для такого рода интерфейса командной строки/tests
для ваших тестов/lib
для ваших библиотек C-языка/doc
для большей части документации/apidoc
для сгенерированных Epydoc документов API.
А каталог верхнего уровня может содержать README, Config и еще много чего.
Трудный выбор - использовать или нет /src
дерево. Python не имеет различия между /src
, /lib
, а также /bin
как Java или C имеет.
С верхнего уровня /src
каталог рассматривается некоторыми как бессмысленный, ваш каталог верхнего уровня может быть архитектурой верхнего уровня вашего приложения.
/foo
/bar
/baz
Я рекомендую поместить все это в каталог "name-of-my-product". Итак, если вы пишете приложение с именем quux
, каталог, который содержит все эти вещи называется /quux
,
Еще один проект PYTHONPATH
затем может включать /path/to/quux/foo
повторно использовать QUUX.foo
модуль.
В моем случае, поскольку я использую Komodo Edit, моя среда IDE представляет собой один файл.KPF. Я на самом деле положил это на верхнем уровне /quux
каталог и не добавляйте его в SVN.
Согласно структуре файловой системы Жан-Поля Кальдероне проекта Python:
Project/
|-- bin/
| |-- project
|
|-- project/
| |-- test/
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py
|
|-- setup.py
|-- README
Этот пост в блоге Жана-Пола Кальдероне обычно дается в качестве ответа в #python на Freenode.
Структура файловой системы проекта Python
Делать:
- Назовите каталог, связанный с вашим проектом. Например, если ваш проект называется "Twisted", назовите каталог верхнего уровня для его исходных файлов.
Twisted
, Когда вы делаете релизы, вы должны включать суффикс номера версии:Twisted-2.5
,- создать каталог
Twisted/bin
и положите туда свои исполняемые файлы, если они у вас есть. Не дают им.py
расширение, даже если они исходные файлы Python. Не помещайте в них какой-либо код, кроме импорта и вызова основной функции, определенной где-то еще в ваших проектах. (Небольшая складка: поскольку в Windows интерпретатор выбирается по расширению файла, ваши пользователи Windows на самом деле хотят расширение.py. Поэтому, когда вы создаете пакет для Windows, вы можете захотеть добавить его. К сожалению, нет простого трюка с distutils, который Я знаю, как автоматизировать этот процесс. Учитывая, что в POSIX расширение.py - это всего лишь бородавка, тогда как в Windows его отсутствие - это настоящая ошибка, если в вашей базе пользователей есть пользователи Windows, вы можете выбрать просто иметь.py расширение везде.)- Если ваш проект может быть выражен как один исходный файл Python, поместите его в каталог и назовите его как-нибудь связанный с вашим проектом. Например,
Twisted/twisted.py
, Если вам нужно несколько исходных файлов, вместо этого создайте пакет (Twisted/twisted/
с пустымTwisted/twisted/__init__.py
) и поместите в него ваши исходные файлы. Например,Twisted/twisted/internet.py
,- Поместите ваши модульные тесты в подпакет вашего пакета (обратите внимание - это означает, что указанная выше опция с единственным исходным файлом Python была хитростью - для ваших модульных тестов всегда нужен хотя бы один другой файл). Например,
Twisted/twisted/test/
, Конечно, сделайте пакет сTwisted/twisted/test/__init__.py
, Поместите тесты в файлы, такие какTwisted/twisted/test/test_internet.py
,- добавлять
Twisted/README
а такжеTwisted/setup.py
объяснить и установить программное обеспечение, соответственно, если вы чувствуете себя хорошо.Не рекомендуется:
- поместите ваш источник в каталог под названием
src
или жеlib
, Это затрудняет запуск без установки.- поместите свои тесты вне вашего пакета Python. Это затрудняет запуск тестов с установленной версией.
- создать пакет, который имеет только
__init__.py
а затем положить весь свой код в__init__.py
, Просто сделайте модуль вместо пакета, это проще.- попробуйте придумать волшебные хаки, чтобы Python мог импортировать ваш модуль или пакет без необходимости добавления пользователем каталога, содержащего его, в свой путь импорта (либо через PYTHONPATH, либо через какой-либо другой механизм). Вы не будете правильно обрабатывать все случаи, и пользователи будут злиться на вас, если ваше программное обеспечение не работает в их среде.
Проверьте Open Sourcing Python Project правильный путь.
Позвольте мне извлечь часть макета проекта из этой превосходной статьи:
При настройке проекта важно правильно настроить макет (или структуру каталогов). Разумный макет означает, что потенциальные участники не должны тратить целую вечность на поиски фрагмента кода; Расположение файлов интуитивно понятно. Поскольку мы имеем дело с существующим проектом, это означает, что вам, вероятно, придется передвигать некоторые вещи.
Давайте начнем с вершины. В большинстве проектов есть несколько файлов верхнего уровня (например, setup.py, README.md, needs.txt и т. Д.). Затем есть три каталога, которые должен иметь каждый проект:
- Каталог документов, содержащий проектную документацию
- Каталог с именем проекта, в котором хранится актуальный пакет Python
- Тестовый каталог в одном из двух мест
- Под каталогом пакета, содержащим тестовый код и ресурсы
- Как автономный каталог верхнего уровня. Чтобы лучше понять, как должны быть организованы ваши файлы, вот упрощенный снимок макета для одного из моих проектов, sandman:
$ pwd
~/code/sandman
$ tree
.
|- LICENSE
|- README.md
|- TODO.md
|- docs
| |-- conf.py
| |-- generated
| |-- index.rst
| |-- installation.rst
| |-- modules.rst
| |-- quickstart.rst
| |-- sandman.rst
|- requirements.txt
|- sandman
| |-- __init__.py
| |-- exception.py
| |-- model.py
| |-- sandman.py
| |-- test
| |-- models.py
| |-- test_sandman.py
|- setup.py
Как видите, есть несколько файлов верхнего уровня, каталог docs (сгенерированный является пустым каталогом, в который sphinx поместит сгенерированную документацию), каталог sandman и тестовый каталог в sandman.
У "Python Packaging Authority" есть пример проекта:
https://github.com/pypa/sampleproject
Это пример проекта, который существует в качестве пособия к Руководству пользователя Python Packaging, посвященному проектам упаковки и распространения.
Попробуйте запустить проект, используя шаблон python_boilerplate. Он во многом соответствует лучшим практикам (например, здесь), но лучше подходит, если вы захотите разделить свой проект на несколько яиц в какой-то момент (и, поверьте мне, с любыми проектами, кроме самых простых, вы это сделаете). Распространенная ситуация, когда вы должны использовать локально-модифицированную версию чужой библиотеки).
Где вы положили источник?
- Для прилично больших проектов имеет смысл разделить источник на несколько яиц. Каждое яйцо будет идти как отдельная настройка setuptools под
PROJECT_ROOT/src/<egg_name>
,
- Для прилично больших проектов имеет смысл разделить источник на несколько яиц. Каждое яйцо будет идти как отдельная настройка setuptools под
Где вы размещаете сценарии запуска приложения?
- Идеальный вариант - зарегистрировать скрипт запуска приложения как
entry_point
в одном из яиц.
- Идеальный вариант - зарегистрировать скрипт запуска приложения как
Куда вы кладете проект IDE?
- Зависит от IDE. Многие из них хранят свои вещи в
PROJECT_ROOT/.<something>
в корне проекта, и это нормально.
- Зависит от IDE. Многие из них хранят свои вещи в
Где вы положили блок / приемочные испытания?
- Каждое яйцо имеет отдельный набор тестов, хранящихся в его
PROJECT_ROOT/src/<egg_name>/tests
каталог. Я лично предпочитаю использоватьpy.test
запустить их.
- Каждое яйцо имеет отдельный набор тестов, хранящихся в его
Где вы размещаете не-Python данные, такие как файлы конфигурации?
- Это зависит. Могут быть разные типы данных, отличных от Python.
- "Ресурсы", то есть данные, которые должны быть упакованы в яйцо. Эти данные попадают в соответствующий каталог egg где-то в пространстве имен пакета. Может использоваться через
pkg_resources
пакет. - "Config-файлы", то есть не-Python файлы, которые должны рассматриваться как внешние по отношению к исходным файлам проекта, но должны быть инициализированы с некоторыми значениями, когда приложение запускается. Во время разработки я предпочитаю хранить такие файлы в
PROJECT_ROOT/config
, Для развертывания могут быть различные варианты. На Windows можно использовать%APP_DATA%/<app-name>/config
в Linux/etc/<app-name>
или же/opt/<app-name>/config
, - Сгенерированные файлы, то есть файлы, которые могут быть созданы или изменены приложением во время выполнения. Я бы предпочел держать их в
PROJECT_ROOT/var
во время разработки и под/var
во время развертывания Linux.
- "Ресурсы", то есть данные, которые должны быть упакованы в яйцо. Эти данные попадают в соответствующий каталог egg где-то в пространстве имен пакета. Может использоваться через
- Это зависит. Могут быть разные типы данных, отличных от Python.
- Где вы размещаете не-Python исходники, такие как C++ для бинарных модулей расширения pyd/so?
- В
PROJECT_ROOT/src/<egg_name>/native
- В
Документация обычно идет в PROJECT_ROOT/doc
или же PROJECT_ROOT/src/<egg_name>/doc
(это зависит от того, считаете ли вы некоторые яйца отдельными крупными проектами). Некоторая дополнительная конфигурация будет в файлах, таких как PROJECT_ROOT/buildout.cfg
а также PROJECT_ROOT/setup.cfg
,
По моему опыту, это просто вопрос итерации. Размещайте свои данные и код там, где вы думаете, куда они идут Скорее всего, вы все равно будете неправы. Но как только вы получите лучшее представление о том, как все будет складываться, вы будете в гораздо лучшем положении, чтобы делать подобные предположения.
Что касается источников расширения, у нас есть каталог Code в trunk, который содержит каталог для python и каталог для различных других языков. Лично я больше склонен в следующий раз попытаться поместить любой код расширения в свой собственный репозиторий.
С учетом сказанного я возвращаюсь к своей исходной точке: не делайте из этого слишком большой сделки. Положите его туда, где вам кажется Если вы найдете что-то, что не работает, это можно (и нужно) изменить.
Данные, не относящиеся к Python, лучше всего связывать внутри ваших модулей Python, используя package_data
поддержка в setuptools. Я настоятельно рекомендую использовать пакеты пространств имен для создания общих пространств имен, которые могут использовать несколько проектов - так же, как соглашение Java о размещении пакетов в com.yourcompany.yourproject
(и возможность иметь общий com.yourcompany.utils
Пространство имен).
Повторное ветвление и слияние, если вы используете достаточно хорошую систему контроля версий, она будет обрабатывать слияния даже через переименования; Базар особенно хорош в этом.
Вопреки некоторым другим ответам здесь, я +1 при наличии src
каталог верхнего уровня (с doc
а также test
каталоги рядом). Конкретные соглашения для деревьев каталогов документации будут варьироваться в зависимости от того, что вы используете; Sphinx, например, имеет свои собственные соглашения, которые поддерживает его инструмент быстрого запуска.
Пожалуйста, пожалуйста, используйте setuptools и pkg_resources; это значительно упрощает использование другими проектами определенных версий вашего кода (и одновременную установку нескольких версий с разными файлами, не относящимися к коду, если вы используете package_data
).