setuptools: paket veri klasörü konumu


98

Python paketimi dağıtmak için setuptools kullanıyorum. Şimdi ek veri dosyaları dağıtmam gerekiyor.

Setuptools belgelerinden topladığım kadarıyla, veri dosyalarımı paket dizininin içinde bulundurmam gerekiyor. Ancak, veri dosyalarımın kök dizindeki bir alt dizinde olmasını tercih ederim.

Kaçınmak istediğim şey:

/ #root
|- src/
|  |- mypackage/
|  |  |- data/
|  |  |  |- resource1
|  |  |  |- [...]
|  |  |- __init__.py
|  |  |- [...]
|- setup.py

Bunun yerine sahip olmak istediğim şey:

/ #root
|- data/
|  |- resource1
|  |- [...]
|- src/
|  |- mypackage/
|  |  |- __init__.py
|  |  |- [...]
|- setup.py

Gerekli değilse, bu kadar çok alt dizine sahip olmak konusunda kendimi rahat hissetmiyorum. Bir neden bulamıyorum, neden dosyaları paket dizini içine koymam / koymam gerekiyor. Ayrıca bu kadar çok sayıda iç içe geçmiş alt dizin IMHO ile çalışmak zahmetlidir. Yoksa bu kısıtlamayı haklı çıkaracak iyi bir neden var mı?


9
Kaynakları (dokümanlar, resimler, vb.) Dağıtmak için 'data_files' kullanımı hakkında benzer bir soru sordum: stackoverflow.com/questions/5192386/… ... ve (iki) yanıtın her ikisi de bunun yerine 'package_data' kullanacağını söyledi. Şimdi paket verilerini kullanıyorum, ancak bu, verilerimi ve belgelerimi paketimin içine, yani kaynak kodumun arasına karıştırmam gerektiği anlamına geliyor. Bunu beğenmedim. Kaynağımı araştırırken, sadece aradığım sınıf tanımını değil, aynı zamanda RST, HTML ve ara dosyalarımda aldıkları düzinelerce sözü buluyorum. :-(
Jonathan Hartley

2
Bu yanıtın çok geç olduğunu biliyorum @JonathanHartley, ancak herhangi bir dizini bir __init__.pydosya ekleyerek , bu dosya boş olsa bile bir "paket" haline getirebilirsiniz . Böylece, __init__.pybir paket gibi görünmesi için bir veri dizinini boş bir dosyayla ayrı tutabilirsiniz . Bu, grep'in kaynak ağacınızın içinden onları toplamasını engellemelidir, ancak yine de python ve derleme araçları tarafından bir paket olarak tanınacaktır.
dhj

@dhj İlginç bir fikir, teşekkürler.
Jonathan Hartley

4
@dhj, bu yaklaşımla ilgili tek sorun python'un 'data' adlı bir paket kurduğunuzu düşünmesidir. Kurduğunuz başka bir paket aynı şekilde verileri paketlemeye çalıştıysa, iki çakışan 'veri' paketiniz kurulur.
ayak parmakları

Yanıtlar:


112

Seçenek 1: Paket verisi olarak yükleyin

Veri dosyalarını Python paketinizin köküne yerleştirmenin ana avantajı, dosyaların bir kullanıcının sisteminde (Windows, Mac, Linux, bazı mobil platformlar veya bir Yumurta içinde) nerede yaşayacağı konusunda endişelenmekten kaçınmanıza olanak vermesidir. dataNerede ve nasıl kurulursa kurulsun , dizini her zaman Python paket kökünüze göre bulabilirsiniz .

Örneğin, böyle bir proje düzenim varsa:

project/
    foo/
        __init__.py
        data/
            resource1/
                foo.txt

__init__.pyBir veri dosyasına mutlak bir yol bulmak için bir işlev ekleyebilirsiniz :

import os

_ROOT = os.path.abspath(os.path.dirname(__file__))
def get_data(path):
    return os.path.join(_ROOT, 'data', path)

print get_data('resource1/foo.txt')

Çıktılar:

/Users/pat/project/foo/data/resource1/foo.txt

Proje Egg olarak kurulduktan sonra, giden yol datadeğişecek, ancak kodun değişmesi gerekmiyor:

/Users/pat/virtenv/foo/lib/python2.6/site-packages/foo-0.0.0-py2.6.egg/foo/data/resource1/foo.txt

Seçenek 2: Sabit konuma yükleyin

Alternatif, verilerinizi Python paketinin dışına yerleştirmek ve ardından şunlardan birini yapmak olabilir:

  1. Konumunu var databir yapılandırma dosyası üzerinden geçirilen, komut satırı argümanları veya
  2. Konumu Python kodunuza gömün.

Projenizi dağıtmayı planlıyorsanız, bu çok daha az istenir. Bunu gerçekten yapmak istiyorsanız, dataher dosya grubu için hedef belirleyerek, bir tuple listesi göndererek hedef sistemde istediğiniz yere kurabilirsiniz :

from setuptools import setup
setup(
    ...
    data_files=[
        ('/var/data1', ['data/foo.txt']),
        ('/var/data2', ['data/bar.txt'])
        ]
    )

Güncellendi : Python dosyalarını yinelemeli olarak grep etmek için bir kabuk işlevi örneği:

atlas% function grep_py { find . -name '*.py' -exec grep -Hn $* {} \; }
atlas% grep_py ": \["
./setup.py:9:    package_data={'foo': ['data/resource1/foo.txt']}

7
Durumun üstesinden gelmeme yardım ettiğiniz için çok teşekkürler. Bu yüzden, sizin (ve diğer herkesin) önerdiği gibi package_data'yı kullanmaktan mutluyum. Ancak: Verilerini ve belgelerini kendi paket kaynak dizinine koymanın uygunsuz bir şekilde dağınık olduğunu bulan sadece ben miyim? (örneğin, kaynağımın grep edilmesi belgelerimden düzinelerce istenmeyen isabet döndürür. Her kullandığımda grep'e '--exclude-dir' parametresi ekleyebilirim, bu bir projeden diğerine farklılık gösterir, ancak bu iğrenç görünüyor) ithalatı bozmadan paket dizinin içine bir 'src' alt dizini eklemek mümkündür
Jonathan Hartley

