2012-03-23 82 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']) 

这实际上下载六本地副本可用,而在安装过程中运行。它还将正确安装六个到当前环境中,以便在安装过程完成后可供使用。