Làm cách nào để bao gồm dữ liệu gói với setuptools / phân phối?


134

Khi sử dụng setuptools / phân phối, tôi không thể cài đặt trình cài đặt trong bất kỳ package_datatệp nào . Tất cả mọi thứ tôi đã đọc nói rằng sau đây là cách chính xác để làm điều đó. Ai đó có thể vui lòng tư vấn?

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

nơi myapp/data/là vị trí của các tập tin dữ liệu.


2
Tôi đang có cùng một vấn đề ... Chỉ định thủ công đã data_filesgiải quyết vấn đề. Nhưng đây là lỗi dễ xảy ra và không "cảm thấy đúng" với tôi. Ai đó có thể xác minh rằng nó thực sự cần thiết để sao chép cấu hình trong cả hai package_datadata_files?
shoutuma

github.com/wimglenn/resource-example Hiển thị cấu trúc dự án setuptools hiện đại, có thể đóng gói chính xác các tệp dữ liệu vào các bánh xe và sdists bằng cách sử dụng pyproject.toml. Không setup.pycần tập tin.
Wim

Câu trả lời:


288

Tôi nhận ra rằng đây là một câu hỏi cũ, nhưng đối với những người tìm đường đến đây thông qua Google: package_datalà một lời nói dối bẩn thỉu , thấp hèn . Nó chỉ được sử dụng khi xây dựng các gói nhị phân ( python setup.py bdist ...) chứ không phải khi xây dựng các gói nguồn ( python setup.py sdist ...). Tất nhiên, điều này là vô lý - người ta sẽ mong đợi rằng việc xây dựng một phân phối nguồn sẽ dẫn đến một tập hợp các tệp có thể được gửi cho người khác để xây dựng phân phối nhị phân.

Trong mọi trường hợp, việc sử dụng MANIFEST.insẽ hoạt động cả cho phân phối nhị phân và nguồn.


97
Tôi đã nghiên cứu vấn đề này trong một giờ qua và đã thử nhiều cách tiếp cận. Như bạn nói, package_datalàm việc cho bdistvà không sdist. Tuy nhiên , MANIFEST.inlàm việc cho sdist, nhưng không phải cho bdist! Do đó, điều tốt nhất tôi có thể đưa ra là bao gồm cả hai package_dataMANIFEST.inđể phù hợp với cả hai bdistsdist.
Wesley Baugh

7
Tôi tìm thấy một cái khác để hỗ trợ @WesleyBaugh. Trong stackoverflow.com/a/2969087/261718 , Sử dụng MANIFEST.incho các tệp bạn sẽ không cài đặt, như tài liệu và package_datacho các tệp bạn sử dụng không phải mã Python (như hình ảnh hoặc mẫu).
Drake Guan

12
Tôi đang sử dụng sdist, và phải bao gồm cả hai MANIFEST.in package_data . Dường như MANIFEST.inđiều khiển những gì được bao gồm trong bản phân phối và pack_data kiểm soát những gì sau đó được sao chép vào thư mục site_packages trong khi cài đặt. Một cách khó hiểu, các đường dẫn trong MANIFEST.incó liên quan đến vị trí của setup.py và package_dataliên quan đến các gói riêng lẻ (ví dụ: mô-đun).
Edward Newell

9
"Đã thay đổi trong phiên bản 2.7: Tất cả các tệp khớp với gói_data sẽ được thêm vào tệp MANIFEST nếu không có mẫu nào được cung cấp. Xem phần Chỉ định các tệp sẽ phân phối." từ distutils . Vì vậy, bạn sẽ chỉ thấy hành vi của các tệp package_datađược tự động đưa vào ZIP nếu bạn không có tệp MANIFEST.in hiện tại và chỉ khi bạn đang sử dụng 2.7+.
Johnus

29
Nghiêm túc mà nói, tôi cảm thấy như chiếc vé này là một buổi trị liệu theo nhóm cho những người sử dụng setuptools và khám phá ra một nơi tồi tệ mà họ đã tìm thấy trong cuộc sống.
Matt Joyce

32

Tôi chỉ có vấn đề tương tự. Các giải pháp, chỉ đơn giản là để loại bỏ include_package_data=True.

Sau khi đọc ở đây , tôi nhận ra rằng include_package_datamục đích bao gồm các tệp từ kiểm soát phiên bản , trái ngược với chỉ "bao gồm dữ liệu gói" như tên ngụ ý. Từ các tài liệu:

