Como incluir dados do pacote com setuptools / distribut?

135

Ao usar setuptools / distribut, não consigo fazer com que o instalador puxe nenhum package_dataarquivo. Tudo o que li diz que o seguinte é a maneira correta de fazer isso. Alguém pode aconselhar?

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

onde myapp/data/é o local dos arquivos de dados.

cmcginty
fonte
2
Estou tendo o mesmo problema ... A especificação manual data_filesresolveu o problema. Mas isso é propenso a erros e não "parece certo" para mim. Alguém pode verificar se é realmente necessário duplicar a configuração em ambos package_datae data_files?
Exhuma
github.com/wimglenn/resources-example Mostra uma estrutura moderna do projeto setuptools, que pode empacotar corretamente os arquivos de dados em rodas e sdists usando pyproject.toml. Nenhum setup.pyarquivo é necessário.
wim

Respostas:

289

Percebo que essa é uma pergunta antiga, mas para as pessoas que estão chegando aqui pelo Google: package_dataé uma mentira humilde e suja . É usado apenas ao criar pacotes binários ( python setup.py bdist ...), mas não ao criar pacotes de origem ( python setup.py sdist ...). Isso é, obviamente, ridículo - seria de esperar que a construção de uma distribuição de origem resultasse em uma coleção de arquivos que poderiam ser enviados a outra pessoa para construir a distribuição binária.

De qualquer forma, o uso MANIFEST.infuncionará tanto para distribuições binárias quanto para fontes.

larsks
fonte
97
Pesquisei esse problema há uma hora e tentei várias abordagens. Como você diz, package_datatrabalha para bdiste não sdist. No entanto , MANIFEST.infunciona para sdist, mas não para bdist! Portanto, o melhor que pude sugerir é incluir ambos package_datae MANIFEST.inpara acomodar ambos bdiste sdist.
Wesley Baugh #
7
Encontrei outro para apoiar @WesleyBaugh. Em stackoverflow.com/a/2969087/261718 , use MANIFEST.inpara arquivos que você não instala, como documentação e package_datapara arquivos que não são código Python (como uma imagem ou modelo).
precisa
12
Eu estou usando sdist, e tinha que incluir ambos MANIFEST.in e package_data . Parece que MANIFEST.incontrola o que está incluído na distribuição e package_data controla o que posteriormente é copiado no diretório site_packages durante a instalação. De maneira confusa, os caminhos em MANIFEST.insão relativos à localização do setup.py e package_dataà raiz dos pacotes individuais (por exemplo, módulos).
Edward Newell
9
"Alterado na versão 2.7: todos os arquivos que correspondem aos dados_pacote serão adicionados ao arquivo MANIFEST se nenhum modelo for fornecido. Consulte Especificando os arquivos a serem distribuídos." de distutils . Portanto, você só verá o comportamento dos arquivos package_datasendo incluídos automaticamente no ZIP se você não tiver o arquivo MANIFEST.in existente e somente se estiver usando o 2.7+.
Johnus 19/10/16
29
Sério, eu sinto que esse ingresso é uma sessão de terapia de grupo para as pessoas que usam ferramentas de configuração e descobrem o lugar horrível em que se encontraram na vida.
Matt Joyce
32

Eu apenas tive esse mesmo problema. A solução foi simplesmente remover include_package_data=True.

Depois de ler aqui , percebi que o include_package_dataobjetivo é incluir arquivos do controle de versão , em vez de apenas "incluir dados do pacote", como o nome indica. Dos documentos:

Os arquivos de dados [de include_package_data] devem estar sob o controle CVS ou Subversion

...

Se você deseja um controle mais refinado sobre quais arquivos estão incluídos (por exemplo, se você possui arquivos de documentação nos diretórios de pacotes e deseja excluí-los da instalação), também pode usar a package_datapalavra - chave.

Retirar esse argumento, corrigi-lo, o que é coincidentemente o motivo pelo qual ele também funcionou quando você mudou para o distutils, já que ele não aceita esse argumento.

Joe
fonte
2
Minha experiência é diferente, tive o mesmo problema sem incluir a include_package_data=Trueentrada. A única solução para mim é adicionar uma entrada no manifesto, como sugerido acima. Você mente que eu estava usando setuptools, talvez sua versão funcione com 'distribuir'?
precisa saber é o seguinte
4
O motivo real pelo qual a remoção include_package_dataresolve o problema é mais aprofundado no texto original - Se você usar o include_package_dataargumento específico do setuptools , os arquivos especificados por package_datanão serão automaticamente adicionados ao manifesto, a menos que estejam listados no MANIFEST.inarquivo.
Piotr Dobrogost 04/04
Qual é o caso de uso de ter package_datadefinido para uma lista não-vazia e especificado include_package_data=False? E por que você precisaria especificar arquivos duas vezes MANIFEST.ine package_data?
Herbert
21

Seguir a recomendação de @Joe para remover a include_package_data=Truelinha também funcionou para mim.

Para elaborar um pouco mais, não tenho nenhum MANIFEST.in arquivo. Eu uso o Git e não o CVS.

O repositório assume esse 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...
        ], },
)

Eu corro python setup.py sdistpara um distrib de origem (não tentei binário).

