¿Cuál es la mejor estructura de proyecto para una aplicación Python? [cerrado]


Imagine que desea desarrollar una aplicación de escritorio de usuario final no trivial (no web) en Python. ¿Cuál es la mejor manera de estructurar la jerarquía de carpetas del proyecto?

Las características deseables son facilidad de mantenimiento, compatibilidad con IDE, idoneidad para la ramificación/fusión de control de código fuente y fácil generación de paquetes de instalación.

En particular:

  1. ¿Dónde pones la fuente?
  2. ¿Dónde pone los scripts de inicio de la aplicación?
  3. Dónde se pone el IDE ¿proyecto cruft?
  4. ¿Dónde se colocan las pruebas de unidad/aceptación?
  5. ¿Dónde pone datos que no son de Python, como archivos de configuración?
  6. ¿Dónde pone fuentes no Python como C++ para módulos de extensión binaria pyd/so?
Author: suci, 2008-10-11

8 answers

No importa demasiado. Lo que te haga feliz funcionará. No hay muchas reglas tontas porque los proyectos de Python pueden ser simples.

  • /scripts o /bin para ese tipo de interfaz de línea de comandos
  • /tests para sus pruebas
  • /lib para sus bibliotecas de lenguaje C
  • /doc para la mayoría de la documentación
  • /apidoc para los documentos de API generados por Epydoc.

Y el directorio de nivel superior puede contener README, Config y qué más.

La elección difícil es si usar o no un árbol /src. Python no tiene una distinción entre /src, /lib, y /bin como Java o C tiene.

Dado que un directorio /src de nivel superior es visto por algunos como sin sentido, su directorio de nivel superior puede ser la arquitectura de nivel superior de su aplicación.

  • /foo
  • /bar
  • /baz

Recomiendo poner todo esto bajo el directorio "nombre-de-mi-producto". Así que, si eres al escribir una aplicación llamada quux, el directorio que contiene todo esto se llama /quux.

Otro proyecto PYTHONPATH, entonces, puede incluir /path/to/quux/foo para reutilizar el módulo QUUX.foo.

En mi caso, ya que uso Komodo Edit, mi IDE cuft es un solo .Archivo KPF. En realidad lo pongo en el directorio de nivel superior /quux, y omito agregarlo a SVN.

 310
Author: S.Lott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-11 01:43:11

De acuerdo con la estructura del sistema de archivos de Jean-Paul Calderone de un proyecto Python :

Project/
|-- bin/
|   |-- project
|
|-- project/
|   |-- test/
|   |   |-- __init__.py
|   |   |-- test_main.py
|   |   
|   |-- __init__.py
|   |-- main.py
|
|-- setup.py
|-- README
 204
Author: cmcginty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-20 14:56:50

Esta entrada de blog de Jean-Paul Calderone se da comúnmente como una respuesta en #python en Freenode.

Estructura del sistema de archivos de un proyecto Python

Do:

  • nombre el directorio algo relacionado con su proyecto. Por ejemplo, si su proyecto se llama "Twisted", nombre el directorio de nivel superior para sus archivos de origen Twisted. Cuando haga lanzamientos, debe incluir un sufijo de número de versión: Twisted-2.5.
  • crear un directorio Twisted/bin y ponga sus ejecutables allí, si tiene alguno. No les dé una extensión .py, incluso si son archivos fuente de Python. No ponga ningún código en ellos, excepto una importación de y llamar a una función principal definida en algún otro lugar de sus proyectos. (Leve arruga: ya que en Windows, el intérprete es seleccionado por la extensión de archivo, los usuarios de Windows realmente quieren la extensión. py. Entonces, cuando empaquete para Windows, es posible que desee agregarlo. Desafortunadamente no hay un truco fácil que yo sepa para automatice este proceso. Teniendo en cuenta que en POSIX la extensión .py es solo una verruga, mientras que en Windows la falta es un error real, si su base de usuarios incluye usuarios de Windows, es posible que desee optar por solo tener la extensión .py en todas partes.)
  • Si su proyecto es expresable como un único archivo fuente de Python, póngalo en el directorio y asígnele un nombre relacionado con su proyecto. Por ejemplo, Twisted/twisted.py. Si necesita varios archivos fuente, cree un paquete en su lugar (Twisted/twisted/, con un Twisted/twisted/__init__.py) y coloque sus archivos fuente en él. Por ejemplo, Twisted/twisted/internet.py.
  • coloque sus pruebas unitarias en un subpaquete de su paquete (nota-esto significa que la opción de archivo fuente único de Python anterior fue un truco - usted siempre necesita al menos otro archivo para sus pruebas unitarias). Por ejemplo, Twisted/twisted/test/. Por supuesto, que sea un paquete con Twisted/twisted/test/__init__.py. Coloque pruebas en archivos como Twisted/twisted/test/test_internet.py.
  • agregue Twisted/README y Twisted/setup.py para explicar e instalar su software, respectivamente, si se siente bien.

