2012-02-06 16 views
10

Tengo un problema al distribuir una aplicación que utiliza pytz. Estoy usando Py2Exe para crear un ejecutable desde mi fuente de Python.DesconocidoTimezoneExcepción de error provocada con la aplicación Python compilada con Py2Exe

Para un simple ejemplo del problema que estoy teniendo, que 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 corro setup.py :

python setup.py py2exe 

Que compila el ejecutable. Ejecución de la creado pytz_test.exe me sale:

supongo que se debe a que la información de zona horaria no se está incluido con el ejecutable, pero no estoy seguro de cómo hacer que suceda.

EDIT: Una solución sencilla sería la de agregar el directorio de información de zonas , desde el módulo pytz en el directorio site-packages de Python, a la library.zip.

Para hacer esto automáticamente, he seguido la solución en ese proyecto RSS Google Transit datos utilizado, a partir de: http://code.google.com/p/googletransitdatafeed/source/browse/trunk/python/setup.py

Mi modificado setup.py ahora queda 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() 
+0

También necesita una versión actual de setuptools. Específicamente pkg_resources. 'import pkg_resources' no debe fallar. – sbaechler

+0

¿Dónde exactamente se usa 'pkg_resources'? o simplemente importándolo? – Triztian

Respuesta

3

Una solución simple sería agregar el directorio zoneinfo, desde el módulo pytz en los paquetes de sitio python directorio, al library.zip.

Para hacer esto automáticamente, he seguido la solución del proyecto Google tránsito de feeds de datos utilizado, a partir de:

Mi modificado setup.py ahora queda 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 asker)

2

Comprimir el zoneinfo manualmente (como lo describe Jason S) ayudo a buildin g el paquete en una de mis computadoras. Sin embargo, cuando construí el paquete en otra computadora, ¡el error volvió! Encontrar el motivo me llevó un tiempo, así que será mejor que lo comparta.

¡La solución propuesta no funciona con las nuevas versiones de pytz (al menos con 2014.7)! Excavando por qué se revela que pytz cambió el formato de los archivos zoneinfo de pyc a algún formato binario.Para mí, parece que con este cambio "rompieron" la opción de empaquetar pytz en un zip, ya que el mecanismo integrado de python para el zipimport no funciona para cargar archivos binarios. En realidad, este problema debe ser fijado por pytz pero por ahora he encontrado otra solución:

  • sólo tienes que copiar el directorio pytz entera directamente en el directorio dist
  • dentro de su programa, agregue la ruta de su man- exectutable a la ruta de búsqueda de Python

en la práctica, esto significa dentro de su setup.py sustituir el pytz-comprimir 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 mover pytz de los "paquetes" -opción a "excluye":

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

En la entrada principal de su programa (para asegurarse de que se ejecuta antes de pytz importador), habría que añadir algo como:

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

Esto funciona para mí (pytz 2014.10), pero tuve que eliminar todas las ignoraciones de shutil.copytree(). – Geotob

+0

¡Sí! ¡Funcionó! Lo más extraño, sin embargo, es que mi pytz con py2exe estaba funcionando. Luego modifiqué algunas cosas en mi programa, sin relación alguna con pytz, y de repente dejó de funcionar y dio las palabras UnkownTimeZoneError – wordsforthewise

+0

por cierto, ¡exactamente! Ese fue mi problema, también. Y dado que (al menos para mí) no siempre es obvio qué hace py2exe y cómo recopila sus cosas, incluso tuve que hackear las impresiones de depuración en pytz para averiguar qué salió mal durante la fase de recopilación de py2exe. :-) – Zappotek

Cuestiones relacionadas