Python kurulum araçlarıyla yükleme sonrası komut dosyası


100

Setuptools setup.py dosyasının bir parçası olarak kurulum sonrası bir Python komut dosyası belirtmek mümkün mü, böylece bir kullanıcı şu komutu çalıştırabilir:

python setup.py install

yerel bir proje dosyası arşivinde veya

pip install <name>

PyPI projesi için ve komut dosyası, standart kurulum araçları kurulumunun tamamlanmasının ardından çalıştırılacak Tek bir Python komut dosyasında kodlanabilen yükleme sonrası görevleri gerçekleştirmek istiyorum (örneğin, kullanıcıya özel bir yükleme sonrası mesaj göndermek, farklı bir uzak kaynak havuzundan ek veri dosyaları çekmek).

Birkaç yıl önce konuyu ele alan bu SO cevabına rastladım ve o zamanki fikir birliği bir yükleme alt komutu oluşturmanız gerektiğiydi. Hala durum böyleyse, kullanıcının betiği çalıştırmak için ikinci bir komut girmesine gerek kalmaması için birisinin bunun nasıl yapılacağına dair bir örnek vermesi mümkün olabilir mi?


4
Kullanıcının ikinci bir komut girmesini gerektirmek yerine, komut dosyasını çalıştırmayı otomatikleştirmeyi umuyorum. Düşüncesi olan var mı?
Chris Simpkins

1
Aradığınız şey bu olabilir: stackoverflow.com/questions/17806485/…
limp_chimp

1
Teşekkür ederim! Kontrol edeceğim
Chris Simpkins

1
Buna ihtiyacınız varsa, hızlı bir google tarafından bulduğum bu blog yazısı faydalı olacak gibi görünüyor. ( Belgelerde Kurulum Araçlarını Genişletme ve Yeniden Kullanma konusuna da bakın .)
abarnert

1
@Simon Pekala, 4 yıl önceki bir yoruma bakıyorsunuz, muhtemelen bu soruna sahip birinin istediği bir şey değil, bu yüzden izlenmesini ve güncel tutulmasını gerçekten bekleyemezsiniz. Bu bir cevap olsaydı, bunların yerini alacak yeni kaynaklar bulmak çabaya değerdi, ama değil. Güncel olmayan bilgilere ihtiyacınız varsa, her zaman Wayback Machine'i kullanabilir veya mevcut dokümanlardaki eşdeğer bölümü arayabilirsiniz.
abarnert

Yanıtlar:


93

Not: Aşağıdaki çözüm yalnızca bir kaynak dağıtım zip veya tarball yüklerken veya bir kaynak ağacından düzenlenebilir modda kurulum yaparken çalışır. Bu olacak değil bir ikili çarkından yüklerken (çalışmak .whl)


Bu çözüm daha şeffaftır:

Birkaç ekleme yapacaksınız setup.pyve fazladan bir dosyaya gerek yok.

Ayrıca iki farklı kurulum sonrası düşünmeniz gerekir; biri geliştirme / düzenlenebilir mod için, diğeri yükleme modu için.

Yükleme sonrası komut dosyanızı içeren bu iki sınıfı şuraya ekleyinsetup.py :

from setuptools import setup
from setuptools.command.develop import develop
from setuptools.command.install import install


class PostDevelopCommand(develop):
    """Post-installation for development mode."""
    def run(self):
        develop.run(self)
        # PUT YOUR POST-INSTALL SCRIPT HERE or CALL A FUNCTION

class PostInstallCommand(install):
    """Post-installation for installation mode."""
    def run(self):
        install.run(self)
        # PUT YOUR POST-INSTALL SCRIPT HERE or CALL A FUNCTION

ve içinde çalışacak cmdclassbağımsız değişken ekleyin :setup()setup.py

setup(
    ...

    cmdclass={
        'develop': PostDevelopCommand,
        'install': PostInstallCommand,
    },

    ...
)

Kurulum öncesi hazırlık yapan bu örnekte olduğu gibi kurulum sırasında kabuk komutlarını bile çağırabilirsiniz:

from setuptools import setup
from setuptools.command.develop import develop
from setuptools.command.install import install
from subprocess import check_call


