¿Cómo incluir los datos del paquete con setuptools / distribution?

135

Cuando uso setuptools / distribution, no puedo hacer que el instalador extraiga ningún package_dataarchivo. Todo lo que he leído dice que la siguiente es la forma correcta de hacerlo. ¿Alguien puede aconsejarme?

setup(
   name='myapp',
   packages=find_packages(),
   package_data={
      'myapp': ['data/*.txt'],
   },
   include_package_data=True,
   zip_safe=False,
   install_requires=['distribute'],
)

donde myapp/data/es la ubicación de los archivos de datos.

cmcginty
fuente
2
Estoy teniendo el mismo problema ... Especificar manualmente data_filessolucionó el problema. Pero esto es propenso a errores y no me parece "correcto". ¿Alguien puede verificar que es realmente necesario duplicar la configuración en ambos package_datay data_files?
exhuma
github.com/wimglenn/resources-example Muestra una estructura de proyecto moderna de setuptools, que puede empaquetar correctamente archivos de datos en ruedas y sdists usando pyproject.toml. No se setup.pyrequiere archivo.
wim

Respuestas:

289

Me doy cuenta de que esta es una vieja pregunta, pero para las personas que encuentran su camino aquí a través de Google: package_dataes una mentira sucia . Solo se usa al construir paquetes binarios ( python setup.py bdist ...) pero no cuando se compilan paquetes fuente ( python setup.py sdist ...). Esto es, por supuesto, ridículo: uno esperaría que construir una distribución de origen resultaría en una colección de archivos que podrían enviarse a otra persona para construir la distribución binaria.

En cualquier caso, el uso MANIFEST.infuncionará tanto para binarios como para distribuciones de origen.

larsks
fuente
97
He estado investigando este problema durante la última hora y he estado probando muchos enfoques. Como dices, package_datafunciona para bdisty no sdist. Sin embargo , MANIFEST.infunciona para sdist, pero no para bdist! Por lo tanto, lo mejor que he podido encontrar es incluir ambos package_datay MANIFEST.inacomodar ambos bdisty sdist.
Wesley Baugh
77
Encontré otro para apoyar a @WesleyBaugh. En stackoverflow.com/a/2969087/261718 , Use MANIFEST.inpara archivos que no instalará, como documentación, y package_datapara archivos que use que no sean código Python (como una imagen o plantilla).
Drake Guan
12
Estoy usando sdist, y tuve que incluir ambos MANIFEST.in y package_data . Parece que MANIFEST.incontrola lo que se incluye en la distribución, y package_data controla lo que posteriormente se copia en el directorio site_packages durante la instalación. Confusamente, las rutas de acceso MANIFEST.inson relativas a la ubicación de setup.py, y package_dataes relativa a la raíz de los paquetes individuales (por ejemplo, módulos).
Edward Newell el
9
"Modificado en la versión 2.7: todos los archivos que coincidan con package_data se agregarán al archivo MANIFEST si no se proporciona una plantilla. Consulte Especificar los archivos para distribuir". de distutils . Por lo tanto, solo verá el comportamiento de los archivos al package_dataincluirse automáticamente en el ZIP si no tiene un archivo MANIFEST.in existente , y solo si está utilizando 2.7+.
Johnus
29
En serio, siento que este boleto es una sesión de terapia grupal para personas que usan herramientas de configuración y descubren qué horrible lugar se han encontrado en la vida.
Matt Joyce
32

Acabo de tener este mismo problema. La solución, era simplemente eliminar include_package_data=True.

Después de leer aquí , me di cuenta de que el include_package_dataobjetivo es incluir archivos del control de versiones , en lugar de simplemente "incluir datos del paquete" como su nombre lo indica. De los documentos:

Los archivos de datos [de include_package_data] deben estar bajo control CVS o Subversion

...

Si desea un control más detallado sobre qué archivos están incluidos (por ejemplo, si tiene archivos de documentación en los directorios de su paquete y desea excluirlos de la instalación), también puede usar la package_datapalabra clave.

Eliminar ese argumento lo solucionó, lo cual es coincidencia por qué también funcionó cuando cambiaste a distutils, ya que no toma ese argumento.

