MANIFEST.in ignorado em “python setup.py install” - nenhum arquivo de dados instalado?

89

Este é o meu script setup.py simplificado com coisas que não são de código removidas:

#!/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'],
)

MANIFEST.in:

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

Quando executo "python setup.py install sdist", recebo um bom .tar.gz com uma pasta raiz "whyteboard-0.41", com meu locale / images / e whyteboard-help / pastas dentro. Isso também contém meu script whyteboard.py que inicia meu programa de dentro do pacote fonte whyteboard.

Então:

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

Isso reflete a fonte do meu programa, é como tudo deveria ser e está correto.

No entanto, quando executo "python setup.py install", nenhum dos meus arquivos de dados é gravado - apenas o pacote fonte "whyteboard", e whyteboard.py é colocado em /usr/local/lib/python2.6/dist-packages/ .

Idealmente, eu gostaria que a mesma estrutura de diretório que foi gerada no arquivo .tar.gz fosse criada em dist-packages, pois é assim que meu programa espera procurar seus recursos.

Como posso obter "instalar" para criar essa estrutura de diretório? Parece estar ignorando meu arquivo de manifesto, pelo que posso dizer.

Steven Sproat
fonte

Respostas:

30

Algumas observações além da resposta de Ned (que atinge o problema central):

O Distutils não instala pacotes e módulos Python dentro de um subdiretório por projeto site-packages(ou dist-packagesno Debian / Ubuntu): eles são instalados diretamente site-packages, como você viu. Portanto, o whyteboard-xxdiretório que contém em seu sdist não existirá na forma final instalada.

Uma implicação disso é que você deve ter cuidado ao nomear o seu data_filesde uma forma que esclareça a qual projeto eles pertencem, porque esses arquivos / diretórios são instalados diretamente no site-packagesdiretório global , não dentro de qualquer whyteboarddiretório contido .

Ou você pode criar seus dados package_datado whyteboardpacote (o que significa que ele precisa estar dentro desse pacote, ou seja, próximo a __init__.py), e então isso não será um problema.

Por último, não faz muito sentido ter um whyteboard.pymódulo py_modulese um whyteboard/__init__.pypacote packages. Os dois são mutuamente exclusivos e, se você tiver os dois, o whyteboard.pymódulo será ignorado pelas importações em favor do pacote de mesmo nome.

Se whyteboard.pyfor apenas um script e não se destina a ser importado, você deve usar a opção de scripts para ele e removê-lo py_modules.

Carl Meyer
fonte
1
Isso é lamentável. Não gosto da ideia de ter dados de pacote - para mim, faz mais sentido que esses recursos fiquem fora do diretório de origem. Também não gosto de ter nomes de diretórios prefixados com o nome do programa (embora já faça isso para os arquivos de ajuda). Hmm ..
Steven Sproat
67

MANIFEST.indiz ao Distutils quais arquivos incluir na distribuição de origem, mas não afeta diretamente quais arquivos são instalados. Para isso, você precisa incluir os arquivos apropriados no setup.pyarquivo, geralmente como dados de pacote ou como arquivos adicionais .

Ned Deily
fonte
Tentei adicionar uma lista de dados do pacote, mas nenhum dos arquivos especificados foi usado. Eu não tinha certeza se os locais dos arquivos foram instalados em relação à instalação geral do pacote. De qualquer forma, ele ainda não estava gravando meus arquivos na estrutura de diretório correta que eu esperava.
Steven Sproat
A documentação vinculada nesta resposta fornece todas as informações de que você precisa sobre onde data_files e package_data estão instalados. Se essas opções não estiverem funcionando para você, atualize sua pergunta com a sintaxe exata que tentou, os resultados e o que você esperava.
Carl Meyer
4
Isso funciona para mim: duplicar minhas entradas MANIFEST.in dentro dos data_packages de setup.py faz tudo funcionar. Obrigado Ned - há anos não consigo entender esse ponto. Espero que agora minhas experiências com distutils / setuptools / distrib façam mais sentido.
Jonathan Hartley
7
Esse design de poder incluir arquivos no pacote que não serão instalados faz sentido? Quando seria usado?
Roger Dahl
27

Não consegui descobrir por que meu MANIFEST.inarquivo estava sendo ignorado quando corri python setup.py install- include_package_data=Trueresolveu o problema. A package_dataopção não é realmente necessária.

Greg
fonte
boa pegadinha, por que include_package_data=Truenão é o valor padrão?
liang
8

Executando o python 2.6.1 no Mac OSX, não tive absolutamente nenhuma sorte, exceto usando o data_files parâmetro em setup.py. Tudo com MANIFEST.in simplesmente resultou na inclusão de arquivos no pacote dist, mas nunca na instalação. Eu verifiquei alguns outros pacotes e eles estavam realmente usando data_files para especificar arquivos adicionais.

Eu criei uma função curta para ajudar a enumerar todos os arquivos de uma árvore de diretório no

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

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

Agora posso apenas chamar isso dentro da minha chamada de configuração:

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

E tudo nessas árvores é instalado.

Scott Persinger
fonte
11
Isso é ótimo, mas onde ele é instalado? Para mim, ao usar "pip install", meus dados_files vão para a raiz do meu virtualenv (ou seja, um único diretório compartilhado por todos os pacotes do virtualenv.) Se usar "setup.py install", então meus data_files vão para "site- packages / <mypackage> .egg / ". Se os arquivos forem dados necessários em tempo de execução, em nenhum dos casos será trivial para meu código localizar esses arquivos e, claro, tenho que pesquisar os dois diretórios em tempo de execução. Se os arquivos forem meu arquivo de LICENÇA, então em nenhum dos casos é trivial para meus usuários obterem da minha fonte para a LICENÇA. Perplexo.
Jonathan Hartley
8

Você deve usar ferramentas de configuração:

#!/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'],
)

Na verdade, isso não está usando o arquivo MANIFEST para fazer o trabalho, mas inclui todos os arquivos necessários.

Juho Rutila
fonte
Isso funcionou para mim com ferramentas de configuração . Eu construo o pacote Debian e vejo meus arquivos glade listados no package_datadicionário aparecerem no lugar certo somente após eu adicionar include_package_data=Tru.
mlt
3

Exemplo de execução mínima publicado

Conclusão importante: só MANIFEST.infuncionou para mim, package_datanão funcionou.

Testado no Ubuntu 19.10, Python 3.7.5, wheel == 0.32.3, setuptools == 41.1.0, twine == 3.1.1.

Como os usuários finais usam o pacote 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

Saída esperada:

hello data

Como os mantenedores o publicam:

# 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

Os arquivos reais:

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-sample-package-with-data

#!/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'],
)

Bibliografia:

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