class PreDevelopCommand(develop):
    """Pre-installation for development mode."""
    def run(self):
        check_call("apt-get install this-package".split())
        develop.run(self)

class PreInstallCommand(install):
    """Pre-installation for installation mode."""
    def run(self):
        check_call("apt-get install this-package".split())
        install.run(self)


setup(
    ...

PS, kurulum araçlarında önceden yükleme giriş noktası yoktur. Neden olmadığını merak ediyorsanız bu tartışmayı okuyun .


Diğerlerinden daha temiz görünüyor, ancak bu , gerçek komuttan önce özel kodu çalıştırmaz installmı?
raphinesse

7
Bu size kalmış: Eğer ararsanız runebeveyn üzerinde ilk sonra komut sonrası yüklüyoruz aksi takdirde önceden yükleme var. Cevabı bunu yansıtacak şekilde güncelledim.
kynan

1
bu çözümü kullanarak install_requiresbağımlılıklar göz ardı ediliyor gibi görünüyor
ealfonso

7
Bu benim için işe yaramadı pip3. Yükleme komut dosyası paketi yayınlarken çalıştı, ancak yüklerken çalışmadı.
Eric Wiener

1
@JuanAntonioOrozco Bozuk bağlantıyı Wayback Machine kullanarak güncelledim. Şu anda neden kırıldığını bilmiyorum. Belki şu anda bugs.python.org ile ilgili bir sorun var .
mertyildiran

15

Not: Aşağıdaki çözüm yalnızca bir kaynak dağıtım zip veya tarball yüklerken veya bir kaynak ağacından düzenlenebilir modda kurulum yaparken çalışır. Bu olacak değil bir ikili çarkından yüklerken (çalışmak .whl)


Bu, yükleme sonrası komut dosyası paket bağımlılıklarının zaten kurulu olmasını gerektirdiğinde benim için çalışan tek stratejidir:

import atexit
from setuptools.command.install import install


def _post_install():
    print('POST INSTALL')


class new_install(install):
    def __init__(self, *args, **kwargs):
        super(new_install, self).__init__(*args, **kwargs)
        atexit.register(_post_install)


setuptools.setup(
    cmdclass={'install': new_install},

atexitKurulum adımından sonra kurulum sonrası işlevini çağırmak yerine neden bir işleyici kaydediyorsunuz?
kynan

1
@kynan Çünkü setuptoolsyeterince belgelenmemiş. Diğerleri bu soru ve cevaptaki cevaplarını doğru çözümlerle zaten değiştirdiler.
Apalala

3
Diğer cevaplar benim için işe yaramıyor: ya yükleme sonrası komut dosyası çalıştırılmıyor ya da bağımlılıklar artık işlenmiyor. Şimdiye kadar sadık kalacağız atexitve değil yeniden tanımlanması install.run()(bu bağımlılıklar artık işlenmez nedeni budur). Ek olarak, kurulum dizinini bilmek için, _post_install()bir yöntem olarak new_install, neye erişmeme izin verdiğini self.install_purelibve self.install_platlib(hangisini kullanacağımı bilmiyorum ama self.install_libyanlış, garip bir şekilde) koydum .
zezollo

2
Ayrıca bağımlılıklarla ilgili sorunlar yaşıyordum ve atexit benim için çalışıyor
ealfonso

7
Buradaki yöntemlerin hiçbiri tekerleklerle işe yaramıyor. Tekerlekler setup.py'yi çalıştırmaz, bu nedenle mesajlar paketi kurarken değil, yalnızca oluştururken görüntülenir.
JCGB

7

Not: Aşağıdaki çözüm yalnızca bir kaynak dağıtım zip veya tarball yüklerken veya bir kaynak ağacından düzenlenebilir modda kurulum yaparken çalışır. Bu olacak değil bir ikili çarkından yüklerken (çalışmak .whl)


Bir çözüm post_setup.py, setup.py'ın dizinini eklemek olabilir . post_setup.pyyükleme sonrası yapan ve setup.pyonu yalnızca uygun zamanda içe aktaracak ve başlatacak bir işlev içerecektir .

İçinde setup.py:

from distutils.core import setup
from distutils.command.install_data import install_data

try:
    from post_setup import main as post_install
except ImportError:
    post_install = lambda: None

class my_install(install_data):
    def run(self):
        install_data.run(self)
        post_install()

if __name__ == '__main__':
    setup(
        ...
        cmdclass={'install_data': my_install},
        ...
    )

İçinde post_setup.py:

def main():
    """Do here your post-install"""
    pass

if __name__ == '__main__':
    main()

Dizinden başlatma genel fikri ile, başka bir şey setup.pyiçe aktarabileceksiniz, post_setup.pybu boş bir işlevi başlatacaktır.

Olarak post_setup.py, if __name__ == '__main__':deyim sen fırlatma elle sağlayan komut satırından yükleme sonrası.


4
Benim durumumda, geçersiz kılma run(), paket bağımlılıklarının kurulmamasına neden olur.
Apalala

1
@Apalala yanlış cmdclassdeğiştirildiği için, bunu düzelttim.
kynan

1
Ah, sonunda doğru cevabı bulduk. StackOverflow'da nasıl yanlış cevaplar bu kadar çok oy alıyor? Nitekim, post_install() peşinden koşmak zorundasın , install_data.run(self)aksi halde bazı şeyleri kaçırırsın. Gibi data_filesen azından. Teşekkür ederim kynan.
personal_cloud

1
Benim için çalışmıyor. Sanırım, herhangi bir nedenle, install_databenim durumumda komut yerine getirilmedi. Öyleyse, atexitherhangi bir durumda kurulum sonrası betiğinin sonunda çalıştırılmasını sağlamanın avantajı yok mu?
zezollo

3

@Apalala, @Zulu ve @mertyildiran'dan gelen cevapları birleştirerek; bu benim için bir Python 3.5 ortamında çalıştı:

import atexit
import os
import sys
from setuptools import setup
from setuptools.command.install import install

class CustomInstall(install):
    def run(self):
        def _post_install():
            def find_module_path():
                for p in sys.path:
                    if os.path.isdir(p) and my_name in os.listdir(p):
                        return os.path.join(p, my_name)
            install_path = find_module_path()

            # Add your post install code here

        atexit.register(_post_install)
        install.run(self)

setup(
    cmdclass={'install': CustomInstall},
...

Bu aynı zamanda, install_pathüzerinde bazı kabuk çalışmaları yapmak için içindeki paketin kurulum yoluna erişmenizi sağlar .


2

Kurulum sonrası gerçekleştirmenin ve gereksinimleri korumanın en kolay yolunun, aramayı şu şekilde dekore etmek olduğunu düşünüyorum setup(...):

from setup tools import setup


def _post_install(setup):
    def _post_actions():
        do_things()
    _post_actions()
    return setup

setup = _post_install(
    setup(
        name='NAME',
        install_requires=['...
    )
)

Bu çalışacaktır setup()bildirirken setup. Gereksinim kurulumu tamamlandıktan sonra _post_install(), iç işlevi çalıştıracak işlevi çalıştıracaktır _post_actions().


1
Bunu denedin mi Python 3.4 ile deniyorum ve normal şekilde çalışıyor ancak post_actions yürütülmüyor ...
dojuba

1

Atexit kullanıyorsanız, yeni bir cmdclass oluşturmaya gerek yoktur. Atexit kaydınızı setup () çağrısından hemen önce kolayca oluşturabilirsiniz. Aynı şeyi yapıyor.

Eğer bağımlılıkları gerekirse Ayrıca, ilk yüklü olması, bunu yapar değil senin atexit işleyicisi yerine pip hareket paketleri önce adı verilecek beri pip ile çalışma yükleyin.


Burada yayınlanan birkaç öneri gibi, bu da "yükleme" modunda çalışıp çalışmadığınızı açıklamaz. Özel "komut" sınıflarının kullanılmasının nedeni budur.
BuvinJ

1

Sunulan herhangi bir öneriyle bir sorunu çözemedim, işte bana yardımcı olan şey şu.

Sen hemen sonra kurulumdan sonra çalıştırmak istediğiniz, işlevini çağırabilirsiniz setup()içinde setup.pybunun gibi,:

from setuptools import setup

def _post_install():
    <your code>

setup(...)

_post_install()
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.