No:

  • ponga su fuente en un directorio llamado src o lib. Esto hace que sea difícil de ejecutar sin instalar.
  • ponga sus pruebas fuera de su paquete Python. Esto hace que sea difícil ejecutar las pruebas contra una versión instalada.
  • cree un paquete que solo tenga un __init__.py y luego ponga todo su código en __init__.py. Simplemente haga un módulo en lugar de un paquete, es más simple.
  • tratar de llegar a hacks mágicos para hacer Python capaz de importar su módulo o paquete sin que el usuario agregue el directorio que lo contiene a su ruta de importación (ya sea a través de PYTHONPATH o algún otro mecanismo). Usted no manejará correctamente todos los casos y los usuarios se enojarán con usted cuando su software no funcione en su entorno.
 182
Author: Adrian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-06 20:42:24

Echa un vistazo a Open Sourcing un Proyecto Python de la Manera Correcta.

Permítanme extraer el diseño del proyecto parte de ese excelente artículo:

Al configurar un proyecto, es importante que el layout (o estructura de directorios) sea correcto. Un diseño sensato significa que los contribuyentes potenciales no tienen que pasar siempre buscando un fragmento de código; la ubicación de los archivos es intuitiva. Dado que estamos tratando con un proyecto existente, significa que probablemente tendrá que mover algunos cosas alrededor.

Comencemos por arriba. La mayoría de los proyectos tienen una serie de archivos de nivel superior (como setup.py, README.md, requisitos.txt, etc.). Hay entonces tres directorios que cada proyecto debe tener:

  • Un directorio docs que contiene documentación del proyecto
  • Un directorio nombrado con el nombre del proyecto que almacena el paquete Python real
  • Un directorio de prueba en uno de dos lugares
    • En el directorio de paquetes que contiene test código y recursos
    • Como un directorio de nivel superior independiente Para tener una mejor idea de cómo deben organizarse sus archivos, aquí hay una instantánea simplificada del diseño de uno de mis proyectos, 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

Como puede ver, hay algunos archivos de nivel superior, un directorio docs (generado es un directorio vacío donde sphinx pondrá la documentación generada), un directorio sandman, y un directorio de prueba bajo sandman.

 96
Author: David C. Bishop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-08 09:44:30

La "Autoridad de Empaquetado de Python" tiene un sampleproject:

Https://github.com/pypa/sampleproject

Es un proyecto de ejemplo que existe como una ayuda para el Tutorial de Python Packaging User Guide sobre Empaquetar y Distribuir Proyectos.

 18
Author: guettli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-07 05:37:41

