Apakah mungkin untuk menentukan file skrip Python pasca-instal sebagai bagian dari file setuptools setup.py sehingga pengguna dapat menjalankan perintah:
python setup.py install
pada arsip file proyek lokal, atau
pip install <name>
untuk proyek PyPI dan skrip akan dijalankan setelah instalasi standar setuptools selesai? Saya mencari untuk melakukan tugas pasca-pemasangan yang dapat dikodekan dalam satu file skrip Python (misalnya, mengirimkan pesan pasca-pemasangan khusus kepada pengguna, menarik file data tambahan dari repositori sumber jarak jauh yang berbeda).
Saya menemukan jawaban SO ini dari beberapa tahun yang lalu yang membahas topik dan kedengarannya seolah-olah konsensus pada saat itu adalah bahwa Anda perlu membuat subperintah instal. Jika masih demikian, apakah mungkin seseorang memberikan contoh bagaimana melakukan ini sehingga pengguna tidak perlu memasukkan perintah kedua untuk menjalankan skrip?
sumber
Jawaban:
Catatan: Solusi di bawah ini hanya berfungsi ketika menginstal zip atau tarball distribusi sumber, atau menginstal dalam mode yang dapat diedit dari pohon sumber. Ini tidak akan berfungsi saat memasang dari roda biner (
.whl
)Solusi ini lebih transparan:
Anda akan membuat beberapa tambahan
setup.py
dan tidak perlu file tambahan.Anda juga perlu mempertimbangkan dua pasca-instalasi yang berbeda; satu untuk mode pengembangan / dapat diedit dan yang lainnya untuk mode penginstalan.
Tambahkan dua kelas ini yang menyertakan skrip pasca-pemasangan Anda ke
setup.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
dan masukkan
cmdclass
argumen untuksetup()
berfungsi disetup.py
:setup( ... cmdclass={ 'develop': PostDevelopCommand, 'install': PostInstallCommand, }, ... )
Anda bahkan dapat memanggil perintah shell selama instalasi, seperti dalam contoh ini yang melakukan persiapan pra-instalasi:
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 tidak ada titik masuk pra-instal yang tersedia di alat setup. Bacalah pembahasan ini jika Anda bertanya-tanya mengapa tidak ada.
sumber
install
perintah sebenarnya ?run
induknya terlebih dahulu, maka perintah Anda adalah pasca-pemasangan, jika tidak maka pra-instal. Saya telah memperbarui jawaban untuk mencerminkan ini.install_requires
dependensi diabaikanpip3
. Skrip instal berjalan saat menerbitkan paket, tetapi tidak saat menginstalnya.Catatan: Solusi di bawah ini hanya berfungsi ketika menginstal zip atau tarball distribusi sumber, atau menginstal dalam mode yang dapat diedit dari pohon sumber. Ini tidak akan berfungsi saat memasang dari roda biner (
.whl
)Ini adalah satu-satunya strategi yang berhasil untuk saya ketika skrip pasca-instal mengharuskan dependensi paket telah diinstal:
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},
sumber
atexit
penangan daripada hanya memanggil fungsi pasca instal setelah langkah instalasi?setuptools
kurang terdokumentasi. Orang lain telah mengubah jawaban mereka pada Q&A ini dengan solusi yang benar.atexit
dan tidak mendefinisikan ulanginstall.run()
(inilah alasan mengapa dependensi tidak ditangani lagi). Selain itu, untuk mengetahui direktori instal, saya telah menempatkan_post_install()
metodenew_install
, apa yang memungkinkan saya mengaksesself.install_purelib
danself.install_platlib
(tidak tahu mana yang akan digunakan, tetapiself.install_lib
salah, anehnya).Catatan: Solusi di bawah ini hanya berfungsi ketika menginstal zip atau tarball distribusi sumber, atau menginstal dalam mode yang dapat diedit dari pohon sumber. Ini tidak akan berfungsi saat memasang dari roda biner (
.whl
)Sebuah solusi bisa untuk menyertakan
post_setup.py
dalamsetup.py
direktori 's.post_setup.py
akan berisi fungsi yang melakukan pasca-pemasangan dansetup.py
hanya akan mengimpor dan meluncurkannya pada waktu yang tepat.Masuk
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}, ... )
Masuk
post_setup.py
:def main(): """Do here your post-install""" pass if __name__ == '__main__': main()
Dengan gagasan umum untuk meluncurkan
setup.py
dari direktorinya, Anda akan dapat mengimporpost_setup.py
jika tidak, itu akan meluncurkan fungsi kosong.Di
post_setup.py
,if __name__ == '__main__':
pernyataan memungkinkan Anda untuk meluncurkan secara manual pasca-pemasangan dari baris perintah.sumber
run()
menyebabkan dependensi paket tidak diinstal.cmdclass
diganti, saya sudah perbaiki ini.post_install()
setelah ituinstall_data.run(self)
jika tidak Anda akan kehilangan beberapa hal.data_files
Setidaknya suka . Terima kasih kynan.install_data
tersebut tidak dijalankan dalam kasus saya. Jadi, bukankahatexit
keuntungan memastikan skrip pasca instalasi akan dijalankan pada akhirnya, dalam situasi apa pun?Menggabungkan jawaban dari @Apalala, @Zulu dan @mertyildiran; ini berhasil untuk saya di lingkungan Python 3.5:
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}, ...
Ini juga memberi Anda akses ke jalur instalasi paket di
install_path
, untuk melakukan beberapa pekerjaan shell.sumber
Menurut saya, cara termudah untuk melakukan pasca-pemasangan, dan memenuhi persyaratannya, adalah dengan menghias panggilan ke
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=['... ) )
Ini akan berjalan
setup()
saat mendeklarasikansetup
. Setelah selesai dengan instalasi persyaratan, itu akan menjalankan_post_install()
fungsi, yang akan menjalankan fungsi bagian dalam_post_actions()
.sumber
Jika menggunakan atexit, tidak perlu membuat cmdclass baru. Anda cukup membuat register atexit tepat sebelum panggilan setup (). Itu melakukan hal yang sama.
Selain itu, jika Anda memerlukan dependensi untuk diinstal terlebih dahulu, ini tidak berfungsi dengan pip install karena atexit handler Anda akan dipanggil sebelum pip memindahkan paket ke tempatnya.
sumber
Saya tidak dapat menyelesaikan masalah dengan rekomendasi yang disajikan, jadi inilah yang membantu saya.
Anda dapat memanggil fungsi, bahwa Anda ingin menjalankan setelah instalasi setelah
setup()
disetup.py
, seperti itu:from setuptools import setup def _post_install(): <your code> setup(...) _post_install()
sumber