Các tệp dữ liệu [của include_package_data] phải nằm trong điều khiển CVS hoặc Subversion

...

Nếu bạn muốn kiểm soát chi tiết hơn đối với những tập tin nào được đưa vào (ví dụ: nếu bạn có tệp tài liệu trong thư mục gói của mình và muốn loại trừ chúng khỏi cài đặt), thì bạn cũng có thể sử dụng package_datatừ khóa.

Lấy lý lẽ đó ra đã sửa nó, điều trùng hợp là tại sao nó cũng hoạt động khi bạn chuyển sang distutils, vì nó không lấy lý lẽ đó.


2
Kinh nghiệm của tôi khác, tôi đã có cùng một vấn đề mà không bao gồm các include_package_data=Truemục. Giải pháp duy nhất cho tôi là thêm một mục trong Manifest như đề xuất ở trên. Có phiền bạn tôi đang sử dụng setuptools, có lẽ phiên bản của bạn hoạt động với 'phân phối'?
TimStaley

4
Lý do thực tế tại sao loại bỏ include_package_datavấn đề giải quyết được tiếp tục trong văn bản gốc - Nếu sử dụng include_package_datađối số dành riêng cho thiết lập, các tệp được chỉ định bởi package_datasẽ không được tự động thêm vào tệp kê khai trừ khi chúng được liệt kê trong MANIFEST.intệp.
Piotr Dobrogost

Trường hợp sử dụng của việc package_datađặt thành một danh sách không trống và chỉ định là include_package_data=Falsegì? Và tại sao bạn cần chỉ định tệp hai lần trong MANIFEST.inpackage_data?
Herbert

21

Theo khuyến nghị của @Joe để xóa include_package_data=Truedòng cũng có hiệu quả với tôi.

Để giải thích thêm một chút, tôi không có MANIFEST.in tập tin. Tôi sử dụng Git chứ không phải CVS.

Kho lưu trữ có hình dạng này:

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

Tôi chạy python setup.py sdistcho một nguồn phân phối (chưa thử nhị phân).

Và khi ở trong một môi trường ảo hoàn toàn mới, tôi có một myproject-4.19.tar.gztập tin và tôi sử dụng

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

Và ngoài mọi thứ được cài đặt vào môi trường ảo của tôi site-packages, các tệp dữ liệu đặc biệt đó được cài đặt vào /opt/local/myproject/data/opt/local/myproject/etc.


16

include_package_data=True đã làm cho tôi.

Nếu bạn sử dụng git, hãy nhớ đưa setuptools-gitvào install_requires. Ít nhàm chán hơn nhiều so với việc có Manifesthoặc bao gồm tất cả đường dẫn trong package_data(trong trường hợp của tôi là ứng dụng django với tất cả các loại thống kê)

(đã dán nhận xét tôi đã đưa ra, vì k3-rnc đã đề cập đến nó thực sự hữu ích như vậy)


7

Cập nhật : Câu trả lời này đã cũ và thông tin không còn giá trị. Tất cả các cấu hình setup.py nên sử dụng import setuptools. Tôi đã thêm một câu trả lời đầy đủ hơn tại https://stackoverflow.com/a/49501350/64313


Tôi đã giải quyết điều này bằng cách chuyển sang distutils. Có vẻ như phân phối bị phản đối và / hoặc bị hỏng.

from distutils.core import setup

setup(
   name='myapp',
   packages=['myapp'],
   package_data={
      'myapp': ['data/*.txt'],
   },
)

2
phân phối không được phản đối, nó đang thay thế distutils. Tôi không biết tại sao bạn gặp vấn đề, nhưng đó không phải là lý do.
agf

1
Đó là phản hồi tôi nhận được từ IRC, vậy tôi tin ai? Nếu bạn có một ví dụ làm việc bằng cách sử dụng phân phối, tôi sẽ đánh giá cao sau đó.
cmcginty

6
làm rõ: phân phối có nghĩa là để thay thế setuptools, cả hai đều được xây dựng trên đỉnh của distutils. distutils cuối cùng sẽ được thay thế bằng một gói mới, được gọi là "distutils2" trong python2 và "bao bì" trong python3
Kevin Horn

