MANIFEST.in zignorowany przy instalacji „python setup.py install” - nie zainstalowano żadnych plików danych?

89

Oto mój uproszczony skrypt setup.py z usuniętymi elementami niekodowymi:

#!/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 w:

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

Kiedy uruchamiam „python setup.py install sdist”, otrzymuję ładny plik .tar.gz z folderem głównym „whyteboard-0.41”, w którym znajdują się moje lokalizacje / images / i whyteboard-help / foldery. Zawiera również mój skrypt whyteboard.py, który uruchamia mój program z pakietu źródłowego whyteboard.

Więc:

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

To odzwierciedla źródło mojego programu, jest takie, jak powinno być i jest poprawne.

Jednak kiedy uruchamiam "python setup.py install", żaden z moich plików danych nie jest zapisywany - tylko pakiet źródłowy "whyteboard", a whyteboard.py jest umieszczany w /usr/local/lib/python2.6/dist-packages/ .

Idealnie, chciałbym mieć taką samą strukturę katalogów jak ta, która została wygenerowana w pliku .tar.gz, aby została utworzona w pakietach dist, ponieważ w ten sposób mój program oczekuje, że będzie szukał swoich zasobów.

Jak mogę „zainstalować”, aby utworzyć taką strukturę katalogów? O ile wiem, wydaje mi się, że ignoruje mój plik manifestu.

Steven Sproat
źródło

Odpowiedzi:

30

Kilka uwag oprócz odpowiedzi Neda (które dotyczą podstawowego problemu):

Distutils nie instaluje pakietów i modułów Pythona w podkatalogu na projekt w site-packages(lub dist-packagesw Debianie / Ubuntu): są one instalowane bezpośrednio site-packages, jak widzieliście. Więc whyteboard-xxkatalog zawierający w twoim sdist nie będzie istniał w ostatecznej zainstalowanej formie.

Jedną z konsekwencji tego jest to, że powinieneś uważać na nazwanie swojego data_filesw sposób, który wyjaśnia, do jakiego projektu należą, ponieważ te pliki / katalogi są instalowane bezpośrednio w site-packageskatalogu globalnym , a nie w żadnym zawierającym whyteboardkatalog.

Czy można zamiast wprowadzać dane package_dataz whyteboardpakietu (co oznacza, że musi żyją wewnątrz tego pakietu, czyli do następnego __init__.py), a to nie jest problem.

Wreszcie, nie ma większego sensu posiadanie zarówno whyteboard.pymodułu, jak py_modulesi whyteboard/__init__.pypakietu packages. Oba wykluczają się wzajemnie, a jeśli masz oba, whyteboard.pymoduł zostanie zignorowany podczas importu na rzecz pakietu o tej samej nazwie.

Jeśli whyteboard.pyjest to tylko skrypt i nie jest przeznaczony do zaimportowania, należy użyć do tego opcji skryptów i usunąć go z py_modules.

Carl Meyer
źródło
1
To niefortunne. Nie podoba mi się pomysł posiadania danych pakietu - wydaje mi się, że bardziej sensowne jest, aby te zasoby znajdowały się poza katalogiem źródłowym. Nie lubię też, gdy nazwy katalogów są poprzedzane nazwą programu (chociaż robię to już dla plików pomocy). Hmm ...
Steven Sproat
67

MANIFEST.ininformuje Distutils, jakie pliki należy dołączyć do dystrybucji źródłowej, ale nie wpływa bezpośrednio na to, które pliki są instalowane. W tym celu należy dołączyć odpowiednie pliki do setup.pypliku, zazwyczaj jako dane pakietu lub jako pliki dodatkowe .

