четверг, 1 декабря 2011 г.

Парсим выражение crontab

Crontab - формат файла заданий для планировщика cron. Знаменит простотой, гибкостью и мощью, позволяющими задать практически любую периодичность для выполнения заданий.

Как только выяснилось, что придется писать свой планировщик, мой взгляд сразу обратился на 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. Напишем виджет:

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 возвращает запрос следующего вида:
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. Что это такое и с чем его едят читаем в документации. А я расскажу, как тыкал это пальцем на конкретном примере.