1
Chuyển sang distutils giải quyết vấn đề của tôi, nơi include_package_data=Truekhông được vinh danh. Vì vậy, với cài đặt đó, bạn chỉ cần MANIFEST.in - không cần sao chép danh sách tệp của bạn trong package_datacài đặt.
Daniel Sokolowski

4

Câu hỏi cổ xưa và ... quản lý gói của trăn thực sự để lại rất nhiều mong muốn. Vì vậy, tôi đã có trường hợp sử dụng cài đặt sử dụng pip cục bộ vào một thư mục được chỉ định và rất ngạc nhiên khi cả hai đường dẫn pack_data và data_files đều không hoạt động. Tôi không quan tâm đến việc thêm một tệp khác vào repo vì vậy cuối cùng tôi đã tận dụng tùy chọn data_files và setup.py --install-data; một cái gì đó như thế này

pip install . --install-option="--install-data=$PWD/package" -t package  


3

Tôi đã có cùng một vấn đề trong một vài ngày nhưng ngay cả chủ đề này cũng không thể giúp tôi vì mọi thứ đều khó hiểu. Vì vậy, tôi đã nghiên cứu và tìm thấy giải pháp sau đây:

Về cơ bản trong trường hợp này, bạn nên làm:

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

Câu trả lời stackoverflow đầy đủ khác ở đây


Đã thử điều này, nhưng vẫn không có gì được sao chép.
gerrit

2

Chỉ cần xóa dòng:

include_package_data=True,

từ tập lệnh thiết lập của bạn, và nó sẽ hoạt động tốt. (Đã thử nghiệm ngay bây giờ với setuptools mới nhất.)


Thật điên rồ nhưng nó hoạt động cả với sdistbdist_wheel, bạn đã kiểm tra tại sao chưa?
Szabolcs

Tôi thực sự có thể xác nhận rằng sdistbỏ qua package_datakhi điều này được thiết lập.
Sander Steffann

Tại thời điểm này đã được vài tháng, nhưng tôi dường như nhớ lại việc đào mã, bị mất hai lần, lấy một chiếc lược có răng tinh xảo vào tài liệu và đạt được sự hài lòng. Rõ ràng các tập lệnh mẫu khác nhau chứa cờ này và nó không gây ra đau đầu.
Ian

1

Sử dụng setup.cfg (setuptools 30.3.0)

Bắt đầu với setuptools 30.3.0 (phát hành 2016-12-08), bạn có thể giữ cho mình setup.pyrất nhỏ và chuyển cấu hình sang một setup.cfgtệp. Với phương pháp này, bạn có thể đặt dữ liệu gói của mình vào một [options.package_data]phần:

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

Trong trường hợp này, bạn setup.pycó thể ngắn như:

from setuptools import setup
setup()

Để biết thêm thông tin, hãy xem cấu hình thiết lập bằng các tệp setup.cfg .

một số thảo luận về việc phản đốisetup.cfg ủng hộ pyproject.tomlnhư được đề xuất trong PEP 518 , nhưng điều này vẫn chỉ là tạm thời vào năm 2020-2-21.


Câu trả lời này bỏ qua việc đề cập đến tệp MANIFEST vì vậy tôi nghĩ rằng nó sẽ không thực sự hoạt động với người theo dõi. Chỉ với bánh xe. Bạn nên đề cập đến điều đó.
wim

@wim Tôi không đủ hiểu về MANIFEST, sdist và bánh xe để trả lời điều đó. Điều này làm việc cho tôi bằng cách sử dụng pip install.
gerrit

Đó là bởi vì pip install, đối với một phiên bản đủ hiện đại của pip, trước tiên sẽ chế tạo một bánh xe và sau đó cài đặt nó. Tuy nhiên, đối với nhiều người dùng, phương pháp này sẽ không bao gồm dữ liệu gói. Xem câu trả lời được chấp nhận và các ý kiến ​​dưới đó để biết chi tiết về điều đó. Sử dụng a setup.cfgthực sự chỉ là một cách viết khác nhau mà OP đã làm trong setup.pycâu hỏi (bằng cách chuyển package_datađối số từ khóa trong lệnh gọi setup), vì vậy tôi không nghĩ rằng đây là câu trả lời đặc biệt hữu ích cho câu hỏi này . Nó không giải quyết vấn đề cơ bản nào cả.
Wim
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.