Python setuptools依赖项和导入问题

Python setuptools依赖项和导入问题,python,setuptools,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,

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

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

你不能这样做吗

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

否则,您可以尝试在init.py中编写版本,但老实说,我不知道这是否是一种好的做法。

您不能这样做吗

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

否则,您可以尝试在init.py中编写版本,但老实说,我不知道这是否是一种好的做法。

作为一般规则,不要从
setup.py
导入包,因为(正如您所意识到的)如果您尚未安装所有依赖项,则无法安装包

相反,按照建议,创建一个单独的模块
version.py
(或类似模块),而不需要定义
version
。在您的
setup.py
do
execfile('mypackage/version.py')
中,您可以访问
version
,而无需任何恶意或不安全的黑客攻击

正如medmunds指出的那样,
execfile
在Python 3中不可用,因此请改用:

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

一般来说,不要从
setup.py
导入软件包,因为(正如您所意识到的那样)如果您尚未安装所有依赖项,则无法安装软件包

相反,按照建议,创建一个单独的模块
version.py
(或类似模块),而不需要定义
version
。在您的
setup.py
do
execfile('mypackage/version.py')
中,您可以访问
version
,而无需任何恶意或不安全的黑客攻击

正如medmunds指出的那样,
execfile
在Python 3中不可用,因此请改用:

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

在提出这个问题后,我发布了几个月以来一直在使用的解决方案。感谢kynan间接地提醒我回答这个问题。虽然kynan发布的解决方案很棒,但我个人不喜欢只为版本号添加一个文件,因为这意味着版本号将保存在package.version.version下的程序中。指示版本号应位于包或模块名称空间的顶级,位于名称
\uuuuu version\uuuuu

我现在使用的解决方案使用一个简单的正则表达式来解析python程序中定义
\uuuuu version\uuuu
的行中的版本号。它看起来像:

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


在提出这个问题后,我发布了几个月以来一直在使用的解决方案。感谢kynan间接地提醒我回答这个问题。虽然kynan发布的解决方案很棒,但我个人不喜欢只为版本号添加一个文件,因为这意味着版本号将保存在package.version.version下的程序中。指示版本号应位于包或模块名称空间的顶级,位于名称
\uuuuu version\uuuuu

我现在使用的解决方案使用一个简单的正则表达式来解析python程序中定义
\uuuuu version\uuuu
的行中的版本号。它看起来像:

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


虽然其他人恰当地指出,从setup.py导入您自己的包不是一个很好的做法,但在某些情况下,这种情况会以不同的方式出现——实际的安装过程需要一些包,这些包在所有依赖项安装完成后才可用

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

from setuptools import setup

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

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

而其他人则适当地指出,从setup.py导入您自己的软件包不是一个很好的做法,在某些情况下,这种情况会以不同的方式出现——实际的安装过程需要一些软件包,这些软件包在安装完所有依赖项之后才可用

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

from setuptools import setup

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

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

此方法遇到相同的问题:
pkg\u resources.DistributionNotFound:six
。事实上,您不应该需要six,而应该需要“mypackage”!是的,我在那里就是这么做的。mypackage.\uuuu init\uuuuuuuuuy.py包含行
import six
,因此该错误和原始问题。此方法遇到相同的问题:
pkg\u resources.DistributionNotFound:six
。事实上,您不应该需要六行,而是需要“mypackage”!是的,我在那里就是这么做的。mypackage.\uuuuu init\uuuuuuuuuy.py包含行
import six
,因此出现了错误和原始问题。我忘了我发布了这个问题。另一个线程有一些很好的建议,其中一个类似于我现在的做法。很快添加我的解决方案。我对
execfile
解决方案非常满意,但它在Python 3上不起作用。好的,对于Python 2和3,使用
和open('mypackage/version.py')作为f:exec(f.read())
代替
execfile('mypackage/version.py')
。我忘了我贴了这封信