J'ai un projet Python dans lequel j'utilise de nombreux fichiers non-code. Actuellement, ce sont toutes des images, mais je pourrais utiliser d'autres types de fichiers à l'avenir. Quel serait un bon schéma pour stocker et référencer ces fichiers?
J'ai envisagé de simplement créer un dossier "ressources" dans le répertoire principal, mais il y a un problème; Certaines images sont utilisées à partir de sous-packages de mon projet. Le stockage de ces images de cette manière entraînerait un couplage, ce qui est un inconvénient.
De plus, j'ai besoin d'un moyen d'accéder à ces fichiers qui est indépendant de mon répertoire actuel.
Vous souhaiterez peut-être utiliser la bibliothèque pkg_resources
Fournie avec setuptools
.
Par exemple, j'ai créé un petit package rapide "proj"
Pour illustrer le schéma d'organisation des ressources que j'utiliserais:
proj/setup.py proj/proj/__ init __. py proj/proj/code.py proj/proj/resources/__ init __. py proj/proj/resources/images/__ init __. py proj/proj/resources/images/pic1.png proj/proj/resources/images/pic2.png
Remarquez comment je conserve toutes les ressources dans un sous-package séparé.
"code.py"
Montre comment pkg_resources
Est utilisé pour faire référence aux objets ressources:
from pkg_resources import resource_string, resource_listdir
# Itemize data files under proj/resources/images:
print resource_listdir('proj.resources.images', '')
# Get the data file bytes:
print resource_string('proj.resources.images', 'pic2.png').encode('base64')
Si vous l'exécutez, vous obtenez:
['__init__.py', '__init __. pyc', 'pic1.png', 'pic2.png'] iVBORw0KGgoAAAANSUhE ...
Si vous devez traiter une ressource comme un objet fichier, utilisez resource_stream()
.
Le code accédant aux ressources peut se trouver n'importe où dans la structure de sous-package de votre projet, il suffit de faire référence au sous-package contenant les images par leur nom complet: proj.resources.images
, Dans ce cas.
Voici "setup.py"
:
#!/usr/bin/env python
from setuptools import setup, find_packages
setup(name='proj',
packages=find_packages(),
package_data={'': ['*.png']})
Avertissement: Pour tester les choses "localement", c'est-à-dire sans installer le paquet en premier, vous devrez appeler vos scripts de test à partir du répertoire qui a setup.py
. Si vous êtes dans le même répertoire que code.py
, Python ne connaît pas le package proj
. Donc, des choses comme proj.resources
Ont gagné ' t résoudre.
Vous pouvez toujours avoir un dossier "ressources" distinct dans chaque sous-package qui en a besoin et utiliser os.path
fonctions pour y accéder à partir du __file__
valeurs de vos sous-packages. Pour illustrer ce que je veux dire, j'ai créé ce qui suit __init__.py
fichier à trois emplacements:
c:\temp\topp (package de niveau supérieur) c:\temp\topp\sub1 (sous-package 1) c:\temp\topp\sub2 (sous-package 2 )
Ici se trouve le __init__.py
fichier:
import os.path
resource_path = os.path.join(os.path.split(__file__)[0], "resources")
print resource_path
Dans c:\temp\work, je crée une application, topapp.py, comme suit:
import topp
import topp.sub1
import topp.sub2
Cela représente l'application utilisant le package et les sous-packages topp
. Ensuite, je l'exécute:
C:\temp\work> topapp Traceback (dernier appel le plus récent): Fichier "C:\temp\work\topapp.py", ligne 1, dans import topp ImportError: Aucun module nommé topp
C'est comme prévu. Nous avons défini le PYTHONPATH pour simuler le fait d'avoir notre package sur le chemin:
C:\temp\work> set PYTHONPATH = c:\temp C:\temp\work> topapp C:\temp\topp\resources c:\temp\topp\sub1\resources c:\temp\topp\sub2\resources
Comme vous pouvez le voir, les chemins d'accès aux ressources se sont correctement résolus à l'emplacement des (sous-) packages réels sur le chemin d'accès.
Mise à jour: Ici est la documentation py2exe appropriée.
@ pycon2009, il y a eu une présentation sur les distutils et les setuptools. Vous pouvez trouver toutes les vidéos ici
Eggs and Buildout Deployment in Python - Part 1
Eggs et déploiement de buildout dans Python - Partie 2
Eggs and Buildout Deployment in Python - Part
Dans ces vidéos, ils décrivent comment inclure des ressources statiques dans votre package. Je crois que c'est dans la partie 2.
Avec setuptools, vous pouvez définir des dépendances, cela vous permettrait d'avoir 2 packages qui utilisent les ressources du 3ème package.
Setuptools vous donne également un moyen standard d'accéder à ces ressources et vous permet d'utiliser des chemins relatifs à l'intérieur de vos packages, ce qui vous évite de vous soucier de l'emplacement d'installation de vos packages.