Comment ajouter des données de package récursivement en Python setup.py?

J'ai une nouvelle bibliothèque qui doit inclure beaucoup de sous-dossiers de petits fichiers de données, et j'essaie de les ajouter en tant que données de paquet. Imaginez que j'ai ma bibliothèque comme ceci:

 library
    - foo.py
    - bar.py
 data
   subfolderA
      subfolderA1
      subfolderA2
   subfolderB
      subfolderB1 
      ...

Je veux ajouter toutes les données dans tous les sous-dossiers à travers setup.py, mais il semble que je doive manuellement aller dans chaque sous-dossier (il y en a 100 ou plus) et Ajouter un fichierinit .PY. En outre, setup.py trouvez ces fichiers récursivement, ou dois-je ajouter manuellement tous ces fichiers dans setup.py comme:

package_data={
  'mypackage.data.folderA': ['*'],
  'mypackage.data.folderA.subfolderA1': ['*'],
  'mypackage.data.folderA.subfolderA2': ['*']
   },

Je peux le faire avec un script, mais cela semble être une super douleur. Comment puis-je y parvenir en setup.py?

PS, la hiérarchie de ces dossiers est importante car il s'agit d'une base de données de fichiers matériels et nous voulons que l'arborescence des fichiers soit préservée lorsque nous les présentons dans une interface graphique à l'utilisateur, il serait donc à notre avantage de garder cette structure de fichiers intacte.

28
demandé sur DWynne 2014-12-27 07:58:35

4 réponses

  1. Utiliser Setuptools au lieu de distutils.
  2. Utilisez les fichiers de données au lieu des données de package. Ceux - ci ne nécessitent pas __init__.py.
  3. Générez les listes de fichiers et de répertoires en utilisant du code Python standard, au lieu de l'écrire littéralement:

    data_files = []
    directories = glob.glob('data/subfolder?/subfolder??/')
    for directory in directories:
        files = glob.glob(directory+'*')
        data_files.append((directory, files))
    # then pass data_files to setup()
    
20
répondu Kevin 2014-12-27 06:04:33

Le problème avec la réponse glob est qu'elle ne fait que beaucoup. I. e. il n'est pas totalement récursive. Le problème avec la réponse copy_tree est que les fichiers copiés seront laissés sur une désinstallation.

La solution appropriée est une solution récursive qui vous permettra de définir le paramètre package_data dans l'appel d'installation.

J'ai écrit cette petite méthode pour faire ceci:

import os

def package_files(directory):
    paths = []
    for (path, directories, filenames) in os.walk(directory):
        for filename in filenames:
            paths.append(os.path.join('..', path, filename))
    return paths

extra_files = package_files('path_to/extra_files_dir')

setup(
    ...
    packages = ['package_name'],
    package_data={'': extra_files},
    ....
)

Vous remarquerez que lorsque vous faites un pip uninstall package_name, que vous verrez vos fichiers listés (suivi effectué avec paquet).

26
répondu Sandy Chapman 2016-06-03 11:33:48

Si vous n'avez aucun problème avec l'obtention de votre setup.py code sale utiliser distutils.dir_util.copy_tree.
Tout le problème est de savoir comment en exclure les fichiers.
Voici un peu le code:

import os.path
from distutils import dir_util
from distutils import sysconfig
from distutils.core import setup

__packagename__ = 'x' 
setup(
    name = __packagename__,
    packages = [__packagename__],
)

destination_path = sysconfig.get_python_lib()
package_path = os.path.join(destination_path, __packagename__)

dir_util.copy_tree(__packagename__, package_path, update=1, preserve_mode=0)

Quelques Notes:

  • ce code copie récursivement le code source dans le chemin de destination.
  • Vous pouvez utiliser le même setup(...) mais l'utilisation de copy_tree() pour étendre le répertoire que vous voulez dans le chemin d'installation.
  • Les chemins par défaut de l'installation de distutil se trouvent dans API .
  • plus d'informations sur le module copy_tree () de distutils peuvent être trouvées ici .
  • 3
    répondu Heartagramir 2016-02-09 11:11:38

    Je peux suggérer un peu de code pour ajouter data_files dans setup ():

    data_files = []
    
    start_point = os.path.join(__pkgname__, 'static')
    for root, dirs, files in os.walk(start_point):
        root_files = [os.path.join(root, i) for i in files]
        data_files.append((root, root_files))
    
    start_point = os.path.join(__pkgname__, 'templates')
    for root, dirs, files in os.walk(start_point):
        root_files = [os.path.join(root, i) for i in files]
        data_files.append((root, root_files))
    
    setup(
        name = __pkgname__,
        description = __description__,
        version = __version__,
        long_description = README,
        ...
        data_files = data_files,
    )
    
    1
    répondu Stan 2017-07-19 15:40:31