2014-04-19 32 views
5

Ho creato un pacchetto in Py2.7 e sto cercando di renderlo compatibile con Py3. Il problema è che se includo unicode_literals inpacchetti setup.py e unicode_literals

__init__.py 

importa i rendimenti costruire questo errore

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

Ho letto l'PEP, ma non riesco a capire che cosa ha a che fare con un Detto come

__pkgdata__ 

qualcuno può aiutare?

__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__ = '[email protected]' 

__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'] 
) 

Grazie,

JM

risposta

5

utilizzando unicode_literals è lo stesso che con u'...' per ogni stringa letterale nel file di input, il che significa che nel vostro __init__.py Precisando

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

è effettivamente lo stesso di

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

per python2, setuptools non si aspetta unicode qui ma str, quindi non riesce.

A quanto pare non si utilizzano i caratteri Unicode nelle stringhe letterali in __init__.py comunque, solo ASCII, in modo da poter rimuovere semplicemente il unicode_literals importazione. Se utilizzi davvero letterali unicode in un punto del file che non è mostrato nel tuo post, utilizza i letterali espliciti di unicode lì.

3

Questo è un bug in setuptools. Valida i valori con isinstance(k, str) che non riesce quando le stringhe vengono trasformate nella classe 2.x unicode mediante l'importazione unicode_literals. Deve essere corretto per utilizzare isinstance(k, basestring).

La soluzione più semplice è inserire le impostazioni di configurazione direttamente in setup.py anziché memorizzarle in __init__.py. Se è necessario l'accesso programmatico a __version__, inserirlo in un pacchetto separato incluso da setup.py e __init__.py.

Da 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" 
    ) 
+0

"si tratta di un bug in setuptools": Sai se esiste una segnalazione di bug? –

0

L'utilizzo di unicode_literals è quello di portare la compatibilità Python 2 a Python 3 codice in cui str è ora Unicode stringhe vs byte-stringhe in Python 2. È grande a prevenire il mix di stringhe di byte e stringhe unicode, problema di lunga data su Py2, tuttavia ci sono alcuni pitfalls come questo problema.

Kevin ha spiegato il bug e mi piacerebbe direi per setup.py non è strettamente necessario e per risolvere il problema è un po 'brutto, soprattutto se si dispone di un gran numero di voci per package_data.


Se si desidera mantenere unicode_literals in installazione.py si avrà solo bisogno di codificare la chiave dict come un byte-stringa:

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

Tuttavia in Python 3 fallirà con lo stesso messaggio in modo bisogno di coprire entrambe le versioni:

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

in alternativa utilizzare bytes_to_native_str da future modulo:

from future.utils import bytes_to_native_str 

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