setuptools依赖和导入问题

时间:2012-03-23 19:04:02

标签: python setuptools

我是python中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,因此from mypackage import VERSION行导致全新安装(其中六个尚未安装)的setup.py失败。我通过黑客入侵虚拟模块导入解决了这个问题(见下文),但我真的希望有一种更好的方法,不需要我在两个位置或单独的文件中维护版本号。

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()

4 个答案:

答案 0 :(得分:2)

作为一般规则,请勿从setup.py导入您的软件包,因为(如您所知),如果您尚未安装所有依赖项,则无法安装软件包。

相反,按照建议in this answer,创建一个单独的模块version.py(或类似的),没有任何外部依赖定义VERSION。在setup.py执行execfile('mypackage/version.py'),您可以访问VERSION,而不会遇到任何令人讨厌或不安全的黑客攻击。

正如medmunds指出的那样{3}中没有execfile,所以改为使用:

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

答案 1 :(得分: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, PACKAGE_NAME, '__init__.py')).read()

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

答案 2 :(得分:0)

难道你不能这样做吗?

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

否则你可以尝试在 init .py中编写版本,但我不知道这是不是一个好习惯,老实说。

答案 3 :(得分:0)

虽然其他人已经恰当地指出从setup.py导入你自己的软件包并不是一种非常好的做法,但是有些情况会以不同的方式出现这种情况 - 实际的安装过程需要一些软件包在完成所有依赖项的安装之前,它将无法使用。

在这些情况下,setuptools提供了一个解决方案:

from setuptools import setup

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

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