Wie kann ich Paketdaten in setuptools / Distribute aufnehmen?

134

Bei Verwendung von setuptools / Distribute kann ich das Installationsprogramm nicht dazu bringen, package_dataDateien abzurufen . Alles, was ich gelesen habe, besagt, dass das Folgende der richtige Weg ist, dies zu tun. Kann jemand bitte beraten?

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

Wo myapp/data/ist der Speicherort der Datendateien?

cmcginty
quelle
2
Ich habe das gleiche Problem ... Die manuelle Angabe hat data_filesdas Problem gelöst. Dies ist jedoch fehleranfällig und fühlt sich für mich nicht "richtig" an. Kann jemand überprüfen, ob es wirklich notwendig ist , die Konfiguration in beiden package_dataund zu duplizieren data_files?
Exhuma
github.com/wimglenn/resources-example Zeigt eine moderne setuptools-Projektstruktur, mit der Datendateien mithilfe von Rädern und SDISTEN korrekt verpackt werden können pyproject.toml. Keine setup.pyDatei erforderlich.
wim

Antworten:

288

Mir ist klar, dass dies eine alte Frage ist, aber für Leute, die sich über Google hierher zurechtfinden: Es package_dataist eine einfache , schmutzige Lüge . Es wird nur beim Erstellen von Binärpaketen ( python setup.py bdist ...) verwendet, nicht jedoch beim Erstellen von Quellpaketen ( python setup.py sdist ...). Dies ist natürlich lächerlich - man würde erwarten, dass das Erstellen einer Quelldistribution zu einer Sammlung von Dateien führen würde, die an eine andere Person gesendet werden könnten, um die Binärdistribution zu erstellen.

In jedem Fall MANIFEST.infunktioniert die Verwendung sowohl für Binär- als auch für Quellverteilungen.

Larsks
quelle
97
Ich habe dieses Problem in der letzten Stunde untersucht und viele Ansätze ausprobiert. Wie Sie sagen, package_datafunktioniert für bdistund nicht sdist. Allerdings , MANIFEST.inarbeitet für sdist, aber nicht für bdist! Aus diesem Grund haben die beste ich in der Lage gewesen , mit zu kommen ist sowohl aufzunehmen package_dataund MANIFEST.inum beide aufzunehmen bdistund sdist.
Wesley Baugh
7
Ich habe einen anderen gefunden, der @WesleyBaugh unterstützt. Verwenden Sie in stackoverflow.com/a/2969087/261718 die OptionMANIFEST.in für Dateien, die Sie nicht installieren möchten , z. B. Dokumentation, und package_datafür Dateien, die Sie verwenden und die keinen Python-Code enthalten (z. B. ein Bild oder eine Vorlage).
Drake Guan
12
Ich benutze sdist und musste sowohl MANIFEST.in als auch einschließen package_data. Es scheint, dass dies MANIFEST.insteuert, was in der Distribution enthalten ist, und package_data steuert, was anschließend während der Installation in das Verzeichnis site_packages kopiert wird. Verwirrenderweise MANIFEST.inbeziehen sich die Pfade in relativ zum Speicherort von setup.py und package_datarelativ zum Stammverzeichnis der einzelnen Pakete (z. B. Module).
Edward Newell
9
"In Version 2.7 geändert: Alle Dateien, die mit package_data übereinstimmen, werden der MANIFEST-Datei hinzugefügt, wenn keine Vorlage bereitgestellt wird. Siehe Angeben der zu verteilenden Dateien." von distutils . Daher wird das Verhalten von Dateien package_datanur dann automatisch in die ZIP- Datei aufgenommen , wenn keine MANIFEST.in-Datei vorhanden ist und wenn Sie 2.7+ verwenden.
Johnus
29
Im Ernst, ich denke, dieses Ticket ist eine Gruppentherapiesitzung für Leute, die Setuptools verwenden und herausfinden, was für ein schrecklicher Ort sie im Leben gefunden haben.
Matt Joyce
32

Ich hatte gerade das gleiche Problem. Die Lösung war einfach zu entfernen include_package_data=True.

Nachdem ich hier gelesen hatte , wurde mir klar, dass das include_package_dataZiel darin besteht, Dateien aus der Versionskontrolle einzuschließen , anstatt nur "Paketdaten einzuschließen", wie der Name schon sagt. Aus den Dokumenten:

