четверг, 10 марта 2011 г.

wxPython + py2exe: ошибки по человечески

Предисловие
Какие бы приложения ни создавались, на разных этапах разработки и поддержки приложений случаются непредвиденные ошибки, которые нужно как-нибудь отлавливать. В этом посте речь пойдет об облагораживании десктопных приложений под windows, созданных с помощью библиотеки wxPython и завернутых в исполняемый файл с помощью py2exe.

Необходимые знания
Первое - конструктор wx.App
Итак, начнем. Первое, что нужно знать, это параметры конструктора класса приложения wx.App. В данном случае интерес представляют аргументы "redirect" и "filename".
- redirect - отвечает за перенаправление потоков стандартного вывода и потока ошибок. Если значение True (а на Windows по умолчанию так и есть), стандартный вывод будет перенаправлен.
- filename - собственно пункт назначения перенаправленного потока (см. redirect). Если значние не установлено, то есть равно None (а на Windows по умолчанию так и есть), стандартный вывод будет перенаправлен в стандартное окно (оно, как известно, состоит из текстовой области, в которую сыпятся ошибки и остальной вывод). Окно можно переопределить установив атрибут outputWindowClass экземпляра класса приложения (wx.App).

Второе - перенаправление потоков вывода
Управление стандартными потоками вывода можно осуществить через встроенный модуль sys. Доступ к ним можно получить через sys.stdout, sys.stderr. Эти переменные являют собой file-подобные объекты, в которых можно что-то писать.

Третье - предупреждения
Предупреждения (warnings) случаются довольно часто, от DeprecationWarning до массы любых других, как возможные нарушения безопасности и т.д. Это нормальное поведение и придумывать ничего не надо их можно просто отключить.

Собираем все вместе
То, что уже было сказано
Для меня самой удобной схемой работы с ошибками оказалось не перенаправление в файл, а распределения потоков вывода и ошибок в два разные файлы. Таким образом в файл с ошибками будут сыпаться ошибки, а в файл вывода - логи (таким образом удобно хранить и вести некие application-specific журналы и, например, время от времени отправлять статистику разработчику с целью повысить качество работы приложения). Таким образом, в случае возникновения ошибки пользователь увидит только окно с сообщением об ошибке и предложением посмотреть в такой-то файл с описанием ошибки, то есть с логом. Также отключим вывод предупреждений. Выглядит это примерно так:

import sys
import warnings
...
warnings.simplefilter('ignore')
...
sys.stdout = open(logs_dir.decode('cp1251') + '\\my_stdout.log'.decode('cp1251'), 'w')
sys.stderr = open(logs_dir.decode('cp1251') + '\\my_stderr.log'.decode('cp1251'), 'w')
...
app = MyApp(redirect=0)
...
Смысл декодирования из cp1251 в том, что путь к папке с логами (logs_dir) мы получили откуда-то, а так как ОС у нас Windows, да и живем мы в кириллическом мире, русские названия папок никто не отменял.


Небольшие проблемы с правами
Так уж исторически сложилось, что в Windows приложения принято устанавливать в папку "Program Files" на логическом диске с системой (в 64-битных версиях Windows есть две таких папки: "Program Files" и "Program Files x86", думаю, назначение понятно). Проблема в том, что некоторые пользователи системы могут не обладать правами администратора, поэтому логи вести в папке с приложением никак не получится, ибо ограниченный в правах пользователь не сможет писать во что-либо, находящееся в Program Files. Поэтому на помощь приходит домашняя папка пользователя (почему-то на *nix ОС это нормально, а о том, что такое же существует на Windows часто забывают =) ). Получить путь к папке очень просто:
import os
home_dir = os.path.expanduser('~')
В эту папку уже любой пользователь сможет спокойно записывать все, что ему нужно.

Комментариев нет:

Отправить комментарий

В этом гаджете обнаружена ошибка