Joe
fuente
2
Mi experiencia es diferente, tuve el mismo problema sin incluir la include_package_data=Trueentrada. La única solución para mí es agregar una entrada en Manifiesto como se sugirió anteriormente. ¿Te importa que estaba usando setuptools, tal vez tu versión funciona con 'distribuir'?
TimStaley
44
La razón real por la que eliminar el include_package_dataproblema resuelve está más allá en el texto original : si usa el include_package_dataargumento específico de setuptools , los archivos especificados por package_datano se agregarán automáticamente al manifiesto a menos que estén listados en el MANIFEST.inarchivo.
Piotr Dobrogost
¿Cuál es el caso de uso de haber package_dataestablecido una lista no vacía y especificar include_package_data=False? ¿Y por qué necesitarías especificar archivos dos veces MANIFEST.iny package_data?
Herbert
21

Seguir las recomendaciones de @Joe para eliminar la include_package_data=Truelínea también funcionó para mí.

Para elaborar un poco más, no tengo ningún MANIFEST.in archivo. Yo uso Git y no CVS.

El repositorio toma este tipo de forma:

/myrepo
    - .git/
    - setup.py
    - myproject
        - __init__.py
        - some_mod
            - __init__.py
            - animals.py
            - rocks.py
        - config
            - __init__.py
            - settings.py
            - other_settings.special
            - cool.huh
            - other_settings.xml
        - words
            - __init__.py
            word_set.txt

setup.py:

from setuptools import setup, find_packages
import os.path

setup (
    name='myproject',
    version = "4.19",
    packages = find_packages(),  
    # package_dir={'mypkg': 'src/mypkg'},  # didnt use this.
    package_data = {
        # If any package contains *.txt or *.rst files, include them:
        '': ['*.txt', '*.xml', '*.special', '*.huh'],
    },

#
    # Oddly enough, include_package_data=True prevented package_data from working.
    # include_package_data=True, # Commented out.
    data_files=[
#               ('bitmaps', ['bm/b1.gif', 'bm/b2.gif']),
        ('/opt/local/myproject/etc', ['myproject/config/settings.py', 'myproject/config/other_settings.special']),
        ('/opt/local/myproject/etc', [os.path.join('myproject/config', 'cool.huh')]),
#
        ('/opt/local/myproject/etc', [os.path.join('myproject/config', 'other_settings.xml')]),
        ('/opt/local/myproject/data', [os.path.join('myproject/words', 'word_set.txt')]),
    ],

    install_requires=[ 'jsonschema',
        'logging', ],

     entry_points = {
        'console_scripts': [
            # Blah...
        ], },
)

Corro python setup.py sdistpor una fuente de distribución (no he probado binario).

Y cuando estoy dentro de un nuevo entorno virtual, tengo un myproject-4.19.tar.gzarchivo y uso

(venv) pip install ~/myproject-4.19.tar.gz
...

Y aparte de todo lo que se instala en mi entorno virtual site-packages, esos archivos de datos especiales se instalan en /opt/local/myproject/datay /opt/local/myproject/etc.

HeyWatchThis
fuente
16

include_package_data=True trabajó para mi.

Si usa git, recuerde incluirlo setuptools-giten install_requires. Mucho menos aburrido que tener una Manifestruta o incluirla package_data(en mi caso, es una aplicación django con todo tipo de estadísticas)

(pegué el comentario que hice, ya que k3-rnc mencionó que en realidad es útil como es)

vincent
fuente
7

Actualización : esta respuesta es antigua y la información ya no es válida. Todas las configuraciones de setup.py deben usar import setuptools. Agregué una respuesta más completa en https://stackoverflow.com/a/49501350/64313


Resolví esto cambiando a distutils. Parece que distribuir está obsoleto y / o roto.

from distutils.core import setup

