К моему удивлению, появился некоторый интерес к моему старому посту о PyNCReport. При этом возник вопрос об ограничениях пробной версии, доступной для скачивания, и просьба показать использование PyNCReport на примерах. Примеры я приведу в отдельной статье позднее, а про лицензирование NCReport исследование провел. Итак.
class QSqliteBlog(QObject):
Блог в первую очередь для себя, для сохранения сакральных знаний о питоновских и иже с ними граблях, плюшках и т.п. Хотя, если еще кому-то окажется полезным, буду только рад.
вторник, 19 февраля 2013 г.
среда, 26 декабря 2012 г.
Рецептики: Определить все загруженные модули
Спросили на ответах Гугла. Не мудрствуя лукаво, нашел решение на stackoverflow.com и сделал его немного более pythonic:
На Python 2.7 можно немного изящнее:
Однако видим пример влияния измерительного инструмента на измеряемую величину, всегда грузится дополнительный модуль types, который также и показывается. Нужен он только для получения типа модуля types.ModuleType. А определен ModuleType прямо таки примитивно (я сразу догадался :)
И тут мы вспоминаем, что у нас всегда есть загруженный магический модуль __builtins__, и ничего не мешает его использовать:
Теперь совсем хорошо!
import types imports = dict((name, val) for name, val in globals().items() if isinstance(val, types.ModuleType))
На Python 2.7 можно немного изящнее:
import types imports = {name: val for name, val in globals().items() if isinstance(val, types.ModuleType)}
Однако видим пример влияния измерительного инструмента на измеряемую величину, всегда грузится дополнительный модуль types, который также и показывается. Нужен он только для получения типа модуля types.ModuleType. А определен ModuleType прямо таки примитивно (я сразу догадался :)
import sys ModuleType = type(sys)
И тут мы вспоминаем, что у нас всегда есть загруженный магический модуль __builtins__, и ничего не мешает его использовать:
imports = {name: val for name, val in globals().items() if isinstance(val, type(__builtins__))}
Теперь совсем хорошо!
четверг, 1 декабря 2011 г.
Парсим выражение crontab
Crontab - формат файла заданий для планировщика cron. Знаменит простотой, гибкостью и мощью, позволяющими задать практически любую периодичность для выполнения заданий.
Как только выяснилось, что придется писать свой планировщик, мой взгляд сразу обратился на crontab. Но, испугавшись кажущейся сложности его парсинга, я начал придумывать другой, возможно более слабый, но простой в реализации, механизм периодичности задач. В этом неблагодарном деле я не преуспел и, несолоно хлебавши, вернулся к кронтабу. Как оказалось, бояться там было абсолютно нечего.
Как только выяснилось, что придется писать свой планировщик, мой взгляд сразу обратился на crontab. Но, испугавшись кажущейся сложности его парсинга, я начал придумывать другой, возможно более слабый, но простой в реализации, механизм периодичности задач. В этом неблагодарном деле я не преуспел и, несолоно хлебавши, вернулся к кронтабу. Как оказалось, бояться там было абсолютно нечего.
среда, 23 ноября 2011 г.
Phonon: Я хочу, чтобы песня звучала
Опыт показывает: пользователь рабочего места, связанного со специфической периферией (автоматизированная касса, испытательный стенд, терминал сбора данных), всегда хочет звукового уведомления о ключевых событиях и нештатных ситуациях. Не миновала чаша сия и меня.
пятница, 28 октября 2011 г.
Рецептики: Проверить дробную часть
Проверить, имеет ли число ненулевую дробную часть, можно так:
>>> import math >>> x = 10.0 >>> bool(math.modf(x)[0]) False >>> x = 10 >>> bool(math.modf(x)[0]) False >>> x = 10.7 >>> bool(math.modf(x)[0]) True
Рецептики: Удалить переводы строки и возвраты каретки
Решил для разнообразия иногда публиковать мелкие посты с рецептиками.
Удаление из строки переводов строк и возвратов каретки:
Удаление из строки переводов строк и возвратов каретки:
>>> s = 'asasd\nasdasd\r\nasdasd\nasdasd' >>> ''.join(s.splitlines()) 'asasdasdasdasdasdasdasd'
PyNCReport: сборка и установка под Windows
Всякой уважающей себя учетной программе, даже самой маленькой, требуется подсистема отчетов. Ну любят клиенты бумажные отчеты. Времена, когда подсистемы отчетов писали руками и с нуля каждый под себя, слава высшему разуму, давно прошли. Сегодня разработчик ищет подходящий генератор отчета (далее репген) и прикручивает его к своему творению, чем экономит собственное время, деньги работодателя и нервы заказчика.
пятница, 14 октября 2011 г.
Очистка значений внешних ключей в модели
В предыдущем посте я благополучно боролся с отбрасыванием записей, содержащих пустые внешние ключи. Практически сразу возникла в некотором роде обратная задача - уметь очищать поля внешних ключей в модели, как в коде, так и из интерфейса (я встречал мнение, что пустые внешние ключи - грубая ошибка проектирования и этого надо всячески избегать; интересно, в каком мире эти люди живут?).
Сначала рассмотрим более сложную задачу - очистка поля внешнего ключа модели из пользовательского интерфейса. Для редактирования внешних ключей я использую QComboBox, связанный посредством QDataWidgetMapper и QSqlRelationalDelegate c QSqlRelationalTableModel. К сожалению, родной комбобокс не умеет очищать значение, поэтому придется его научить. Пусть он очищается по нажатию кнопки Delete. Очевидно, что комбобокс очистится, если установить его текущий индекс в -1. Напишем виджет:
и в дальнейшем будем использовать именно его.
К сожалению, это работает совсем не так, как ожидалось. Комбобокс действительно благополучно очищается, но при потере фокуса в модель пустое значение не попадает, восстанавливается предыдущее. В чем же дело?
Сначала рассмотрим более сложную задачу - очистка поля внешнего ключа модели из пользовательского интерфейса. Для редактирования внешних ключей я использую QComboBox, связанный посредством QDataWidgetMapper и QSqlRelationalDelegate c QSqlRelationalTableModel. К сожалению, родной комбобокс не умеет очищать значение, поэтому придется его научить. Пусть он очищается по нажатию кнопки Delete. Очевидно, что комбобокс очистится, если установить его текущий индекс в -1. Напишем виджет:
class ResettableComboBox(QComboBox): def keyPressEvent(self, event): if event.key() == Qt.Key_Delete: self.setCurrentIndex(-1) else: QComboBox.keyPressEvent(self, event)
и в дальнейшем будем использовать именно его.
К сожалению, это работает совсем не так, как ожидалось. Комбобокс действительно благополучно очищается, но при потере фокуса в модель пустое значение не попадает, восстанавливается предыдущее. В чем же дело?
пятница, 7 октября 2011 г.
Некорректный SQL-запрос SELECT в QSqlRelationalTableModel
Было замечено, что в QTableView, настроенном на QRelationalTableModel отображает не все строки таблицы, в частности строки, где значение хотя бы одного поля внешнего ключа (поля, у которых есть QRelation) равно NULL. Более того, оказалось, что эти строки отсутствуют и в модели.
Исследование показало, что QRelationalTableMode.selectStatement возвращает запрос следующего вида:
Это INNER JOIN, который действительно не выбирает строки с пустыми ссылками. Выход напрашивается - переписать selectStatement, что бы он возвращал правильный запрос, использующий LEFT JOIN. Тогда выберутся все строки таблицы.
Исследование показало, что QRelationalTableMode.selectStatement возвращает запрос следующего вида:
SELECT tbl.fld1, relTblAl_1.fld1 AS reftbl1_fld1_2, relTblAl_2.fld1, relTblAl_3.fld1, tbl.fld2, tbl.fld3, FROM tbl, reftbl1 relTblAl_1, reftbl1 relTblAl_2, reftbl2 relTblAl_3 WHERE ( tbl.fkfld1 = relTblAl_1.pkfld AND tbl.fkfld2 = relTblAl_2.pkfld AND tbl.fkfld3 = relTblAl_3.pkfld ) ORDER BY tbl.sortfld ASC
Это INNER JOIN, который действительно не выбирает строки с пустыми ссылками. Выход напрашивается - переписать selectStatement, что бы он возвращал правильный запрос, использующий LEFT JOIN. Тогда выберутся все строки таблицы.
среда, 28 сентября 2011 г.
Тюнинг вкладок QMdiArea
Главное окно проекта должно быть многодокументным и в соответствии с современным стандартом де-факто хочется отображать дочерние окна на отдельных вкладках. Для этого в качестве центрального виджета главного окна нужно использовать QMdiArea и установить режим отображения TabbedView
Все бы хорошо, но добавив одну-две вкладки начинаешь понимать, что вещь из коробки снова придется допиливать напильником:
from PyQt4.QtGui import QMainWindow, QMdiArea class MainWnd(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.setCentralWidget(QMdiArea(self)) self.centralWidget().setViewMode(QMdiArea.TabbedView)
Все бы хорошо, но добавив одну-две вкладки начинаешь понимать, что вещь из коробки снова придется допиливать напильником:
понедельник, 6 июня 2011 г.
Мелкие грабли при работе с PyWin32
Первые грабли
Возникла необходимость написать простую службу Windows. Для этой цели была избрана известная библиотека PyWin32. На просторах интернета было найдено несколько релевантных примеров и быстренько слеплена служба. Тут я напоролся на первую проблему.
суббота, 2 апреля 2011 г.
Тестирование пользовательского интерфейса в PyQt
Мне всегда была интересна тема автоматизации тестирования GUI, ибо задача, мягко скажем нетривиальная. А сейчас возник практический интерес к тестированию UI приложений на PyQT.
Как выяснилось, разработчики впихнули в QT целый фреймворк для автоматического тестирования, который в том числе умеет и эмулировать внешние действия пользователя на интерфейсе. Это называется QtTestLib. Другие разработчики не стали все это добро целиком тащить в PyQt, так как для питона и так предостаточно библиотек тестирования. А вот механизм эмуляции внешних телодвижений пользователя перенесли, спасибо.
Итак PyQt4.QtTest. Что это такое и с чем его едят читаем в документации. А я расскажу, как тыкал это пальцем на конкретном примере.
Как выяснилось, разработчики впихнули в QT целый фреймворк для автоматического тестирования, который в том числе умеет и эмулировать внешние действия пользователя на интерфейсе. Это называется QtTestLib. Другие разработчики не стали все это добро целиком тащить в PyQt, так как для питона и так предостаточно библиотек тестирования. А вот механизм эмуляции внешних телодвижений пользователя перенесли, спасибо.
Итак PyQt4.QtTest. Что это такое и с чем его едят читаем в документации. А я расскажу, как тыкал это пальцем на конкретном примере.
Подписаться на:
Сообщения (Atom)