Ned Deily
źródło
Próbowałem dodać listę danych pakietu, ale żaden z podanych przeze mnie plików nie był używany. Nie byłem pewien, czy lokalizacje plików zostały zainstalowane w stosunku do ogólnej instalacji pakietu. W każdym razie nadal nie zapisywał moich plików w odpowiedniej strukturze katalogów, jakiej się spodziewałem.
Steven Sproat
Dokumentacja, do której link znajduje się w tej odpowiedzi, zawiera wszystkie potrzebne informacje o tym, gdzie są zainstalowane pliki data_files i package_data. Jeśli te opcje nie działają w Twoim przypadku, zaktualizuj pytanie, podając dokładnie wypróbowaną składnię, wyniki i oczekiwane.
Carl Meyer
4
To działa dla mnie: powielanie moich wpisów MANIFEST w wewnątrz pakietów data_packages setup.py sprawia, że ​​wszystko działa. Dzięki Ned - od lat nie rozumiem tego punktu. Mam nadzieję, że teraz moje doświadczenia z distutils / setuptools / Distribution będą miały więcej sensu.
Jonathan Hartley,
7
Czy taki projekt możliwości dołączania do pakietu plików, które nie zostaną zainstalowane, ma sens? Kiedy będzie używany?
Roger Dahl
28

Nie mogłem dowiedzieć się, dlaczego mój MANIFEST.inplik jest ignorowany, kiedy uruchomiłem python setup.py install- okazuje się, że include_package_data=Truerozwiązuje problem. Ta package_dataopcja nie jest w rzeczywistości wymagana.

Greg
źródło
dobry połów, dlaczego include_package_data=Truenie ma wartości domyślnej?
liang
9

Powinieneś użyć setuptools:

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

W rzeczywistości nie jest to użycie pliku MANIFESTU do wykonania zadania, ale zawiera wszystkie potrzebne pliki.

Juho Rutila
źródło
To zadziałało dla mnie z setuptools . Buduję pakiet Debiana i widzę, że moje pliki glade wymienione w package_datasłowniku pojawiają się we właściwym miejscu dopiero po dodaniu include_package_data=Tru.
mlt
8

Uruchamiając Pythona 2.6.1 w systemie Mac OSX, nie miałem absolutnie żadnego szczęścia, z wyjątkiem użycia parametru data_files w setup.py. Wszystko z MANIFEST.in po prostu skutkowało dołączeniem plików do pakietu dist, ale nigdy ich nie instalował. Sprawdziłem kilka innych pakietów i rzeczywiście używali one data_files do określenia dodatkowych plików.

Stworzyłem krótką funkcję, która pomaga wyliczyć wszystkie pliki z drzewa katalogów w

(katalog_docelowy, [lista plików]) format oczekiwany przez 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

Teraz mogę po prostu zadzwonić do tego w mojej rozmowie konfiguracyjnej:

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

I wszystko w tych drzewach zostanie zainstalowane.

Scott Persinger
źródło
11
To jest świetne, ale gdzie jest instalowane? Dla mnie, kiedy używam "pip install", moje pliki_danych trafiają do katalogu głównego mojego virtualenv (tj. Pojedynczego katalogu współużytkowanego przez wszystkie pakiety virtualenv). Jeśli używam "setup.py install", wtedy moje pliki data_files trafiają do "site- packages / <mypackage> .egg / ”. Jeśli pliki są danymi potrzebnymi w czasie wykonywania, to w żadnym przypadku nie jest trywialne dla mojego kodu, aby znaleźć te pliki i oczywiście muszę przeszukiwać oba katalogi w czasie wykonywania. Jeśli pliki są moim plikiem LICENCJI, to w żadnym przypadku nie jest to trywialne, aby moi użytkownicy mogli dostać się z mojego źródła do LICENCJI. Zdziwiony.
Jonathan Hartley,
3

Minimalny opublikowany przykład do uruchomienia

Kluczowy MANIFEST.inwniosek : działał tylko dla mnie, package_datanie.

Testowano na Ubuntu 19.10, Python 3.7.5, wheel == 0.32.3, setuptools == 41.1.0, twine == 3.1.1.

Jak użytkownicy końcowi korzystają z pakietu z https://pypi.org/project/python-sample-package-with-data/ :

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

Oczekiwany wynik:

hello data

Jak opiekunowie to publikują:

# 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

Rzeczywiste pliki:

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 郝海东 冠状 病 六四 事件 法轮功
źródło