Какова лучшая структура проекта для приложения Python?

Представьте, что вы хотите разработать нетривиальное настольное (не веб) приложение для конечного пользователя на Python. Каков наилучший способ структурировать иерархию папок проекта?

Желаемыми функциями являются простота обслуживания, удобство IDE, пригодность для ветвления / слияния управления исходным кодом и простота создания инсталляционных пакетов.

Особенно:

  1. Где вы положили источник?
  2. Где вы размещаете сценарии запуска приложения?
  3. Куда вы кладете проект IDE?
  4. Где вы положили блок / приемочные испытания?
  5. Где вы размещаете не-Python данные, такие как файлы конфигурации?
  6. Где вы размещаете не-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>,
  • Где вы размещаете сценарии запуска приложения?

    • Идеальный вариант - зарегистрировать скрипт запуска приложения как entry_point в одном из яиц.
  • Куда вы кладете проект IDE?

    • Зависит от IDE. Многие из них хранят свои вещи в PROJECT_ROOT/.<something> в корне проекта, и это нормально.
  • Где вы положили блок / приемочные испытания?

    • Каждое яйцо имеет отдельный набор тестов, хранящихся в его 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.
  • Где вы размещаете не-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).

Другие вопросы по тегам