MANIFEST.in bị bỏ qua trên “python setup.py install” - không có tệp dữ liệu nào được cài đặt?


89

Đây là tập lệnh setup.py đã rút xuống của tôi với nội dung không phải mã đã bị xóa:

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

Khi tôi chạy "python setup.py install sdist", tôi nhận được .tar.gz đẹp với thư mục gốc "whyteboard-0.41", với các thư mục locale / images / và whyteboard-help / của tôi bên trong. Điều này cũng có tập lệnh whyteboard.py của tôi khởi chạy chương trình của tôi từ bên trong gói nguồn whyteboard.

Vì thế:

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

Điều này phản ánh nguồn gốc của chương trình của tôi, mọi thứ nên như thế nào và là chính xác.

Tuy nhiên, khi tôi chạy "python setup.py install" thì không có tệp dữ liệu nào của tôi được ghi - chỉ có gói nguồn "whyteboard" và whyteboard.py được đặt trong /usr/local/lib/python2.6/dist-packages/ .

Lý tưởng nhất, tôi muốn cấu trúc thư mục giống như những gì được tạo trong tệp .tar.gz được tạo trong các gói phân phối, vì đây là cách chương trình của tôi mong đợi tìm kiếm tài nguyên của nó.

Làm cách nào tôi có thể lấy "cài đặt" để tạo cấu trúc thư mục này? Dường như nó đang bỏ qua tệp kê khai của tôi, theo như tôi có thể nói.


Câu trả lời:


30

Một số lưu ý ngoài câu trả lời của Ned (đánh vào vấn đề cốt lõi):

Distutils không cài đặt các gói và mô-đun Python bên trong thư mục con cho mỗi dự án bên trong site-packages(hoặc dist-packagestrên Debian / Ubuntu): chúng được cài đặt trực tiếp vào site-packages, như bạn đã thấy. Vì vậy, whyteboard-xxthư mục chứa trong sdist của bạn sẽ không tồn tại ở dạng cài đặt cuối cùng.

Một ngụ ý của điều này là bạn nên cẩn thận đặt tên data_filestheo cách làm rõ chúng thuộc về dự án nào, vì những tệp / thư mục đó được cài đặt trực tiếp vào site-packagesthư mục chung, không phải bên trong bất kỳ whyteboardthư mục chứa nào .

Hoặc thay vào đó bạn có thể tạo dữ liệu package_datacủa whyteboardgói (có nghĩa là nó cần nằm bên trong gói đó, tức là bên cạnh __init__.py), và sau đó đây không phải là vấn đề.

Cuối cùng, không có ý nghĩa gì khi có cả một whyteboard.pymô-đun trong py_modulesvà một whyteboard/__init__.pygói trong đó packages. Cả hai loại trừ lẫn nhau và nếu bạn có cả hai, whyteboard.pymô-đun sẽ bị bỏ qua bởi các lần nhập để có lợi cho gói cùng tên.

Nếu whyteboard.pychỉ là một tập lệnh và không có ý định nhập, thì bạn nên sử dụng tùy chọn tập lệnh cho nó và xóa nó khỏi đó py_modules.


1
Thật không may. Tôi không thích ý tưởng có dữ liệu gói - đối với tôi, việc các tài nguyên đó nằm ngoài thư mục nguồn sẽ có ý nghĩa hơn. Tôi cũng không muốn có tên thư mục được đặt trước tên chương trình (mặc dù tôi đã làm điều đó cho các tệp trợ giúp). Hmm ..
Steven Sproat

67

MANIFEST.incho Distutils biết những tệp nào cần đưa vào bản phân phối nguồn nhưng nó không ảnh hưởng trực tiếp đến những tệp nào được cài đặt. Để làm được điều đó, bạn cần đưa các tệp thích hợp vào setup.pytệp, thường là dữ liệu gói hoặc dưới dạng tệp bổ sung .


Tôi đã thử thêm danh sách dữ liệu gói nhưng không có tệp nào tôi chỉ định được sử dụng. Tôi không chắc liệu vị trí của các tệp đã được cài đặt liên quan đến cài đặt tổng thể của gói hay chưa. Nhưng dù sao, nó vẫn không ghi các tệp của tôi theo đúng cấu trúc thư mục mà tôi mong đợi.
Steven Sproat

