2012-03-23 80 views
2

我是半新在Python setuptools的。我最近添加了一個依賴項到我的項目中,並遇到依賴問題。這裏的問題:setuptools的依賴和進口問題

try: 
    from setuptools import setup 
except ImportError: 
    from distutils.core import setup 

from mypackage import VERSION 

setup(
    name='mypackage', 
    ... 
    version=VERSION, 
    packages=['mypackage'], 
    install_requires=['six']) 

的問題是,mypackage進口six,從而setup.py執行全新安裝失敗(六是尚未安裝)由於from mypackage import VERSION線。我曾在一個虛擬的模塊導入(如下圖所示)黑客解決了這個問題,但我真的希望有不要求我保持在兩個位置中的版本號或一個單獨的文件更好的辦法。

try: 
    import six 
except ImportError: 
    # HACK so we can import the VERSION without needing six first 
    import sys 
    class HackObj(object): 
     def __call__(*args): 
      return HackObj() 
     def __getattr__(*args): 
      return HackObj() 
    sys.modules['six'] = HackObj() 
    sys.modules['six.moves'] = HackObj() 

回答

1

我張貼,我一直在使用,因爲提出這個問題後,許多個月的方案。感謝kynan間接促使我爲這個問題提供答案。雖然張貼的解決方案kynan是偉大的,我個人不喜歡添加一個單獨的文件只是一個版本號,因爲它意味着版本號將被保存下package.version.version程序。 PEP 396表明版本號應該在名稱__version__下一個包或模塊的名稱空間的頂層。

溶液我現在用使用一個簡單的正則表達式來從在限定__version__ Python程序行解析的版本號。它看起來像:

import os 
import re 

PACKAGE_NAME = 'thepackage' 
HERE = os.path.abspath(os.path.dirname(__file__)) 
INIT = open(os.path.join(HERE, PACKAGE_NAME, '__init__.py')).read() 
README = open(os.path.join(HERE, 'README.md')).read() 

VERSION = re.search("__version__ = '([^']+)'", INIT).group(1) 

過程可用於模塊相似,

INIT = open(os.path.join(HERE, '{0}.py'.format(PACKAGE_NAME))).read() 
0

難道你不能這樣做嗎?

from pkg_resources import require 
version = require("module_name")[0].version 

否則,你可以嘗試寫在初始化的.py的版本,但我不知道這是否是一個很好的做法,真的。

+0

此方法存在同樣的問題:'pkg_resources.DistributionNotFound:six'。 – bboe 2012-03-24 07:11:25

+0

事實上,你不應該需要六個,但「mypackage」! – luke14free 2012-03-24 11:58:28

+0

是的,那是我在那裏做的。 mypackage.__init__.py包含'import six'這一行,因此這個錯誤和原始問題。 – bboe 2012-03-24 15:25:41

2

作爲一般規則,請勿從setup.py導入您的軟件包,因爲(如您所知),如果您尚未安裝所有依賴項,則無法安裝軟件包。

相反,如建議in this answer,創建一個單獨的模塊version.py(或類似)而不定義VERSION任何外部依賴。在你做setup.pyexecfile('mypackage/version.py')瞧你有機會獲得VERSION沒有任何討厭的或不安全的黑客。

由於medmunds指出execfile不是在Python 3可用,所以改用:

with open('mypackage/version.py') as f: 
    exec(f.read()) 
+0

我忘了我發佈了這個問題。那個線程有一些很棒的建議,其中一個與我現在的做法很相似。儘快添加我的解決方案 – bboe 2012-12-08 03:52:57

+0

對'execfile'解決方案真的很滿意,但它對Python 3不起作用。 – medmunds 2013-03-05 04:48:22

+0

對於Python 2 *和* 3,使用'with open('mypackage/version.py')作爲f:exec(f .read())'代替'execfile('mypackage/version.py')''。 (來自http://stackoverflow.com/a/437857/647002) – medmunds 2013-03-05 05:19:42

0

更換

INIT = open(os.path.join(HERE, PACKAGE_NAME, '__init__.py')).read() 

雖然其他人指出適當地從setup.py ISN導入您自己的包這是一種非常好的做法,有些情況下這種情況會以不同的方式出現 - 實際的安裝過程需要一些包,直到安裝完成後才能使用所有的依賴完成。

在這些情況下,setuptools的提供soluiton:

from setuptools import setup 

setup(
name='mypackage', 
... 
version=VERSION, 
packages=['mypackage'], 
setup_requires=['six'], 
install_requires=['six']) 

這實際上下載六本地副本可用,而在安裝過程中運行。它還將正確安裝六個到當前環境中,以便在安裝過程完成後可供使用。