Die Datendateien [von include_package_data] müssen unter CVS- oder Subversion-Kontrolle stehen

...

Wenn Sie eine genauere Kontrolle darüber wünschen, welche Dateien enthalten sind (z. B. wenn Sie Dokumentationsdateien in Ihren Paketverzeichnissen haben und diese von der Installation ausschließen möchten), können Sie auch das package_dataSchlüsselwort verwenden.

Das Herausnehmen dieses Arguments hat es behoben, weshalb es zufällig auch funktioniert hat, als Sie zu distutils gewechselt sind, da es dieses Argument nicht akzeptiert.

Joe
quelle
2
Meine Erfahrung ist unterschiedlich, ich hatte das gleiche Problem ohne den include_package_data=TrueEintrag einzuschließen. Die einzige Lösung für mich besteht darin, einen Eintrag in Manifest hinzuzufügen, wie oben vorgeschlagen. Wohlgemerkt, ich habe Setuptools verwendet. Vielleicht funktioniert Ihre Version mit 'Distribute'?
TimStaley
4
Die tatsächliche Grund , warum das Entfernen include_package_dataProblem löst , ist weiter im Originaltext - Wenn die Setuptools spezifische Verwendung include_package_dataArgumente angegebenen Dateien package_datanicht automatisch zu dem Manifest hinzugefügt werden , wenn sie in der aufgelisteten MANIFEST.inDatei.
Piotr Dobrogost
Was ist der Anwendungsfall, wenn package_dataeine nicht leere Liste festgelegt und angegeben wird include_package_data=False? Und warum sollten Sie Dateien in MANIFEST.inund zweimal angeben müssen package_data?
Herbert
21

Das Befolgen der Empfehlung von @Joe, die include_package_data=TrueLeitung zu entfernen , hat auch bei mir funktioniert.

Um etwas näher darauf einzugehen, habe ich keine MANIFEST.in Datei. Ich benutze Git und nicht CVS.

Das Repository nimmt folgende Form an:

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

Ich laufe python setup.py sdistfür eine Quelldistribution (habe keine Binärdatei ausprobiert).

Und wenn ich mich in einer brandneuen virtuellen Umgebung befinde, habe ich eine myproject-4.19.tar.gz, Datei und verwende sie

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

Und abgesehen davon, dass alles in meiner virtuellen Umgebung installiert wird site-packages, werden diese speziellen Datendateien in /opt/local/myproject/dataund installiert /opt/local/myproject/etc.

HeyWatchThis
quelle
16

include_package_data=True arbeitete für mich.

Wenn Sie git verwenden, denken Sie daran, setuptools-gitin aufzunehmen install_requires. Weit weniger langweilig als einen Manifestoder alle Pfade einzuschließen package_data(in meinem Fall ist es eine Django-App mit allen Arten von Statik)

(fügte den Kommentar ein, den ich gemacht habe, wie k3-rnc erwähnte, ist es tatsächlich hilfreich, wie es ist)

Vincent
quelle
7

Update : Diese Antwort ist alt und die Informationen sind nicht mehr gültig. Alle setup.py-Konfigurationen sollten verwenden import setuptools. Ich habe eine vollständigere Antwort unter https://stackoverflow.com/a/49501350/64313 hinzugefügt


Ich habe das gelöst, indem ich zu Distutils gewechselt bin. Es sieht so aus, als ob Distribute veraltet und / oder defekt ist.

from distutils.core import setup

setup(
   name='myapp',
   packages=['myapp'],
   package_data={
      'myapp': ['data/*.txt'],
   },
)
cmcginty
quelle
2
Distribute ist nicht veraltet, sondern ersetzt Distutils. Ich weiß nicht, warum Sie das Problem hatten, aber das ist nicht der Grund.
Agf
1
Das war die Antwort, die ich vom IRC erhalten habe. Wem glaube ich? Wenn Sie ein Arbeitsbeispiel mit Distribute haben, würde ich mich freuen.
cmcginty
6
Klarstellung: Distribute soll Setuptools ersetzen, beide sind auf Distutils aufgebaut. distutils selbst wird schließlich durch ein neues Paket ersetzt, das in python2 "distutils2" und in python3 "package" heißt
Kevin Horn
1
Der Wechsel zu distutils löste mein Problem, bei dem include_package_data=Truenicht geehrt wurde. Mit dieser Einstellung benötigen Sie also nur MANIFEST.in - Sie müssen Ihre Dateiliste in der package_dataEinstellung nicht duplizieren .
Daniel Sokolowski
4