setup(
   name='myapp',
   packages=['myapp'],
   package_data={
      'myapp': ['data/*.txt'],
   },
)
cmcginty
fuente
2
distribuir no está en desuso, está reemplazando distutils. No sé por qué estabas teniendo el problema, pero esa no es la razón.
agf
1
Esa fue la respuesta que recibí del IRC, entonces, ¿a quién le creo? Si tiene un ejemplo de trabajo con distribución, se lo agradecería.
cmcginty
66
aclaración: distribuir está destinado a reemplazar las herramientas de configuración, ambas están construidas sobre distutils. distutils eventualmente será reemplazado por un nuevo paquete, llamado "distutils2" en python2 y "packaging" en python3
Kevin Horn
1
Cambiar a distutils resolvió mi problema donde include_package_data=Trueno se estaba cumpliendo . Entonces, con esa configuración, solo necesita MANIFEST.in, no es necesario duplicar su lista de archivos en la package_dataconfiguración.
Daniel Sokolowski
4

Antigua pregunta y sin embargo ... la gestión de paquetes de python realmente deja mucho que desear. Así que tuve el caso de uso de instalar pip localmente en un directorio específico y me sorprendió que las rutas package_data y data_files no funcionaran. No estaba interesado en agregar otro archivo al repositorio, así que terminé aprovechando data_files y la opción setup.py --install-data; algo como esto

pip install . --install-option="--install-data=$PWD/package" -t package  
Mat Baker
fuente
3

Tuve el mismo problema durante un par de días, pero incluso este hilo no pudo ayudarme, ya que todo era confuso. Así que hice mi investigación y encontré la siguiente solución:

Básicamente en este caso, debes hacer:

from setuptools import setup

setup(
   name='myapp',
   packages=['myapp'],
   package_dir={'myapp':'myapp'}, # the one line where all the magic happens
   package_data={
      'myapp': ['data/*.txt'],
   },
)

La otra respuesta completa de stackoverflow aquí

moctarjallo
fuente
Intenté esto, pero todavía no se copia nada.
Gerrit
3

Simplemente elimine la línea:

include_package_data=True,

desde su script de configuración, y funcionará bien. (Probado ahora con las últimas herramientas de configuración).

Ian
fuente
Es una locura, pero funciona tanto con sdisty bdist_wheel, ¿has comprobado por qué?
Szabolcs
1
De hecho, puedo confirmar que sdistignora package_datacuando esto se establece.
Sander Steffann
En este punto han pasado meses, pero me parece recordar haber cavado en el código, perderme dos veces, llevar un peine EXTREMADAMENTE de dientes finos a la documentación y obtener satisfacción. Aparentemente, varios scripts de muestra contienen esta bandera y no causa fin de dolores de cabeza.
Ian
1

Usando setup.cfg (setuptools ≥ 30.3.0)

A partir de setuptools 30.3.0 (publicado el 12/12/2016), puede mantener su setup.pymuy pequeño y mover la configuración a un setup.cfgarchivo. Con este enfoque, puede poner los datos de su paquete en una [options.package_data]sección:

[options.package_data]
* = *.txt, *.rst
hello = *.msg

En este caso, setup.pypuede ser tan corto como:

from setuptools import setup
setup()

Para obtener más información, consulte la configuración de la instalación utilizando los archivos setup.cfg .

Se habla de menospreciarsetup.cfg a favor de pyproject.tomllo propuesto en PEP 518 , pero esto todavía es provisional a partir de 2020-02-21.

gerrit
fuente
Esta respuesta no menciona el archivo MANIFEST, por lo que creo que en realidad no funcionará con sdists. Solo con ruedas. Deberías mencionar eso.
wim
@wim No entiendo lo suficiente de MANIFEST, sdist y wheels para responder eso. Esto funcionó para mí usando pip install.
Gerrit
Esto se debe a que pip install, para una versión suficientemente moderna de pip, primero construirá una rueda y luego la instalará. Sin embargo, para muchos usuarios, este enfoque no incluirá silenciosamente los datos del paquete. Consulte la respuesta aceptada y los comentarios debajo para obtener detalles al respecto. Usando unsetup.cfg es realmente una forma diferente de escribir lo que el OP ya estaba haciendo en setup.pyla pregunta (pasando el package_dataargumento de la palabra clave en la llamada a setup), por lo que no creo que esto sea particularmente útil como respuesta a esta pregunta . No se trata el problema subyacente en absoluto.
wim