पाइथन सेटप्टूल के साथ स्क्रिप्ट स्थापित करें


97

क्या सेट-अप सेटअपहोम फ़ाइल के भाग के रूप में एक पोस्ट-इंस्टाल पाइथन स्क्रिप्ट फ़ाइल को निर्दिष्ट करना संभव है, ताकि उपयोगकर्ता इसे व्यवस्थित कर सकें:

python setup.py install

स्थानीय प्रोजेक्ट फ़ाइल संग्रह पर, या

pip install <name>

एक PyPI प्रोजेक्ट के लिए और स्क्रिप्ट मानक setuptools स्थापित के पूरा होने पर चलाया जाएगा? मैं पोस्ट-इंस्टॉल कार्यों को करने के लिए देख रहा हूं, जिन्हें एक एकल पायथन स्क्रिप्ट फ़ाइल में कोडित किया जा सकता है (उदाहरण के लिए उपयोगकर्ता को एक कस्टम पोस्ट-इंस्टॉल संदेश वितरित करें, एक अलग दूरस्थ स्रोत रिपॉजिटरी से अतिरिक्त डेटा फ़ाइलों को खींचें)।

मैं इस SO उत्तर से कई साल पहले आया था जो इस विषय को संबोधित करता है और ऐसा लगता है जैसे कि उस समय आम सहमति थी कि आपको एक स्थापित सबकोमैंड बनाने की आवश्यकता है। अगर ऐसा अभी भी होता है, तो क्या किसी के लिए यह उदाहरण देना संभव होगा कि ऐसा कैसे किया जाए ताकि उपयोगकर्ता के लिए स्क्रिप्ट चलाने के लिए दूसरी कमांड दर्ज करना आवश्यक न हो?


4
मैं उपयोगकर्ता को दूसरी कमांड दर्ज करने की आवश्यकता के बजाय स्क्रिप्ट रन को स्वचालित करने की उम्मीद कर रहा हूं। कोई विचार?
क्रिस सिम्प्किंस

1
यह वही हो सकता है जो आप ढूंढ रहे हैं: stackoverflow.com/questions/17806485/…
limp_chimp

1
धन्यवाद! मैं इसे बाहर की जाँच करूँगा
क्रिस Simpkins

1
अगर आपको इसकी आवश्यकता है, तो यह ब्लॉग पोस्ट जो मुझे त्वरित Google द्वारा मिली है, ऐसा लगता है कि यह उपयोगी होगा। ( डॉक्स में विस्तार और पुन: उपयोग करने वाले सेटपूल को भी देखें ।)
अवतरण

1
@Simon खैर, आप 4 साल पहले की एक टिप्पणी को देख रहे हैं, जिसके बारे में शायद कोई भी ऐसा नहीं है जिसे यह समस्या चाहिए, इसलिए आप वास्तव में इसकी निगरानी और अद्यतित रहने की उम्मीद नहीं कर सकते। यदि यह एक उत्तर थे, तो उन्हें बदलने के लिए नए संसाधनों को खोजने के प्रयास के लायक होगा, लेकिन ऐसा नहीं है। यदि आपको पुरानी जानकारी की आवश्यकता है, तो आप हमेशा वेकबैक मशीन का उपयोग कर सकते हैं, या आप वर्तमान डॉक्स में समकक्ष अनुभाग की खोज कर सकते हैं।
१ert ’

जवाबों:


92

नोट: नीचे दिया गया समाधान केवल स्रोत वितरण ज़िप या टारबॉल स्थापित करते समय, या स्रोत पेड़ से संपादन योग्य मोड में स्थापित करने पर काम करता है। बाइनरी व्हील ( ) से इंस्टॉल करने पर यह काम नहीं करेगा.whl


यह समाधान अधिक पारदर्शी है:

आप कुछ अतिरिक्त करेंगे setup.pyऔर अतिरिक्त फ़ाइल की कोई आवश्यकता नहीं है।

इसके अलावा आपको दो अलग-अलग पोस्ट-इंस्टॉलेशन पर विचार करने की आवश्यकता है; एक विकास / संपादन मोड के लिए और दूसरा स्थापित मोड के लिए।

इन दो वर्गों को अपनी पोस्ट- स्क्रिप्ट में शामिल करें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

और इसमें कार्य करने के लिए cmdclassतर्क डालें :setup()setup.py

