[python] 패키지의 setup.py (setuptools)에 정의 된 버전을 얻으려면 어떻게해야합니까?

setup.py패키지에서 ( --version또는 다른 목적으로) 버전을 정의하려면 어떻게 해야합니까?



답변

이미 설치된 배포의 질문 버전 문자열

런타임에 패키지 내부에서 버전을 검색하려면 (질문이 실제로 묻는 것) 다음을 사용할 수 있습니다.

import pkg_resources  # part of setuptools
version = pkg_resources.require("MyProject")[0].version

설치 중 사용할 저장소 버전 문자열

다른 방법으로 돌아가고 싶다면 (여기서 다른 답변 작성자가 요청한 것으로 보이는 것처럼 보임) 버전 문자열을 별도의 파일에 넣고에서 해당 파일의 내용을 읽으십시오 setup.py.

패키지에서 한 __version__줄로 version.py를 만든 다음을 사용하여 setup.py에서 읽어서 setup.py 네임 스페이스에서 execfile('mypackage/version.py')설정할 수 __version__있습니다.

버전 문자열에 액세스해야하는 모든 Python 버전 및 비 Python 언어에서 작동하는 훨씬 간단한 방법을 원할 경우 :

버전 문자열을 일반 텍스트 파일 (예 : eg)의 유일한 내용으로 저장하고 VERSION그 동안 해당 파일을 읽습니다 setup.py.

version_file = open(os.path.join(mypackage_root_dir, 'VERSION'))
version = version_file.read().strip()

그러면 동일한 VERSION파일이 다른 프로그램, 심지어 비 Python 파일에서도 동일 하게 작동하며 모든 프로그램에 대해 한 곳에서 버전 문자열 만 변경하면됩니다.

설치 중 경쟁 조건에 대한 경고

그건 그렇고, 다른 대답에서 제안 된 것처럼 setup.py에서 패키지를 가져 오지 마십시오. 패키지의 종속성이 이미 설치되어 있기 때문에 효과가있는 것처럼 보이지만 패키지의 새로운 사용자에게 혼란을 줄 수 있습니다 종속성을 수동으로 설치하지 않으면 패키지를 설치할 수 없습니다.


답변

예시 연구 : mymodule

이 구성을 상상해보십시오.

setup.py
mymodule/
        / __init__.py
        / version.py
        / myclasses.py

그런 다음 의존성이 있고 setup.py다음과 같은 일반적인 시나리오를 상상하십시오 .

setup(...
    install_requires=['dep1','dep2', ...]
    ...)

그리고 예 __init__.py:

from mymodule.myclasses import *
from mymodule.version import __version__

그리고 예를 들면 myclasses.py:

# these are not installed on your system.
# importing mymodule.myclasses would give ImportError
import dep1
import dep2

문제 # 1 : 가져 오기 mymodule 설정 중

귀하의 경우 setup.py수입은 mymodule다음 설치하는 동안 당신은 일 가능성을 얻을 것ImportError . 패키지에 종속성이있는 경우 매우 일반적인 오류입니다. 패키지에 내장 이외의 다른 종속성이없는 경우 안전 할 수 있습니다. 그러나 이것은 좋은 습관이 아닙니다. 그 이유는 미래에 대비할 수 없기 때문입니다. 내일 코드에서 다른 종속성을 사용해야한다고 말하십시오.

문제 # 2 : 나의 어디에 __version__ ?

당신이 하드 코딩하는 경우 __version__setup.py그것은 당신이 당신의 모듈에 출시 할 것이라는 버전과 일치하지 않을 수 있습니다. 일관성을 유지하려면 한 장소에 놓고 필요할 때 같은 장소에서 읽으십시오. 사용import 하면 문제 # 1이 발생할 수 있습니다.

해결책 : à la setuptools

당신의 조합을 사용 open, exec그리고에 대한 딕셔너리를 제공하는 exec추가 변수 :