Genellikle sadece paketin gerektirdiği veri dosyalarını paket dizinin altına koyarım. Dokümanları olarak kurardım data_files. Ayrıca, grep'in Python dışı dosyaları yoksayması için bir kabuk takma adı da oluşturabilirsiniz grep_py.
samplebias

Hey samplebias. Güncellemeler için teşekkürler. Bu sadece grep değil , metin düzenleyiciden dosyalarda arama yapmadan ctag'lere ve awk'a kadar her şey . Belgeleri önerdiğiniz gibi data_files içine koymak için projemi yeniden biçimlendirmeyi deneyeceğim, bunun nasıl çalıştığını görün. Çok yakında ... :-)
Jonathan Hartley

... bu iyi çalışıyor gibi görünüyor. Beni doğru yola koyduğunuz için teşekkürler. +50 itibar puanı lezzetli mi?
Jonathan Hartley

Teşekkürler! Bunu duymak harika, işe yaradığına ve ilerleme kaydettiğinize sevindim!
samplebias

14

Aşağıdaki yapıyı korumanıza izin verecek iyi bir uzlaşma bulduğumu düşünüyorum:

/ #root
|- data/
|  |- resource1
|  |- [...]
|- src/
|  |- mypackage/
|  |  |- __init__.py
|  |  |- [...]
|- setup.py

Örnekler yanıtında açıklanan sorunlardan kaçınmak için verileri paket_verisi olarak yüklemelisiniz, ancak dosya yapısını korumak için setup.py dosyanıza eklemelisiniz:

try:
    os.symlink('../../data', 'src/mypackage/data')
    setup(
        ...
        package_data = {'mypackage': ['data/*']}
        ...
    )
finally:
    os.unlink('src/mypackage/data')

Bu şekilde uygun yapıyı "tam zamanında" oluştururuz ve kaynak ağacımızı organize ederiz.

Bu tür veri dosyalarına kodunuz içinde erişmek için, 'basitçe' şunu kullanmalısınız:

data = resource_filename(Requirement.parse("main_package"), 'mypackage/data')

Verilerin bu modülle zorunlu olarak hiçbir ilgisi olmadığı için kodda 'mypackage' belirtmek zorunda kalmayı hala sevmiyorum, ancak sanırım bu iyi bir uzlaşma.


-4

Kurulum () için temelde bir argüman * data_files * olarak herhangi bir şey verebileceğinizi düşünüyorum .


Hmm ... Distutils belgelerinde olduğunu görebiliyorum, yine de kurulum araçları belgelerinde göremiyorum. Her neyse, sonunda ona nasıl erişebilirim?
phant0m

Bence data_files yalnızca birkaç paket arasında paylaşılan veriler için kullanılmalıdır. örneğin, PyPI'den pip kurulumu yaparsanız, data_files içinde listelenen dosyalar doğrudan ana Python kurulum dizininizin altındaki dizinlere yüklenir. (yani, Python27 / Lib / site-packages / mypackage içinde değil, 'Python27 / Lib' ile paralel olarak)
Jonathan Hartley
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.