setup(
    ...

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

    ...
)

आप स्थापना के दौरान शेल कमांड भी कह सकते हैं, जैसे इस उदाहरण में जो पूर्व-इंस्टालेशन तैयारी करता है:

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 वहाँ कोई पूर्व स्थापित प्रविष्टि बिंदुओं पर उपलब्ध नहीं हैं। इस चर्चा को पढ़ें यदि आप सोच रहे हैं कि कोई भी क्यों नहीं है।


दूसरों की तुलना में क्लीनर दिखता है, लेकिन क्या यह वास्तविक आदेश से पहले कस्टम कोड को निष्पादित नहीं करता है install?
रफनेस

7
यह आप पर निर्भर है: यदि आप पहलेrun अभिभावक को फोन करते हैं तो आपकी कमांड एक पोस्ट-इंस्टाल है, अन्यथा यह प्री-इंस्टॉल है। मैंने इसे प्रतिबिंबित करने के लिए उत्तर अपडेट कर दिया है।
कियान

1
इस समाधान का उपयोग करने पर ऐसा लगता है कि install_requiresनिर्भरता को नजरअंदाज किया जाता है
ilefonso

6
यह मेरे साथ काम नहीं किया pip3। पैकेज प्रकाशित करते समय इंस्टॉल स्क्रिप्ट चलती थी, लेकिन इसे इंस्टॉल करते समय नहीं।
एरिक वीनर

1
@JuanAntonioOrozco मैंने वेबैक मशीन का उपयोग करके टूटी हुई लिंक को अपडेट किया है। मुझे नहीं पता कि यह इस समय क्यों टूट गया है। शायद Bugs.python.org के साथ अभी कुछ गलत है ।
मेरिटिल्डिरन

13

नोट: नीचे दिया गया समाधान केवल स्रोत वितरण ज़िप या टारबॉल स्थापित करते समय, या स्रोत पेड़ से संपादन योग्य मोड में स्थापित करने पर काम करता है। बाइनरी व्हील ( ) से इंस्टॉल करने पर यह काम नहीं करेगा.whl


यह एकमात्र रणनीति है जो मेरे लिए काम करती है जब पोस्ट-इंस्टॉल स्क्रिप्ट की आवश्यकता होती है कि पैकेज निर्भरता पहले ही स्थापित हो चुकी है:

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},

आप atexitइंस्टालेशन स्टेप के बाद केवल पोस्ट इंस्टॉल फ़ंक्शन को कॉल करने के बजाय एक हैंडलर को क्यों पंजीकृत करते हैं ?
kynan

1
@kynan क्योंकि setuptoolsकाफी अंडर-डॉक्यूमेंटेड है। अन्य लोगों ने पहले ही सही समाधान के साथ इस प्रश्नोत्तर पर अपने उत्तरों में संशोधन कर दिया है।
अपाला

3
वैसे अन्य उत्तर मेरे लिए काम नहीं करते हैं: या तो पोस्ट इंस्टॉल स्क्रिप्ट निष्पादित नहीं होती है, या निर्भरता अब और नहीं संभाला जाता है। अब तक, मैं पुनर्परिभाषित नहीं करूंगा atexitऔर यहinstall.run() निर्भर करेगा (यही कारण है कि अब निर्भरताएं नहीं संभाली जाती हैं)। इसके अलावा, क्रम स्थापित निर्देशिका पता करने के लिए में, मैं डाल दिया है _post_install()की एक विधि के रूप में new_install, मुझे क्या तक पहुंचने देता है self.install_purelibऔर self.install_platlib(जो एक का उपयोग करने पता नहीं है, लेकिन self.install_lib, गलत है अजीब तरह से)।
zezollo

2
मुझे निर्भरता के साथ भी समस्या हो रही थी और मेरे लिए
एटिक्स

7
यहां कोई भी विधि पहियों के साथ काम नहीं करती है। पहिए सेटअपफ्रेम नहीं चलते हैं, इसलिए संदेश केवल निर्माण करते समय प्रदर्शित होते हैं, पैकेज स्थापित करते समय नहीं।
JCGB

7

नोट: नीचे दिया गया समाधान केवल स्रोत वितरण ज़िप या टारबॉल स्थापित करते समय, या स्रोत पेड़ से संपादन योग्य मोड में स्थापित करने पर काम करता है। बाइनरी व्हील ( ) से इंस्टॉल करने पर यह काम नहीं करेगा.whl