Tài liệu được liên kết trong câu trả lời này cung cấp cho bạn tất cả thông tin bạn cần về nơi cài đặt data_files và package_data. Nếu những tùy chọn này không phù hợp với bạn, vui lòng cập nhật câu hỏi của bạn với cú pháp chính xác mà bạn đã thử, kết quả và những gì bạn mong đợi.
Carl Meyer

4
Điều này phù hợp với tôi: Sao chép các mục nhập MANIFEST.in của tôi bên trong data_packages của setup.py sẽ làm cho mọi thứ hoạt động. Cảm ơn Ned - Tôi đã không hiểu điểm này trong nhiều năm. Hy vọng rằng bây giờ trải nghiệm distutils / setuptools / phân phối của tôi sẽ có ý nghĩa hơn.
Jonathan Hartley

7
Thiết kế có thể bao gồm các tệp trong gói sẽ không được cài đặt này có hợp lý không? Khi nào nó sẽ được sử dụng?
Roger Dahl

27

Tôi không thể tìm ra lý do tại sao MANIFEST.intệp của tôi bị bỏ qua khi tôi chạy python setup.py install- hóa ra lại include_package_data=Truegiải quyết được vấn đề. Các package_datatùy chọn không thực sự cần thiết.


bắt tốt, tại sao include_package_data=Truekhông phải là giá trị mặc định?
liang

8

Chạy python 2.6.1 trên Mac OSX, tôi hoàn toàn không gặp may mắn ngoại trừ việc sử dụng data_files tham số trong setup.py. Mọi thứ với MANIFEST.in chỉ đơn giản là dẫn đến các tệp được đưa vào gói dist, nhưng không bao giờ được cài đặt. Tôi đã kiểm tra một số gói khác và chúng thực sự đang sử dụng data_files để chỉ định các tệp bổ sung.

Tôi đã tạo một hàm ngắn để giúp liệt kê tất cả các tệp từ cây thư mục trong

(target_dir, [file list]) định dạng mà data_files mong đợi:

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

Bây giờ tôi chỉ có thể gọi điều này bên trong cuộc gọi thiết lập của mình:

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

Và mọi thứ trong những cái cây đó đã được cài đặt.


11
Điều này thật tuyệt, nhưng nó được cài đặt ở đâu? Đối với tôi, khi sử dụng "pip install", data_files của tôi đi vào thư mục gốc của virtualenv của tôi (tức là một thư mục duy nhất được chia sẻ bởi tất cả các gói của virtualenv.) Nếu sử dụng "setup.py install", thì data_files của tôi đi vào "site- package / <mypackage> .egg / ". Nếu các tệp là dữ liệu cần thiết trong thời gian chạy, thì trong cả hai trường hợp, mã của tôi không thể tìm thấy các tệp này là tầm thường và tất nhiên tôi phải tìm kiếm cả hai thư mục trong thời gian chạy. Nếu các tệp là tệp LICENSE của tôi, thì trong cả hai trường hợp, việc người dùng của tôi lấy từ nguồn của tôi đến LICENSE là điều không bình thường. Bối rối.
Jonathan Hartley

8

Bạn nên sử dụng các công cụ cài đặt:

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

Đây không thực sự là sử dụng tệp MANIFEST để thực hiện công việc, nhưng nó bao gồm tất cả các tệp cần thiết.


Điều này đã làm việc cho tôi với setuptools . Tôi xây dựng gói Debian và tôi thấy các tệp glade của mình được liệt kê trong package_datatừ điển chỉ xuất hiện ở đúng vị trí sau khi tôi thêm include_package_data=Tru.
mlt,

3

Ví dụ có thể chạy được xuất bản tối thiểu

Bài học chính: chỉ MANIFEST.inlàm việc cho tôi,package_data không.

Đã thử nghiệm trên Ubuntu 19.10, Python 3.7.5, wheel == 0.32.3, setuptools == 41.1.0, twine == 3.1.1.

Cách người dùng cuối sử dụng gói từ https://pypi.org/project/python-sample-package-with-data/ :

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

Sản lượng mong đợi:

hello data

Cách các nhà bảo trì xuất bản nó:

# 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

Các tệp thực tế:

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='ciro.santilli.contact@gmail.com',
    packages=find_packages(),
    include_package_data=True,
    scripts=['python-sample-package-with-data'],
)

Thư mục:

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.