Alte Frage und doch ... Paketverwaltung von Python lässt wirklich zu wünschen übrig. Ich hatte also den Anwendungsfall, Pip lokal in einem bestimmten Verzeichnis zu installieren, und war überrascht, dass sowohl die Pfade package_data als auch data_files nicht funktionierten. Ich war nicht daran interessiert, dem Repo noch eine weitere Datei hinzuzufügen, also nutzte ich schließlich die Option data_files und setup.py --install-data; etwas wie das

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

Ich hatte ein paar Tage lang das gleiche Problem, aber selbst dieser Thread konnte mir nicht helfen, da alles verwirrend war. Also habe ich meine Recherchen durchgeführt und die folgende Lösung gefunden:

Grundsätzlich sollten Sie in diesem Fall Folgendes tun:

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

Die vollständige Antwort auf den anderen Stackoverflow finden Sie hier

Moctarjallo
quelle
Versuchte dies, aber immer noch wird nichts kopiert.
Gerrit
2

Entfernen Sie einfach die Zeile:

include_package_data=True,

von Ihrem Setup-Skript, und es wird gut funktionieren. (Gerade jetzt mit den neuesten Setuptools getestet.)

Ian
quelle
Es ist verrückt, aber es funktioniert sowohl mit sdistals auch bdist_wheel, hast du überprüft warum?
Szabolcs
Ich kann in der Tat bestätigen, dass sdistignoriert, package_datawenn dies eingestellt ist.
Sander Steffann
Zu diesem Zeitpunkt sind Monate vergangen, aber ich erinnere mich, dass ich mich im Code umgesehen habe, zweimal verloren gegangen bin, einen EXTREM feinzahnigen Kamm in die Dokumentation aufgenommen habe und Zufriedenheit gewonnen habe. Anscheinend enthalten verschiedene Beispielskripte dieses Flag und es verursacht kein Ende der Kopfschmerzen.
Ian
1

Verwenden von setup.cfg (setuptools ≥ 30.3.0)

Ab setuptools 30.3.0 (veröffentlicht am 08.12.2016) können Sie Ihre setup.pysehr klein halten und die Konfiguration in eine setup.cfgDatei verschieben. Mit diesem Ansatz können Sie Ihre Paketdaten in einen [options.package_data]Abschnitt einfügen:

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

In diesem Fall kann Ihr setup.pyso kurz sein wie:

from setuptools import setup
setup()

Weitere Informationen finden Sie unter Konfigurieren des Setups mithilfe der Dateien setup.cfg .

Es ist die Rede von einer Abwertungsetup.cfg zugunsten der pyproject.tomlin PEP 518 vorgeschlagenen , aber diese ist ab dem 21.02.2020 noch vorläufig.

gerrit
quelle
In dieser Antwort wird die MANIFEST-Datei nicht erwähnt, daher denke ich, dass sie mit SDISTEN nicht funktioniert. Nur mit Rädern. Das solltest du erwähnen.
wim
@wim Ich habe nicht genug Verständnis für MANIFEST, SDIST und Räder, um darauf zu antworten. Das hat bei mir mit funktioniert pip install.
Gerrit
Das liegt daran pip install, dass für eine ausreichend moderne Version von Pip zuerst ein Rad gebaut und dann installiert wird. Für viele Benutzer wird dieser Ansatz jedoch stillschweigend keine Paketdaten enthalten. Einzelheiten dazu finden Sie in der akzeptierten Antwort und den Kommentaren darunter. Die Verwendung von a setup.cfgist wirklich nur eine andere Art zu schreiben, was das OP bereits setup.pyin der Frage getan hat (indem das package_dataSchlüsselwortargument im Aufruf an übergeben wurde setup), daher denke ich nicht, dass dies als Antwort auf diese Frage besonders hilfreich ist . Es geht überhaupt nicht um das zugrunde liegende Problem.
wim