एक समाधान एक निर्देशिका post_setup.pyमें शामिल करने के लिए हो सकता है setup.pypost_setup.pyएक फ़ंक्शन शामिल करेगा जो पोस्ट-इंस्टॉल करता है और setup.pyकेवल उचित समय पर इसे आयात और लॉन्च करेगा।

इन 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},
        ...
    )

इन post_setup.py:

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

if __name__ == '__main__':
    main()

setup.pyइसकी निर्देशिका से लॉन्च करने के सामान्य विचार के साथ , आप post_setup.pyइसे आयात कर पाएंगे और यह एक खाली फ़ंक्शन लॉन्च करेगा।

में post_setup.py, if __name__ == '__main__':बयान आपको कमांड लाइन से मैन्युअल रूप से पोस्ट-इंस्टॉल लॉन्च करने की अनुमति देता है।


4
मेरे मामले में, ओवरराइडिंग run()पैकेज निर्भरता को स्थापित नहीं करने का कारण बनता है।
अपाला

1
@ अपाला क्योंकि गलत cmdclassको बदल दिया गया था, मैंने यह तय कर लिया है।
कियान

1
आह, आखिरकार, हम सही जवाब पाते हैं। कैसे गलत जवाब स्टैकऑवरफ्लो पर इतने वोट मिलते हैं? दरअसल, आप अपने को चलाने के लिए है post_install() के बादinstall_data.run(self) अन्यथा आप गायब हो जाएगा कुछ सामान। data_filesकम से कम पसंद है । धन्यवाद किन्नन।
personal_cloud

1
मेरे लिए काम नहीं करता है। मुझे लगता है, किसी भी कारण से, install_dataमेरे मामले में आदेश निष्पादित नहीं किया गया है। तो, क्या यह atexitसुनिश्चित करने का फायदा नहीं है कि पोस्ट इंस्टॉल स्क्रिप्ट को किसी भी स्थिति में अंत में निष्पादित किया जाएगा?
zezollo

3

@ अपाला, @Zulu और @mertyildiran से उत्तरों को मिलाकर; इसने पायथन 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},
...

यह आपको पैकेज के इंस्टॉलेशन पथ तक पहुंच प्रदान करता है install_path, कुछ शेल कार्य करने के लिए।


2

मुझे लगता है कि पोस्ट-इंस्टॉलेशन करने और आवश्यकताओं को रखने का सबसे आसान तरीका है, कॉल को 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=['...
    )
)

यह setup()घोषणा करते समय चलेगा setup। एक बार आवश्यकताओं की स्थापना के साथ, यह _post_install()फ़ंक्शन चलाएगा , जो आंतरिक फ़ंक्शन चलाएगा _post_actions()


1
क्या आपने यह कोशिश की? मैं पायथन 3.4 के साथ कोशिश कर रहा हूं और सामान्य रूप से काम करता हूं लेकिन पोस्ट_डाउन निष्पादित नहीं किए जाते ...
डोजुबा

1

एटेक्सिट का उपयोग करते समय, एक नया cmdclass बनाने की आवश्यकता नहीं है। आप सेटअप () कॉल से ठीक पहले अपना एटैक्सिट रजिस्टर बना सकते हैं। यह वही काम करता है।

इसके अलावा, अगर आपको पहले स्थापित होने के लिए निर्भरता की आवश्यकता है, तो यह पाइप इंस्टॉल के साथ काम नहीं करता है क्योंकि आपके एटैक्सिट हैंडलर को पाइप को जगह में ले जाने से पहले बुलाया जाएगा।


यहाँ पोस्ट किए गए कुछ सुझावों की तरह, यह भी कि आप "इंस्टॉल" मोड में चल रहे हैं या नहीं इसका कोई हिसाब नहीं है। यही कारण है कि कस्टम "कमांड" कक्षाएं कार्यरत हैं।
बुविन जे

0

मैं किसी भी प्रस्तुत अनुशंसा के साथ एक समस्या को हल करने में सक्षम नहीं था, इसलिए यहां मुझे मदद मिली।

आप समारोह कॉल कर सकते हैं, कि आप बस के बाद स्थापना के बाद से चलाना चाहते हैं setup()में setup.pyइस तरह,:

from setuptools import setup

def _post_install():
    <your code>

setup(...)

_post_install()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.