Intente iniciar el proyecto usando la plantilla python_boilerplate. Sigue en gran medida las mejores prácticas (por ejemplo, las de aquí), pero es más adecuado en caso de que te encuentres dispuesto a dividir tu proyecto en más de un huevo en algún momento (y créeme, con cualquier cosa menos los proyectos más simples, lo harás. Una situación común es cuando tienes que usar una versión modificada localmente de la biblioteca de otra persona).

  • ¿Dónde pones la fuente?

    • Para proyectos decentemente grandes tiene sentido dividir la fuente en varios huevos. Cada huevo iría como un setuptools-layout separado bajo PROJECT_ROOT/src/<egg_name>.
  • ¿Dónde pone los scripts de inicio de la aplicación?

    • La opción ideal es tener el script de inicio de la aplicación registrado como entry_point en uno de los huevos.
  • Dónde poner el proyecto IDE ¿cruft?

    • Depende del IDE. Muchos de ellos mantienen sus cosas en PROJECT_ROOT/.<something> en la raíz del proyecto, y esto está bien.
  • ¿Dónde colocas las pruebas de unidad / aceptación?

    • Cada huevo tiene un conjunto separado de pruebas, mantenidas en su directorio PROJECT_ROOT/src/<egg_name>/tests. Personalmente prefiero usar py.test para ejecutarlos.
  • ¿Dónde pone datos que no son de Python, como archivos de configuración?

    • depende. Alli pueden ser diferentes tipos de datos que no son de Python.
      • "Recursos", es decir, datos que deben ser empaquetados dentro de un huevo. Estos datos van al directorio egg correspondiente, en algún lugar dentro del espacio de nombres del paquete. Se puede utilizar a través del paquete pkg_resources.
      • "Config-files", es decir, archivos no Python que deben considerarse externos a los archivos fuente del proyecto, pero deben inicializarse con algunos valores cuando la aplicación comienza a ejecutarse. Durante el desarrollo prefiero mantener tales archivos en PROJECT_ROOT/config. Para el despliegue puede haber varias opciones. En Windows se puede usar %APP_DATA%/<app-name>/config, en Linux, /etc/<app-name> o /opt/<app-name>/config.
      • Archivos generados, es decir, archivos que pueden ser creados o modificados por la aplicación durante la ejecución. Preferiría mantenerlos en PROJECT_ROOT/var durante el desarrollo, y bajo /var durante el despliegue de Linux.
  • ¿Dónde pone fuentes no Python como C++ para módulos de extensión binaria pyd/so?
    • En PROJECT_ROOT/src/<egg_name>/native

La documentación normalmente entraría en PROJECT_ROOT/doc o PROJECT_ROOT/src/<egg_name>/doc (esto depende de si considera que algunos de los huevos son proyectos grandes separados). Alguna configuración adicional estará en archivos como PROJECT_ROOT/buildout.cfg y PROJECT_ROOT/setup.cfg.

 16
Author: KT.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-21 09:49:41

En mi experiencia, es solo una cuestión de iteración. Ponga sus datos y código donde quiera que crea que van. Lo más probable es que te equivoques de todos modos. Pero una vez que tienes una mejor idea de exactamente cómo las cosas van a salir, estás en una mejor posición para hacer este tipo de conjeturas.

En cuanto a las fuentes de extensión, tenemos un directorio de código bajo trunk que contiene un directorio para python y un directorio para varios otros idiomas. Personalmente, estoy más inclinado a tratar de poner cualquier código de extensión en su propio repositorio la próxima vez.

Dicho esto, vuelvo a mi punto inicial: no hagas un gran problema con esto. Ponlo en algún lugar que parezca funcionar para ti. Si encuentras algo que no funciona, puede (y debe) cambiarse.

 14
Author: Jason Baker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-10 22:57:39

Los datos que no son de python se agrupan mejor dentro de sus módulos Python utilizando el soporte package_data en setuptools. Una cosa que recomiendo encarecidamente es usar paquetes de espacio de nombres para crear espacios de nombres compartidos que varios proyectos pueden usar much al igual que la convención de Java de poner paquetes en com.yourcompany.yourproject (y poder tener un espacio de nombres compartido com.yourcompany.utils).

Re ramificación y fusión, si utiliza un sistema de control de código fuente lo suficientemente bueno, manejará las fusiones incluso a través de renombres; Bazaar es particularmente bueno en esto.

Contrariamente a algunas otras respuestas aquí, estoy +1 al tener un directorio src de nivel superior (con los directorios doc y test al lado). Las convenciones específicas para los árboles de directorios de documentación variarán dependiendo de lo que esté utilizando; Sphinx, por ejemplo, tiene sus propias convenciones que admite su herramienta de inicio rápido.

Por favor, aproveche setuptools y pkg_resources; esto hace que sea mucho más fácil para otros proyectos confiar en versiones específicas de su código (y para que se instalen varias versiones simultáneamente con diferentes archivos que no sean de código, si está utilizando package_data).

 7
Author: Charles Duffy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-10 22:39:22