Возникла исключительная ситуация UnknownTimezoneError с приложением Python, скомпилированным с Py2Exe - PullRequest
11 голосов
/ 06 февраля 2012

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

Для простого примера возникшей проблемы у меня есть: 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 Я получаю:

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

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

РЕДАКТИРОВАТЬ: простое решение было бы добавить каталог zoneinfo из модуля pytz в каталоге python site-packages, в library.zip .

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

Myизмененный 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()

Ответы [ 2 ]

3 голосов
/ 02 августа 2014

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

Чтобы сделать это автоматически, я следовал решению, которое использовал проект Канал данных Google Transit , из: 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()

(ответ от автора)

2 голосов
/ 27 октября 2014

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

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

  • Просто скопируйте весь каталог pytz прямо в ваш каталог dist
  • в вашей программе, добавьте путь вашего main-exjectutable к пути поиска python

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

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 из опции "packages" в "exclude":

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