E quando dentro de um novo ambiente virtual, tenho um myproject-4.19.tar.gzarquivo e uso

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

E além de tudo que está sendo instalado no meu ambiente virtual site-packages, esses arquivos de dados especiais são instalados no /opt/local/myproject/datae /opt/local/myproject/etc.

HeyWatchThis
fonte
16

include_package_data=True trabalhou para mim.

Se você usar git, lembre-se de incluir setuptools-gitno install_requires. Muito menos chato do que ter um Manifestou incluir todo o caminho package_data(no meu caso, é um aplicativo django com todo tipo de estática)

(colei o comentário que fiz, como o k3-rnc mencionou, é realmente útil como está)

vincent
fonte
7

Atualização : esta resposta é antiga e as informações não são mais válidas. Todas as configurações do setup.py devem ser usadas import setuptools. Adicionei uma resposta mais completa em https://stackoverflow.com/a/49501350/64313


Eu resolvi isso mudando para distutils. Parece que a distribuição está obsoleta e / ou quebrada.

from distutils.core import setup

setup(
   name='myapp',
   packages=['myapp'],
   package_data={
      'myapp': ['data/*.txt'],
   },
)
cmcginty
fonte
2
distribuir não está obsoleto, está substituindo distutils. Não sei por que você estava tendo o problema, mas não é esse o motivo.
agf
1
Essa foi a resposta que recebi do IRC, então em quem eu acredito? Se você tem um exemplo de trabalho usando distribuir, eu agradeceria então.
cmcginty
6
esclarecimento: a distribuição destina-se a substituir as ferramentas de instalação, ambas são construídas em cima de distutils. distutils si acabará por ser substituído por um novo pacote, chamado de "distutils2" em python2 e "embalagem" em python3
Kevin Chifre
1
Mudar para distutils resolveu meu problema onde include_package_data=Truenão estava sendo respeitado. Portanto, com essa configuração, você só precisa do MANIFEST.in - não é necessário duplicar sua lista de arquivos na package_dataconfiguração.
21712 Daniel Sokolowski
4

Pergunta antiga e ainda ... o gerenciamento de pacotes do python realmente deixa muito a desejar. Portanto, tive o caso de uso de instalar o pip localmente em um diretório especificado e fiquei surpreso que os caminhos package_data e data_files não funcionassem. Como não estava interessado em adicionar outro arquivo ao repositório, acabei aproveitando os arquivos data_files e setup.py --install-data; algo assim

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

Eu tive o mesmo problema por alguns dias, mas mesmo esse segmento não foi capaz de me ajudar, pois tudo estava confuso. Então, eu fiz minha pesquisa e encontrei a seguinte solução:

Basicamente, neste caso, você deve fazer:

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'],
   },
)

A outra resposta completa do stackoverflow aqui

moctarjallo
fonte
Tentei isso, mas ainda nada é copiado.
gerrit 17/03
3

Basta remover a linha:

include_package_data=True,

do seu script de instalação e funcionará bem. (Testado agora com as ferramentas de instalação mais recentes.)

Ian
fonte
É uma loucura, mas funciona com sdiste bdist_wheel, você já verificou por quê?
Szabolcs
1
Posso confirmar que sdistignora package_dataquando isso está definido.
Sander Steffann
Neste ponto, já faz meses, mas eu me lembro de ter pesquisado o código, me perdido duas vezes, levado um pente de dentes extremamente finos para a documentação e obtendo satisfação. Aparentemente, vários scripts de amostra contêm esse sinalizador e não causa dores de cabeça.
Ian
1

Usando o setup.cfg (setuptools ≥ 30.3.0)

A partir do setuptools 30.3.0 (lançado em 12/12/2016), você pode manter o setup.pytamanho muito pequeno e mover a configuração para um setup.cfgarquivo. Com essa abordagem, você pode colocar os dados do pacote em uma [options.package_data]seção:

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

Nesse caso, você setup.pypode ser tão curto quanto:

from setuptools import setup
setup()

Para obter mais informações, consulte a configuração usando os arquivos setup.cfg .

alguma conversa de depreciativosetup.cfg a favor de pyproject.tomlcomo proposto na PEP 518 , mas isso ainda é provisória a partir de 2020/02/21.

gerrit
fonte
Esta resposta não menciona o arquivo MANIFEST, então acho que não funcionará realmente com sdists. Somente com rodas. Você deveria mencionar isso.
wim 9/04
@ wim Não tenho compreensão suficiente de MANIFEST, sdist e rodas para responder a isso. Isso funcionou para mim usando pip install.
gerrit 10/04
Isso ocorre porque pip install, para versões bastante modernas do pip, primeiro constrói uma roda e depois a instala. Ainda para muitos usuários, essa abordagem silenciosamente falha ao incluir dados do pacote. Veja a resposta aceita e os comentários abaixo para obter detalhes sobre isso. Usar a setup.cfgé realmente apenas uma maneira diferente de escrever o que o OP já estava fazendo na setup.pypergunta (passando o package_dataargumento da palavra - chave na chamada para setup), então não acho que isso seja particularmente útil como resposta para essa pergunta . Não está resolvendo o problema subjacente.
wim 10/04