UnknownTimezoneError Excepción generada con la aplicación Python comstackda con Py2Exe

Tengo un problema para distribuir una aplicación que utiliza pytz . Estoy usando Py2Exe para crear un ejecutable desde mi fuente de Python.

Para un ejemplo simple del problema que tengo, tengo: pytz_test.py:

import pytz tz_au = pytz.timezone("Australia/Sydney") print tz_au 

y en setup.py:

 from distutils.core import setup import py2exe setup(console=['pytz_test.py'], options={"py2exe" : { 'packages': ['pytz'], } }) 

Entonces ejecuto setup.py:

 python setup.py py2exe 

Que comstack el ejecutable. Ejecutando el pytz_test.exe creado obtengo:

 Traceback (most recent call last): File "pytz_test.py", line 3, in  tz_au = pytz.timezone("Australia/Sydney") File "pytz\__init__.pyc", line 185, in timezone pytz.exceptions.UnknownTimeZoneError: 'Australia/Sydney' 

Supongo que es porque la información de la zona horaria no se está empaquetando con el ejecutable, pero no estoy seguro de cómo hacerlo.

EDITAR: una solución simple sería agregar el directorio zoneinfo , desde el módulo pytz en el directorio python site-packages, a library.zip .

Para hacer esto automáticamente, seguí la solución en el proyecto que usaba Google Transit Data Feed , desde: http://code.google.com/p/googletransitdatafeed/source/browse/trunk/python/setup.py

Mi setup.py modificado ahora se ve como:

 from distutils.core import setup import glob import py2exe options = { "py2exe" : { "compressed": 1, "optimize": 2, 'packages': ['pytz'], } } setup(console=['pytz_test.py'], options=options) import pytz import os import zipfile zipfile_path = os.path.join("dist/" 'library.zip') z = zipfile.ZipFile(zipfile_path, 'a') zoneinfo_dir = os.path.join(os.path.dirname(pytz.__file__), 'zoneinfo') disk_basedir = os.path.dirname(os.path.dirname(pytz.__file__)) for absdir, directories, filenames in os.walk(zoneinfo_dir): assert absdir.startswith(disk_basedir), (absdir, disk_basedir) zip_dir = absdir[len(disk_basedir):] for f in filenames: z.write(os.path.join(absdir, f), os.path.join(zip_dir, f)) z.close() 

Una solución simple sería agregar el directorio zoneinfo , desde el módulo pytz en el directorio python site-packages, a library.zip .

Para hacer esto automáticamente, seguí la solución que usaba Google Transit Data Feed , desde: http://code.google.com/p/googletransitdatafeed/source/browse/trunk/python/setup.py

Mi setup.py modificado ahora se ve como:

 from distutils.core import setup import glob import py2exe options = { "py2exe" : { "compressed": 1, "optimize": 2, 'packages': ['pytz'], } } setup(console=['pytz_test.py'], options=options) import pytz import os import zipfile zipfile_path = os.path.join("dist/" 'library.zip') z = zipfile.ZipFile(zipfile_path, 'a') zoneinfo_dir = os.path.join(os.path.dirname(pytz.__file__), 'zoneinfo') disk_basedir = os.path.dirname(os.path.dirname(pytz.__file__)) for absdir, directories, filenames in os.walk(zoneinfo_dir): assert absdir.startswith(disk_basedir), (absdir, disk_basedir) zip_dir = absdir[len(disk_basedir):] for f in filenames: z.write(os.path.join(absdir, f), os.path.join(zip_dir, f)) z.close() 

(Respondido por el que pregunta)

La compresión manual de la zona (como lo describe Jason S) ayudó a crear el paquete en una de mis computadoras. Sin embargo, cuando construí el paquete en otra computadora, ¡el error estaba de vuelta! Encontrar la razón me tomó un tiempo, así que es mejor que comparta.

¡La solución propuesta no funciona con las nuevas versiones de pytz (al menos con 2014.7)! Averiguar por qué se revela esto, pytz cambió el formato de los archivos zoneinfo de pyc a algún formato binario. A mi parecer, con este cambio, “rompieron” la opción de empaquetar pytz en un archivo zip, ya que el mecanismo zipimport integrado de python no funciona para cargar archivos binarios. En realidad, este problema debería ser solucionado por pytz pero por ahora encontré otra solución:

  • Simplemente copie el directorio pytz completo directamente en su directorio dist
  • dentro de su progtwig, agregue la ruta de acceso principal de la ruta de búsqueda de python

En la práctica, esto significa que dentro de tu setup.py reemplaza el pytz-zipping con

 import pytz, os, shutil srcDir = os.path.dirname( pytz.__file__ ) dstDir = os.path.join( 'dist', 'pytz' ) shutil.copytree( srcDir, dstDir, ignore = shutil.ignore_patterns('*.py') ) 

y mueva pytz de la opción “paquetes” a “excluye”:

 options = { "py2exe" : { "compressed": 1, "optimize": 2, "packages": [], "excludes": ['pytz'] } } 

En la entrada principal de tu progtwig (para asegurarte de que se ejecuta antes de importar pytz), deberías agregar algo como:

 import os, sys basePath = os.path.dirname( os.path.abspath( sys.argv[0] ) ) sys.path.insert( 0, basePath )