MANIFEST.in ignorado en "python setup.py install" - ¿no hay archivos de datos instalados?

89

Aquí está mi script setup.py simplificado con cosas que no son de código eliminadas:

#!/usr/bin/env python

from distutils.core import setup
from whyteboard.misc import meta


setup(
    name = 'Whyteboard',
    version = meta.version,

    packages = ['whyteboard', 'whyteboard.gui', 'whyteboard.lib', 'whyteboard.lib.pubsub',
                'whyteboard.lib.pubsub.core', 'whyteboard.lib.pubsub.utils', 'whyteboard.misc'],

    py_modules = ['whyteboard'],
    scripts = ['whyteboard.py'],
)

MANIFIESTO en:

include *.txt
include whyteboard-help/*.*
recursive-include locale *.mo
recursive-include images *.png

Cuando ejecuto "python setup.py install sdist" obtengo un bonito .tar.gz con una carpeta raíz "whyteboard-0.41", con mis carpetas locale / images / y whyteboard-help / dentro. Esto también tiene mi script whyteboard.py que inicia mi programa desde dentro del paquete fuente de whyteboard.

Entonces:

whyteboard/
 ├── locale/
 ├── images
 ├── whyteboard-help/
 ├── whyteboard/
 │  ├── __init__.py
 │  └── other packages etc
 ├── whyteboard.py
 ├── README
 ├── setup.py
 └── CHANGELOG

Esto refleja la fuente de mi programa, así es como debería ser todo y es correcto.

Sin embargo, cuando ejecuto "python setup.py install", ninguno de mis archivos de datos está escrito, solo el paquete fuente "whyteboard" y el whyteboard.py se coloca en /usr/local/lib/python2.6/dist-packages/ .

Idealmente, me gustaría que se creara la misma estructura de directorios que la que se generó en el archivo .tar.gz en dist-packages, ya que así es como mi programa espera buscar sus recursos.

¿Cómo puedo "instalar" para crear esta estructura de directorio? Parece estar ignorando mi archivo de manifiesto, por lo que puedo decir.

Steven Sproat
fuente

Respuestas:

30

Algunas notas además de la respuesta de Ned (que aborda el problema central):

Distutils no instala paquetes y módulos de Python dentro de un subdirectorio por proyecto dentro site-packages(o dist-packagesen Debian / Ubuntu): se instalan directamente en site-packages, como ha visto. Por lo tanto, el whyteboard-xxdirectorio que lo contiene en su sdist no existirá en el formulario final instalado.

Una implicación de esto es que debe tener cuidado de nombrar su data_filesde una manera que aclare a qué proyecto pertenecen, porque esos archivos / directorios se instalan directamente en el site-packagesdirectorio global , no dentro de ningún whyteboarddirectorio que los contenga .

O, en su lugar, podría crear sus datos package_datadel whyteboardpaquete (lo que significa que debe vivir dentro de ese paquete, es decir, al lado __init__.py), y entonces esto no es un problema.

Por último, no tiene mucho sentido tener tanto un whyteboard.pymódulo py_modulescomo un whyteboard/__init__.pypaquete packages. Los dos son mutuamente excluyentes, y si tiene ambos, el whyteboard.pymódulo será ignorado por las importaciones a favor del paquete del mismo nombre.

Si whyteboard.pyes solo un script y no está destinado a ser importado, entonces debería usar la opción de scripts y eliminarlo py_modules.

Carl Meyer
fuente
1
Eso es lamentable. No me gusta la idea de tener datos de paquetes; para mí, tiene más sentido que esos recursos vivan fuera del directorio de origen. Tampoco me gusta tener nombres de directorio prefijados con el nombre del programa (aunque ya lo hago para los archivos de ayuda). Hmm ...
Steven Sproat
67

MANIFEST.inle dice a Distutils qué archivos incluir en la distribución de origen, pero no afecta directamente qué archivos están instalados. Para eso, debe incluir los archivos apropiados en el setup.pyarchivo, generalmente como datos de paquete o como archivos adicionales .

Ned Deily
fuente
Intenté agregar una lista de datos de paquetes, pero no se usó ninguno de los archivos que especifiqué. No estaba seguro de si las ubicaciones de los archivos se instalaron en relación con la instalación general del paquete. De todos modos, todavía no estaba escribiendo mis archivos en la estructura de directorio correcta que esperaba.
Steven Sproat
La documentación vinculada en esta respuesta le brinda toda la información que necesita sobre dónde están instalados data_files y package_data. Si estas opciones no le funcionan, actualice su pregunta con la sintaxis exacta que probó, los resultados y lo que esperaba.
Carl Meyer
4
Esto funciona para mí: duplicar mis entradas MANIFEST.in dentro de los paquetes de datos de setup.py hace que todo funcione. Gracias Ned, no he podido entender este punto durante años. Con suerte, ahora mis experiencias distutils / setuptools / distribuir tendrán más sentido.
Jonathan Hartley
7
¿Tiene sentido este diseño de poder incluir archivos en el paquete que no se instalarán? ¿Cuándo se usaría?
Roger Dahl
28

No pude averiguar por qué MANIFEST.inse ignoraba mi archivo cuando lo ejecuté python setup.py install; resulta que include_package_data=Trueresuelve el problema. La package_dataopción no es realmente necesaria.

Greg
fuente
buena captura, ¿por qué include_package_data=Trueno es el valor predeterminado?
liang
9

Deberías usar herramientas de configuración:

#!/usr/bin/env python

from setuptools import setup, find_packages
from whyteboard.misc import meta


setup(
  name = 'Whyteboard',
  version = meta.version,

  packages = find_packages(),
  include_package_data=True,

  py_modules = ['whyteboard'],
  scripts = ['whyteboard.py'],
)

En realidad, esto no usa el archivo MANIFEST para hacer el trabajo, pero incluye todos los archivos necesarios.

Juho Rutila
fuente
Esto funcionó para mí con setuptools . Construyo el paquete Debian y veo que mis archivos glade enumerados en el package_datadiccionario aparecen en el lugar correcto solo después de que los agregué include_package_data=Tru.
mlt
8

Ejecución de Python 2.6.1 en Mac OS X, no tenía absolutamente ninguna suerte, excepto mediante el uso de las data_files parámetro en setup.py. Todo con MANIFEST.in simplemente resultó en archivos incluidos en el paquete dist, pero nunca instalados. Revisé algunos otros paquetes y de hecho estaban usando data_files para especificar archivos adicionales.

Creé una función corta para ayudar a enumerar todos los archivos de un árbol de directorios en el

(target_dir, [lista de archivos]) formato que espera data_files:

def gen_data_files(*dirs):
    results = []

    for src_dir in dirs:
        for root,dirs,files in os.walk(src_dir):
            results.append((root, map(lambda f:root + "/" + f, files)))
    return results

Ahora puedo llamar a esto dentro de mi llamada de configuración:

setup(... data_files = gen_data_files("docs", "lib") ...

Y todo en esos árboles se instala.

Scott Persinger
fuente
11
Esto es genial, pero ¿dónde se instala? Para mí, cuando uso "pip install", mis data_files van a la raíz de mi virtualenv (es decir, un único directorio compartido por todos los paquetes de virtualenv). Si utilizo "setup.py install", entonces mis data_files van a "site- paquetes / <mipaquete> .egg / ". Si los archivos son datos necesarios en tiempo de ejecución, en ningún caso es trivial para mi código encontrar estos archivos y, por supuesto, tengo que buscar en ambos directorios en tiempo de ejecución. Si los archivos son mi archivo de LICENCIA, en ningún caso es trivial para mis usuarios obtener de mi fuente a la LICENCIA. Perplejo.
Jonathan Hartley
3

Ejemplo ejecutable mínimo publicado

Conclusión clave: solo MANIFEST.infuncionó para mí, package_datano lo hizo.

Probado en Ubuntu 19.10, Python 3.7.5, wheel == 0.32.3, setuptools == 41.1.0, twine == 3.1.1.

Cómo los usuarios finales usan el paquete de https://pypi.org/project/python-sample-package-with-data/ :

python3 -m pip install --user python-sample-package-with-data
python-sample-package-with-data

Rendimiento esperado:

hello data

Cómo lo publican los mantenedores:

# One time setup.
python3 -m pip install --user setuptools wheel twine

# Every time you want to publish.
python setup.py sdist bdist_wheel
twine upload dist/*
rm -rf build dist *.egg-info

Los archivos reales:

MANIFEST.in

# Or else pip install cannot find README.md on the setup.py under certain conditions.
include README.md

# This actually adds the data file.
include python_sample_package_with_data/mydata.txt

Python-muestra-paquete-con-datos

#!/usr/bin/env python3

import python_sample_package_with_data

print(python_sample_package_with_data.get_data(), end='')

python_sample_package_with_data / __ init__.py

try:
    import importlib.resources as importlib_resources
except ImportError:
    # In PY<3.7 fall-back to backported `importlib_resources`.
    import importlib_resources

def get_data():
    return importlib_resources.read_text(__name__, 'mydata.txt')

python_sample_package_with_data / mydata.txt

hello data

setup.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from setuptools import setup, find_packages

from os import path
this_directory = path.abspath(path.dirname(__file__))
with open(path.join(this_directory, 'README.md')) as f:
    long_description = f.read()

setup(
    name='python-sample-package-with-data',
    version='0.0.3',
    description='My short description',
    long_description=long_description,
    long_description_content_type='text/markdown',
    url='https://github.com/cirosantilli/python-sample-package-with-data',
    author='Ciro Santilli',
    author_email='[email protected]',
    packages=find_packages(),
    include_package_data=True,
    scripts=['python-sample-package-with-data'],
)

Bibliografía:

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente