Python 설정 도구를 사용한 설치 후 스크립트


97

사용자가 명령을 실행할 수 있도록 설치 후 Python 스크립트 파일을 setuptools setup.py 파일의 일부로 지정할 수 있습니까?

python setup.py install

로컬 프로젝트 파일 아카이브 또는

pip install <name>

PyPI 프로젝트의 경우 표준 setuptools 설치가 완료되면 스크립트가 실행됩니까? 단일 Python 스크립트 파일로 코딩 할 수있는 설치 후 작업을 수행하려고합니다 (예 : 사용자에게 사용자 지정 설치 후 메시지 전달, 다른 원격 소스 저장소에서 추가 데이터 파일 가져 오기).

나는 몇 년 전에 주제를 다루는 이 SO 답변을 보았고 당시의 합의는 install 하위 명령을 만들어야한다는 것입니다. 이 경우에도 사용자가 스크립트를 실행하기 위해 두 번째 명령을 입력 할 필요가 없도록 누군가가이를 수행하는 방법에 대한 예제를 제공 할 수 있습니까?


4
사용자가 두 번째 명령을 입력하도록 요구하는 대신 스크립트 실행을 자동화하고 싶습니다. 이견있는 사람?
Chris Simpkins 2013

1
이 당신을 위해 무엇을 찾고있는 수 있습니다 stackoverflow.com/questions/17806485/...
limp_chimp

1
감사합니다! 나는 그것을 확인합니다
크리스 심프 킨스에게

1
이것이 필요하다면 빠른 구글에서 찾은 이 블로그 게시물 이 유용 할 것 같습니다. (또한 문서에서 Setuptools 확장 및 재사용을 참조하십시오 .)
abarnert

1
@Simon 글쎄, 당신은 아마이 문제를 가진 누군가가 원하는 것이 아닌 것에 대한 4 년 전의 코멘트를보고 있습니다. 그래서 당신은 그것이 모니터링되고 최신 상태로 유지 될 것이라고 기대할 수 없습니다. 이것이 답이라면 그것을 대체 할 새로운 자원을 찾는 노력의 가치가있을 것이지만 그렇지 않습니다. 오래된 정보가 필요한 경우 언제든지 Wayback Machine을 사용하거나 현재 문서에서 해당 섹션을 검색 할 수 있습니다.
abarnert

답변:


92

참고 : 아래 솔루션은 소스 배포 zip 또는 tarball을 설치하거나 소스 트리에서 편집 가능한 모드로 설치할 때만 작동합니다. 그것은 것입니다 하지 바이너리 휠에서 설치할 때 (작동 .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(
    ...

추신 : setuptools에 사용할 수있는 사전 설치 진입 점이 없습니다. 왜 없는지 궁금하다면 이 토론을 읽으십시오 .


다른 것보다 깨끗해 보이지만 실제 명령 전에 사용자 지정 코드 실행하지 install않습니까?
raphinesse

7
그것은 당신에게 달려 있습니다. 먼저run 부모 를 호출하면 명령은 사후 설치이고 그렇지 않으면 사전 설치입니다. 이것을 반영하기 위해 답변을 업데이트했습니다.
kynan

1
이 솔루션을 사용하여이 보인다 install_requires의존성이 무시됩니다
ealfonso

7
이것은 나를 위해 작동하지 않았습니다 pip3. 설치 스크립트는 패키지를 게시 할 때 실행되었지만 설치할 때는 실행되지 않았습니다.
Eric Wiener

1
@JuanAntonioOrozco Wayback Machine을 사용하여 끊어진 링크를 업데이트했습니다. 이 순간에 왜 고장 났는지 모르겠습니다. 지금 은 bugs.python.org에 문제가 있을 수 있습니다.
mertyildiran

14

참고 : 아래 솔루션은 소스 배포 zip 또는 tarball을 설치하거나 소스 트리에서 편집 가능한 모드로 설치할 때만 작동합니다. 그것은 것입니다 하지 바이너리 휠에서 설치할 때 (작동 .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문서가 상당히 부족하기 때문 입니다. 다른 사람들은 이미이 Q & A에 대한 답변을 올바른 솔루션으로 수정했습니다.
Apalala

3
다른 답변은 나를 위해 작동하지 않습니다. 설치 후 스크립트가 실행되지 않거나 종속성이 더 이상 처리되지 않습니다. 지금까지, 나는에 충실 것 atexit하지 재정의 install.run()(이 종속성이 더 이상 처리되지 않는 이유입니다). 또한 설치 디렉토리를 알기 위해 , 무엇에 액세스 할 수 있는지 및 ( 어떤 것을 사용할지 모르겠지만 이상하게 잘못 _post_install()되었습니다)의 방법으로 넣었습니다 . new_installself.install_purelibself.install_platlibself.install_lib
zezollo

2
나는 또한 나를 위해 종속성 및 위해서는 atexit 작품에 문제가되었다
ealfonso

7
여기에있는 방법 중 어느 것도 바퀴와 함께 작동하지 않는 것 같습니다. 휠은 setup.py를 실행하지 않으므로 패키지를 설치할 때가 아니라 빌드 할 때만 메시지가 표시됩니다.
JCGB

7

참고 : 아래 솔루션은 소스 배포 zip 또는 tarball을 설치하거나 소스 트리에서 편집 가능한 모드로 설치할 때만 작동합니다. 그것은 것입니다 하지 바이너리 휠에서 설치할 때 (작동 .whl)


해결책은 post_setup.pyin setup.py의 디렉토리 를 포함하는 것 입니다 . post_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.py1, if __name__ == '__main__':문 당신이 발사 수동으로 할 수 있습니다 명령 줄에서 설치 후.


4
제 경우에는 재정의로 run()인해 패키지 종속성이 설치되지 않습니다.
Apalala

1
@Apalala는 잘못된 cmdclass것이 교체 되었기 때문에이 문제 를 해결했습니다.
kynan

1
아, 드디어 정답을 찾았습니다. 왜 잘못된 답변이 StackOverflow에서 그렇게 많은 표를 얻습니까? 사실, 당신은 당신의 post_install() 실행해야 합니다 install_data.run(self)그렇지 않으면 당신은 몇 가지 물건을 놓칠 것입니다. data_files적어도 좋아 . 키난 감사합니다.
personal_cloud

1
나를 위해 작동하지 않습니다. 어떤 이유로 든 install_data내 경우 에는 명령 이 실행되지 않습니다. 따라서 atexit어떤 상황에서도 설치 후 스크립트가 결국 실행되도록 보장하는 이점이 없습니까?
zezollo

3

@Apalala, @Zulu 및 @mertyildiran의 답변 결합; 이것은 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},
...

또한 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과 함께 노력하고 정상적으로 작동을 설치하지만 post_actions은 실행되지 않습니다 있어요 ...
dojuba

1

atexit을 사용하는 경우 새 cmdclass를 만들 필요가 없습니다. setup () 호출 직전에 atexit 레지스터를 간단히 만들 수 있습니다. 같은 일을합니다.

또한 종속성을 먼저 설치해야하는 경우 pip가 패키지를 제자리로 이동하기 전에 atexit 핸들러가 호출되므로 pip 설치와 함께 작동 하지 않습니다 .


여기에 게시 된 몇 가지 제안과 마찬가지로이 제안은 "설치"모드에서 실행 중인지 여부를 설명하지 않습니다. 이것이 사용자 정의 "명령"클래스가 사용되는 이유입니다.
BuvinJ

1

제시된 권장 사항으로 문제를 해결할 수 없었으므로 여기에 도움이되었습니다.

setup()에서 설치 직후 실행하려는 함수를 다음과 같이 호출 할 수 있습니다 setup.py.

from setuptools import setup

def _post_install():
    <your code>

setup(...)

_post_install()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.