2012-02-06 12 views
10

Sto riscontrando un problema nella distribuzione di un'applicazione che utilizza pytz. Sto usando Py2Exe per creare un eseguibile dalla mia fonte Python.UnknownTimezoneError Eccezione generata con Python Applicazione compilata con Py2Exe

Per un semplice esempio del problema che sto avendo, ho: pytz_test.py:

import pytz 

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

e in setup.py:

from distutils.core import setup 
import py2exe 

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

Ho poi corro setup.py :

python setup.py py2exe 

Che compila l'eseguibile. Esecuzione del creato pytz_test.exe ottengo:

Suppongo che sia perché le informazioni fuso orario non è sempre in bundle con l'eseguibile, ma non sono sicuro di come farlo accadere.

EDIT: Una soluzione semplice sarebbe quella di aggiungere la directory zoneinfo, dal modulo pytz nella directory site-packages python, al library.zip.

per farlo automaticamente, ho seguito la soluzione in quel progetto Google Transit Data Feed usati, da: http://code.google.com/p/googletransitdatafeed/source/browse/trunk/python/setup.py

mio modificato setup.py ora assomiglia:

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

È inoltre necessaria una versione corrente di setuptools. Specificamente pkg_resources. 'import pkg_resources' non deve fallire. – sbaechler

+0

Dove si usa esattamente 'pkg_resources'? o semplicemente importandolo? – Triztian

risposta

3

Una soluzione semplice sarebbe aggiungere la directory zonainfo , dal modulo pytz nei pacchetti del sito python directory, allo library.zip.

per farlo automaticamente, ho seguito la soluzione progetto Google Transit Data Feed usati, da:

mio modificato setup.py ora assomiglia:

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

(Risposta del richiedente)

2

Zippare manualmente la zonainfo (come descritto da Jason S) è stato di grande aiuto per la creazione g il pacchetto su uno dei miei computer. Tuttavia, quando ho creato il pacchetto su un altro computer, l'errore era tornato! Trovare la ragione mi ha portato un po 'di tempo - quindi è meglio condividere.

La soluzione proposta non funziona con le nuove versioni di pytz (almeno con 2014.7)! Scavando perché è stato rivelato che pytz ha cambiato il formato dei file zoneinfo da pyc in un formato binario.A me sembra che, con questo cambiamento, abbiano "rotto" l'opzione di comprimere pytz in un file zip, poiché il meccanismo integrato zipimport di python non funziona per caricare i file binari. In realtà, questo problema dovrebbe essere risolto pytz ma per ora ho trovato un'altra soluzione:

  • basta copiare l'intera directory pytz direttamente nella directory dist
  • all'interno del programma, aggiungere il percorso del man- exectutable al percorso di ricerca di Python

In pratica, questo significa che all'interno della vostra setup.py sostituire il pytz-zippare 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')) 

e spostare pytz dai "pacchetti" -Possibilità di "esclude":

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

All'entrata principale del programma (per assicurarsi che viene eseguita prima pytz importazione), si dovrà aggiungere qualcosa ad esempio:

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

Questo funziona per me (pytz 2014.10), ma ho dovuto rimuovere tutti gli ignori da shutil.copytree(). – Geotob

+0

Sì! Ha funzionato! La cosa più strana è che il mio pytz con py2exe stava funzionando. Poi ho modificato alcune cose nel mio programma, completamente estraneo a pytz, e all'improvviso ha smesso di funzionare e ha dato l'UnkownTimeZoneError – wordsforthewise

+0

wordsfortlywise, esattamente! Questo era anche il mio problema. E dato che (almeno per me) non è sempre ovvio cosa faccia Py2exe e come raccolga le sue cose, ho persino dovuto incidere le debug in pytz per scoprire cosa è andato storto durante la fase di raccolta di py2exe. :-) – Zappotek

Problemi correlati