109 votes

setuptools: emplacement du dossier de données du paquet

J'utilise setuptools pour distribuer mon paquet python. Maintenant, j'ai besoin de distribuer des fichiers de données supplémentaires.

De ce que j'ai recueillies fromt la setuptools de la documentation, j'ai besoin d'avoir mes fichiers de données à l'intérieur du répertoire du package. Cependant, je préfère avoir mes fichiers de données à l'intérieur d'un sous-répertoire dans le répertoire racine.

Ce que je voudrais éviter:

/ #root
|- src/
|  |- mypackage/
|  |  |- data/
|  |  |  |- resource1
|  |  |  |- [...]
|  |  |- __init__.py
|  |  |- [...]
|- setup.py

Ce que j'aimerais avoir:

/ #root
|- data/
|  |- resource1
|  |- [...]
|- src/
|  |- mypackage/
|  |  |- __init__.py
|  |  |- [...]
|- setup.py

Je ne me sens pas à l'aise avec le fait d'avoir autant de sous-répertoires, si ce n'est pas essentiel. Je n'arrive pas à trouver une raison, pourquoi je /avoir/ pour mettre les fichiers dans le répertoire du package. Il est également lourd de travailler avec autant de imbriquée des sous-répertoires à mon humble avis. Ou est-il une bonne raison pour justifier cette restriction?

124voto

samplebias Points 19805

Option 1: Installation du paquet de données

Le principal avantage de placer les fichiers de données à l'intérieur de la racine de votre paquet Python c'est qu'il vous permet de ne pas se soucier de l'endroit où les fichiers en direct sur un utilisateur le système, qui peut être Windows, Mac, Linux, certaines plate-forme mobile, ou à l'intérieur d'un Oeuf. Vous pouvez toujours trouver le répertoire data par rapport à votre paquet Python racine, n'importe où ou comment il est installé.

Par exemple, si j'ai un projet de mise en page comme ceci:

project/
    foo/
        __init__.py
        data/
            resource1/
                foo.txt

Vous pouvez ajouter une fonction à l' __init__.py pour localiser le chemin absolu de données fichier:

import os

_ROOT = os.path.abspath(os.path.dirname(__file__))
def get_data(path):
    return os.path.join(_ROOT, 'data', path)

print get_data('resource1/foo.txt')

Sorties:

/Users/pat/project/foo/data/resource1/foo.txt

Après le projet est installé comme un Œuf le chemin de data va changer, mais le code n'a pas besoin de changer:

/Users/pat/virtenv/foo/lib/python2.6/site-packages/foo-0.0.0-py2.6.egg/foo/data/resource1/foo.txt

Option 2: Installation à emplacement fixe

L'alternative serait de placer vos données à l'extérieur du paquet Python et puis soit:

  1. L'emplacement de data transmis via un fichier de configuration, arguments de ligne de commande ou
  2. Incorporer l'emplacement dans votre code Python.

C'est beaucoup moins souhaitable si vous envisagez de distribuer votre projet. Si vous vraiment voulez faire cela, vous pouvez installer votre data où vous le souhaitez sur le système cible par la spécification de la destination pour chaque groupe de fichiers en passant par une liste de tuples:

from setuptools import setup
setup(
    ...
    data_files=[
        ('/var/data1', ['data/foo.txt']),
        ('/var/data2', ['data/bar.txt'])
        ]
    )

Mise à jour: Exemple d'une coquille en fonction récursive grep fichiers Python:

atlas% function grep_py { find . -name '*.py' -exec grep -Hn $* {} \; }
atlas% grep_py ": \["
./setup.py:9:    package_data={'foo': ['data/resource1/foo.txt']}

21voto

polvoazul Points 104

Je Crois que j'ai trouvé un bon compromis qui vous permettra de mantain la structure suivante:

/ #root
|- data/
|  |- resource1
|  |- [...]
|- src/
|  |- mypackage/
|  |  |- __init__.py
|  |  |- [...]
|- setup.py

Vous devez installer les données package_data, pour éviter les problèmes décrits dans samplebias réponse, mais pour mantain la structure du fichier, vous devez l'ajouter à votre setup.py:

try:
    os.symlink('../../data', 'src/mypackage/data'
    setup(
        ...
        package_data = {'mypackage': ['data/*']}
        ...
    )
finally:
    os.unlink('src/mypackage/data')

De cette façon, nous créons la structure appropriée "juste à temps", et mantain notre arborescence des sources organisé.

Pour accéder à ces fichiers de données au sein de votre code, vous 'simplement' utilisation:

data = resource_filename(Requirement.parse("main_package"), 'mypackage/data')

Je ne l'aime toujours pas avoir à spécifier 'mypackage" dans le code, comme les données pourraient n'avoir rien à faire necessarally avec ce module, mais je suppose que c'est un bon compromis.

1voto

dietbuddha Points 4031

J'utilise setuptools pour créer des packages de système d'exploitation natifs tels que les RPM et les DEB. La mise en page du projet que j'utilise est.

 <project>/
        lib/      -> .../lib/pythonX/site-packages/
        bin/      -> .../bin/
        etc/      -> /etc/
        doc/
           man/   -> .../man/man1/
           share/ -> .../share/doc/<project>/
 

Mon fichier setup.py effectue le mappage approprié comme spécifié ci-dessus. Je trouve cette mise en page idéale pour le python. Les paquets produits sont déplaçables, mais par défaut, ils passeront sous /usr/local/ .

-4voto

lgautier Points 4164

Je pense que vous pouvez en principe donner n'importe quoi comme argument * data_files * à setup () .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X