2012-02-06 1 views
10

У меня возникла проблема с распространением приложения, которое использует pytz. Я использую Py2Exe, чтобы создать исполняемый файл из моего источника Python.UnknownTimezoneError Exception, созданный с помощью приложения Python, составленного с Py2Exe

Для простого примера проблема, у меня, у меня есть: pytz_test.py:

import pytz 

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

и в setup.py:

from distutils.core import setup 
import py2exe 

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

тогда я бегу setup.py :

python setup.py py2exe 

Что скомпилирует исполняемый файл. Запуск созданного pytz_test.exe я получаю:

Я предполагаю, что это потому, что информация о часовом поясе не получает в комплекте с исполняемым файлом, но я не знаю, как это произошло.

EDIT: простое решение было бы добавить каталог ZoneInfo, из pytz модуля в каталоге сайта-пакетов питона, к library.zip.

Чтобы сделать это автоматически, я последовал за решение в этом проекте-канал Google Transit Data используется, начиная с: http://code.google.com/p/googletransitdatafeed/source/browse/trunk/python/setup.py

Мой модифицированный setup.py теперь выглядит следующим образом:

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

Вам также нужна текущая версия setuptools. В частности, pkg_resources. «Импорт pkg_resources» не должен прерываться. – sbaechler

+0

Где именно используется 'pkg_resources'? или просто импортируя его? – Triztian

ответ

3

Простым решением было бы добавить каталог zoneinfo, из модуля pytz в пакетах сайтов python справочник, до library.zip.

Чтобы сделать это автоматически, я последовал за решение проект Google Transit Data Feed используется, начиная с:

Мои модифицирована setup.py теперь выглядит следующим образом:

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

(Ответил asker)

2

Zipping zoneinfo вручную (как описано Джейсоном S) действительно помог построить g пакет на одном из моих компьютеров. Однако, когда я построил пакет на другом компьютере - ошибка вернулась! Нахождение причины заняло у меня некоторое время - так что мне лучше поделиться.

Предлагаемое решение не работает с новыми версиями pytz (по крайней мере, с 2014.7)! Копаем, почему выясняется, что pytz изменил формат файлов zoneinfo с pyc на некоторый двоичный формат.Для меня это похоже, с этим изменением они «сломали» вариант пакет pytz в zip, так как встроенный механизм zipimport python не работает для загрузки двоичных файлов. На самом деле, эта проблема должна быть решена pytz но сейчас я нашел другое решение:

  • Просто скопировать весь каталог pytz непосредственно в папку Dist
  • в вашей программе, добавьте путь к вашему Main- exectutable на пути поиска питона

практически, это означает, что в вашем setup.py заменить pytz-проносясь с

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

и двигаться pytz из «пакетов» -Возможность «исключает»:

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

На главном входе вашей программы (чтобы убедиться, что она выполняется перед импортом pytz), вы бы добавить что-то например:

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

Это работает для меня (pytz 2014.10), но мне пришлось удалить все игнорирования из shutil.copytree(). – Geotob

+0

Да! Это сработало! Самое странное, что мой pytz с py2exe работает. Затем я изменил некоторые вещи в своей программе, совершенно не связанные с pytz, и вдруг он перестал работать и точно дал слова UnkownTimeZoneError – wordsforthewise

+0

, в точности! Это тоже моя проблема. И поскольку (по крайней мере для меня) не всегда очевидно, что делает py2exe и как он собирает свои вещи, мне даже пришлось взломать отладочные отпечатки в pytz, чтобы узнать, что пошло не так во время фазы сбора py2exe. :-) – Zappotek