setup.py 包和unicode_literals

5 投票
3 回答
2733 浏览
提问于 2025-04-18 03:25

我在Python 2.7中创建了一个包,现在想让它能在Python 3中使用。问题是,如果我在

__init__.py

中加入unicode_literals,构建的时候就会出现这个错误

error in daysgrounded setup command: package_data must be a dictionary mapping
package names to lists of wildcard patterns

我看过PEP文档,但我不太明白它和像这样的字典有什么关系

__pkgdata__

有没有人能帮帮我?

__init__.py
#!/usr/bin/env python
# -*- coding: latin-1 -*-

"""Manage child(s) grounded days."""

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
# ToDo: correct why the above unicode_literals import prevents setup.py from working

import sys
from os import path
sys.path.insert(1, path.dirname(__file__))

__all__ = ['__title__', '__version__',
           '__desc__', '__license__', '__url__',
           '__author__', '__email__',
           '__copyright__',
           '__keywords__', '__classifiers__',
           #'__packages__',
           '__entrypoints__', '__pkgdata__']

__title__ = 'daysgrounded'
__version__ = '0.0.9'

__desc__ = __doc__.strip()
__license__ = 'GNU General Public License v2 or later (GPLv2+)'
__url__ = 'https://github.com/jcrmatos/DaysGrounded'

__author__ = 'Joao Matos'
__email__ = 'jcrmatos@gmail.com'

__copyright__ = 'Copyright 2014 Joao Matos'

__keywords__ = 'days grounded'
__classifiers__ = [# Use below to prevent any unwanted publishing
                   #'Private :: Do Not Upload'
                   'Development Status :: 4 - Beta',
                   'Environment :: Console',
                   'Environment :: Win32 (MS Windows)',
                   'Intended Audience :: End Users/Desktop',
                   'Intended Audience :: Developers',
                   'Natural Language :: English',
                   'Natural Language :: Portuguese',
                   'License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)',
                   'Operating System :: OS Independent',
                   'Programming Language :: Python',
                   'Programming Language :: Python :: 2.7',
                   'Programming Language :: Python :: 3.4',
                   'Topic :: Other/Nonlisted Topic']

#__packages__ = ['daysgrounded']

__entrypoints__ = {
    'console_scripts': ['daysgrounded = daysgrounded.__main__:main'],
    #'gui_scripts': ['app_gui = daysgrounded.daysgrounded:start']
    }

__pkgdata__ = {'daysgrounded': ['*.txt']}
#__pkgdata__= {'': ['*.txt'], 'daysgrounded': ['*.txt']}


setup.py
#!/usr/bin/env python
# -*- coding: latin-1 -*-

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

from setuptools import setup, find_packages
#import py2exe

#from daysgrounded import *
from daysgrounded import (__title__, __version__,
                          __desc__, __license__, __url__,
                          __author__, __email__,
                          __keywords__, __classifiers__,
                          #__packages__,
                          __entrypoints__, __pkgdata__)

setup(
    name=__title__,
    version=__version__,

    description=__desc__,
    long_description=open('README.txt').read(),
    #long_description=(read('README.txt') + '\n\n' +
    #                  read('CHANGES.txt') + '\n\n' +
    #                  read('AUTHORS.txt')),
    license=__license__,
    url=__url__,

    author=__author__,
    author_email=__email__,

    keywords=__keywords__,
    classifiers=__classifiers__,

    packages=find_packages(exclude=['tests*']),
    #packages=__packages__,

    entry_points=__entrypoints__,
    install_requires=open('requirements.txt').read(),
    #install_requires=open('requirements.txt').read().splitlines(),

    include_package_data=True,
    package_data=__pkgdata__,

    #console=['daysgrounded\\__main__.py']
)

谢谢,

JM

3 个回答

0

unicode_literals的使用是为了让Python 3的代码在兼容Python 2时更顺利。在Python 2中,str是字节字符串,而在Python 3中,str变成了Unicode字符串。这种做法可以有效避免字节字符串和Unicode字符串混在一起的问题,这在Python 2中是个长期存在的麻烦。不过,这里也有一些需要注意的地方,比如这个问题。

Kevin解释了这个bug,我觉得在setup.py中并不是绝对必要的去修复它,特别是当你有很多package_data的条目时,修复起来会有点麻烦。


如果你想在setup.py中保留unicode_literals,你只需要把dict的键编码成字节字符串:

__pkgdata__ = {b'daysgrounded': ['*.txt']}

但是在Python 3中,这样做会出现相同的错误信息,所以需要同时兼顾两个版本:

if sys.version_info.major == 2:
    __pkgdata__ = {b'daysgrounded': ['*.txt']}
else:
    __pkgdata__ = {'daysgrounded': ['*.txt']}

另外,你也可以使用来自future模块的bytes_to_native_str

from future.utils import bytes_to_native_str

__pkgdata__ = {bytes_to_native_str(b'daysgrounded'): ['*.txt']}
3

这是setuptools中的一个错误。它在检查值的时候用到了 isinstance(k, str),但是当字符串被 unicode_literals 导入后转变成2.x的 unicode 类时,这个检查就会失败。应该修正为使用 isinstance(k, basestring)

最简单的解决办法是把配置设置直接放在 setup.py 文件里,而不是放在 __init__.py 里。如果你需要以编程方式访问 __version__,那么可以把它放在一个单独的包里,这个包同时被 setup.py__init__.py 引用。

来自setuptools的dist.py:

def check_package_data(dist, attr, value):
    """Verify that value is a dictionary of package names to glob lists"""
    if isinstance(value,dict):
        for k,v in value.items():
            if not isinstance(k,str): break
            try: iter(v)
            except TypeError:
                break
        else:
        return
    raise DistutilsSetupError(
        attr+" must be a dictionary mapping package names to lists of "
        "wildcard patterns"
   )
6

使用 unicode_literals 就相当于在你的输入文件中的每个字符串前面加上 u'...',这意味着在你的 __init__.py 文件中指定的内容

__pkgdata__ = {'daysgrounded': ['*.txt']}

实际上和下面的内容是一样的

__pkgdata__ = {u'daysgrounded': [u'*.txt']}

在 Python 2 中,setuptools 这里不需要 unicode 类型,而是需要 str 类型,所以会出错。

看起来你在 __init__.py 文件中的字符串里并没有使用任何 Unicode 字符,都是普通的 ASCII 字符,所以你可以直接去掉 unicode_literals 的导入。如果你在文件的其他地方确实用到了 Unicode 字符,而这些地方没有在你的帖子中显示出来,那就在那里使用明确的 Unicode 字符。

撰写回答