# setup.py
from setuptools import setup, find_packages
from distutils.util import convert_path

main_ns = {}
ver_path = convert_path('mymodule/version.py')
with open(ver_path) as ver_file:
    exec(ver_file.read(), main_ns)

setup(...,
    version=main_ns['__version__'],
    ...)

그리고 mymodule/version.py버전 을 공개하십시오 :

__version__ = 'some.semantic.version'

이 방법으로, 버전은 모듈과 함께 제공되며, 설치 중에 종속성이없는 모듈을 가져 오려고 시도하는 동안 문제가 발생하지 않습니다 (아직 설치해야 함).


답변

가장 좋은 방법은 __version__제품 코드에서 정의한 다음 거기에서 setup.py로 가져 오는 것입니다. 이를 통해 실행중인 모듈에서 읽을 수있는 값을 정의 할 수있는 위치는 한 곳뿐입니다.

setup.py의 값이 설치되어 있지 않으며 설치 후 setup.py가 붙어 있지 않습니다.

coverage.py에서 내가 한 일 (예 🙂

# coverage/__init__.py
__version__ = "3.2"


# setup.py
from coverage import __version__

setup(
    name = 'coverage',
    version = __version__,
    ...
    )

업데이트 (2017) : coverage.py가 더 이상 버전을 가져 오기 위해 가져 오지 않습니다. 제품 코드는 setup.py가 설치되어 있기 때문에 아직 설치되지 않은 종속성을 가져 오려고하기 때문에 고유 코드를 가져 오면 제거 할 수 있습니다.


답변

귀하의 질문은 약간 모호하지만, 당신이 묻는 것은 그것을 지정하는 방법이라고 생각합니다.

다음 __version__과 같이 정의해야합니다 .

__version__ = '1.4.4'

그런 다음 setup.py가 방금 지정한 버전에 대해 알고 있음을 확인할 수 있습니다.

% ./setup.py --version
1.4.4


답변

나는이 답변에 만족하지 못했습니다 … setuptools를 필요로하지 않고 단일 변수에 대해 별도의 모듈을 만들지 않기 때문에 이것들을 생각해 냈습니다.

메인 모듈이 pep8 스타일이고 확실하게 유지 될 때 :

version = '0.30.unknown'
with file('mypkg/mymod.py') as f:
    for line in f:
        if line.startswith('__version__'):
            _, _, version = line.replace("'", '').split()
            break

추가로주의를 기울이고 실제 파서를 사용하려는 경우 :

import ast
version = '0.30.unknown2'
with file('mypkg/mymod.py') as f:
    for line in f:
        if line.startswith('__version__'):
            version = ast.parse(line).body[0].value.s
            break

setup.py는 다소 낡은 모듈이므로 조금 추한 경우에는 문제가되지 않습니다.


업데이트 : 재미있었습니다. 최근 몇 년 동안이에서 멀어지고 패키지에서 별도의 파일을 사용하기 시작했습니다 meta.py. 나는 자주 변경하고 싶을 정도로 많은 메타 데이터를 거기에 넣었다. 따라서 하나의 가치 만이 아닙니다.


답변

소스 트리에서 파일을 작성하십시오 (예 : yourbasedir / yourpackage / _version.py). 해당 파일에 다음과 같이 한 줄의 코드 만 포함 시키십시오.

__version__ = "1.1.0-r4704"

그런 다음 setup.py에서 해당 파일을 열고 다음과 같이 버전 번호를 구문 분석하십시오.

verstr = "알 수 없음"
시험:
    verstrline = open ( 'yourpackage / _version.py', "rt"). read ()
EnvironmentError를 제외하고 :
    pass # 좋아요, 버전 파일이 없습니다.
그밖에:
    VSRE = r "^ __ version__ = [ '\"] ([^'\ "] *) [ '\"] "
    mo = 재검색 (VSRE, verstrline, re.M)
    mo 인 경우 :
        verstr = mo.group (1)
    그밖에:
        런타임 오류 발생 ( "package / _version.py에서 버전을 찾을 수 없음")

마지막으로 yourbasedir/yourpackage/__init__.pyimport _version에서 다음과 같이하십시오.

__version__ = "알 수 없음"
시험:
    _version import __version__에서
ImportError를 제외하고 :
    # _version.py가없는 트리에서 실행 중이므로 버전이 무엇인지 모릅니다.
    통과하다

이를 수행하는 코드의 예는 내가 관리하는 “pyutil”패키지입니다. (PyPI 또는 Google 검색 참조-stackoverflow로 인해이 답변에 하이퍼 링크가 포함되지 않습니다.)

@pjeby는 자신의 setup.py에서 패키지를 가져 와서는 안됩니다. 새로운 파이썬 인터프리터를 만들고 setup.py를 먼저 실행하여 테스트 할 때 작동 python setup.py하지만 작동하지 않는 경우가 있습니다. 의 때문 import youpackage“yourpackage”라는 이름의 디렉토리에 대한 현재 작업 디렉토리를 읽을 것을 의미하지 않는다, 현재에 보는 의미 sys.modules핵심 “yourpackage”에 대한 한 후이없는 경우 다양한 일을 할 수 있습니다. 따라서 python setup.py비어 sys.modules있고 비어 있기 때문에 항상 작동 하지만 일반적으로는 작동하지 않습니다.

예를 들어 py2exe가 응용 프로그램을 패키징하는 과정의 일부로 setup.py를 실행중인 경우 어떻게해야합니까? 패키지가 버전 번호를 가져 오기 때문에 py2exe가 패키지에 잘못된 버전 번호를 넣는 경우를 보았습니다.import myownthingsetup.py에 있지만 py2exe 실행 중에 해당 패키지의 다른 버전을 이전에 가져 왔습니다. 마찬가지로 setuptools, easy_install, distribution 또는 distutils2가 사용자에 따라 다른 패키지를 설치하는 프로세스의 일부로 패키지를 빌드하려고하면 어떻게합니까? 그런 다음 setup.py를 평가할 때 패키지를 가져올 수 있는지 또는이 Python 인터프리터 수명 동안 가져온 패키지 버전이 있는지 또는 패키지를 가져 오기 위해 다른 패키지를 먼저 설치해야하는지 여부 부작용이 있거나 결과가 바뀔 수 있습니다. py2exe 및 setuptools와 같은 도구에서 setup.py가 버전 번호를 찾기 위해 패키지 자체를 가져 오기 때문에 py2exe 및 setuptools와 같은 도구에 문제를 일으키는 Python 패키지를 재사용하려고 시도하는 데 어려움을 겪었습니다.

그건 그렇고,이 기술은 yourpackage/_version.py수정 제어 기록을 읽고 수정 제어 기록의 최신 태그를 기반으로 버전 번호를 작성하는 등 자동으로 파일 을 자동으로 생성하는 도구와 함께 잘 작동 합니다. 다음은 darcs에 해당하는 도구입니다. http://tahoe-lafs.org/trac/darcsver/browser/trunk/README.rst 여기 git에 대해 동일한 작업을 수행하는 코드 스 니펫이 있습니다. http : // github .com / warner / python-ecdsa / blob / 0ed702a9d4057ecf33eea969b8cf280eaccd89a1 / setup.py # L34


답변

정규식을 사용하고 메타 데이터 필드에 따라 다음과 같은 형식을 갖도록 작동해야합니다.

__fieldname__ = 'value'

setup.py의 시작 부분에서 다음을 사용하십시오.

import re
main_py = open('yourmodule.py').read()
metadata = dict(re.findall("__([a-z]+)__ = '([^']+)'", main_py))

그런 다음 스크립트에서 메타 데이터를 다음과 같이 사용할 수 있습니다.

print 'Author is:', metadata['author']
print 'Version is:', metadata['version']