Есть скрипт на dev-машине, есть на production. На production валится с ошибками, а на dev все работает. Окружение, вроде, совпадает. assert-ы и логгинг явных проблем не выдали и понятно, что только ими уже не обойдешься. К счастью у PyCharm есть удаленный дебаг:
- настраиваем
- запускаем дебаггер на dev-машине, а скрипт на production.
- ????
- ЭВРИКА!
(Как оказалось в итоге, окружения все таки не совпадали и я нашел модуль, который гадил в чужие пространства.)
Удаленный debug в PyCharm пока все же имеет некоторые ограничения:
- пути до скриптов на разных машинах могут отличаться и это нормально. Для этого PyCharm предлагает настроить соответствие этих путей. Это работает пока не надо спуститься в глубь third-party библиотек, которые в случае того же virtualenv так же могут лежать по разным путям. Тут приходится выбирать что отлаживать: скрипты или чужие библиотеки, но не одновременно
- окружение (точнее тот срез, с которым мы должны работать) должно совпадать на 100%
Наверно можно было бы еще на самом сервере через pdb сделать, но PyCharm сработал и дальше я не копал
PyCharm
За полтора месяца государственная машина раскрутилась и бюджет России опустел на $200 долларов, чтобы купить PyCharm (на это пошли наши налоги!), которым я уже пользуюсь как раз два месяца.
У меня раньше не было опыта с IDE для Python (да их вообще мало). Я пробовал Python для NetBeans (который в 7-й версии не работает и его делают заного). Там была подсветка синтаксиса, интеграция с системами контроля версий и все. Учитывая сколько памяти жрет Java использовать NetBeans было нерационально. Поэтому я полгода работал с gedit и делал все то же самое (работу с SVN освоил с консоли).
А вот PyCharm заточен именно под Python и, что тоже важно, под Django (работа с шаблонами, готовые шаблоны кода). Он тоже на Java и тоже жрет кучу памяти, но с 6Gb на рабочей машине работать уже можно без проблем.
Из того, что я пользуюсь:
- подсветка года
- автоматический импорт и очистка импорта
- автоматическое создание видов и шаблонов
- подсветка ошибок и несуществующих файлов
- автодополнение (переменные, параметры функций, ...)
- рефакторинг! (перенос функций и классов в другие модули с необходимым импортом)
- встроенный дебаггер.
- SVN/git, diff
- работа с отдельными списками правок в SVN/git
- быстрая навигация по структуре файла и кода (суперклассы, дочерние классы, место объявления переменной)
- синтаксический анализатор кода (правила хорошего тона, чтобы ваш код был гладкий и шелковистый)
- встроенная работа с gettext
- чтобы в списках изменений минимальной единицей была правка, а не файл
- системный рендеринг шрифтов в Linux
Рабочий процесс:
Откровение девелопера
За последние несколько дней освоил дао postgres views & rules прицепленных к django-моделям для создания прозрачных many-to-many и one-to-one цепочек.
Задача проста: нам нужно вычисляемое поле на модели. Через django-ORM его вычислить не получиться. Считать для каждой записи может быть долго. Поэтому это дело выносится в слой БД. CREATE VIEW... и работа закипела.
На выходе мы должны получить вид с двумя (1 + кол-во вычисляемых полей) колонками. Первая колонка —связь one-to-one с родительской таблицей, остальные по вкусу. Связь надо только назвать по шаблону родительскаятаблица_ptr_id или прописать в дочерней модели поле вручную.
При помощи CREATE RULE можно поставить заглушку на удаление записей. Или даже не заглушку, а более умное действие, чтобы можно было прямо удалять из дочерней таблицы не задумываясь. INSERT/UPDATE по желанию.
Аналогично можно создать «фиктивные» m2m. Связать таблицы, которые явно с друг-другом не связаны, например. Создаем вид с двумя колонками (ссылки на первичные ключи связываемых таблиц) и в одной из моделей добавляем ManyToManyField.
CREATE RULE ON DELETE тут нужно прописывать явно, так как django обязательно будет пытаться удалить связь из этого вида при удалении записей из связываемых таблиц.
Django и ODF (ODS, ODT)
Вроде OpenOffice весь из себя формат открытый-преоткрытый, свободный-пресвободный, но функциональной библиотеки для генерации документов я не нашел. Нужный функционал только в самом OpenOffice, к которому можно цепляться по сетевому протоколу.
Но на наше счастье внутри ODF сидит обычный xml (плюс пара файлов и все это обернуто в zip).
Поэтому результат вышел даже лучше чем планировал.
- Шаблон документа можно подготовить в самом openoffice;
- Распаковать odf-документ, извлечь content.xml;
- подстановку переменных и повторение строк можно поручить обычным таким шаблонам django;
- собрать zip-файл с content.xml, блэк-джеком, манифестом и mime можно на лету средствами стандартной библиотеки python;
Личный профит: шаблоны можно теперь не рисовать самому, а поручить кому-нибудь другому
Теперь надо обкатать технологию и попробовать как-нибудь скрестить с генерацией PDF
В копилку валидатор, который помог в отладке.
Ради соблюдения DRY-принципа в ход пошли уже метаклассы.
Зато если что теперь и поломается, то строго в одном месте.
Основная опасность в Django при создании чего-нибудь более крупного, чем сайт визитка — это возможность увлечься метапрограммированием, вместо создания полезного кода. Тем более, что Python с его богатыми ООП и интроспекцией этому только способствует.
Но на самом деле такой подход очень даже и верный. Он помогает здорово структуировать программу и писать реюзабельный код и не рвать через год на себе волосы, пытаясь понять как же это все работает.
Но не в условиях дедлайна. Хотя еще остается шанс «день потерять, зато за час долететь», на что я и надеюсь, посвятив уже целые рабочие сутки на рефакторинг форм, написание абстрактных фабрик классов и хитрых примесей.
PyCharm
Еще до того как в NetBeans 7 вырезали поддержку Python (потом добавили плагином, который лежит еще где-то в dev-репах) я перестал им пользоваться. Уж больно тяжелая эта Java
Но gedit, конечно, хорошо, но как минимум грамотного рефакторинга, быстрого перехода между файлами и других не таких уж мелочей там не хватало.
И тут я скачал и попробовал PyCharm, благо у него 30 дней пробного срока имеется.
По описанию, IDE резко заточено под Python и, что самое приятное, поддержка Django у них тоже приоритетна. После двух дней становится ясно, что надо брать. Есть и рефакторинг и переход между вьюхами-шаблонами, классами-суперклассами, импорт, автозаполнение параметров функций, методов, шаблонных тегов и всего остального, подсветка ошибок. Распознает модели django, в том числе как и явно указанные поля, так и то, что появляется по FK/m2m связям из RelatedManager.
И наконец-то я могу дебажить Python, а не разбрасывать assert-ы где попало
Наверняка еще много чего полезного там есть. За два дня не найдешь всего.
Конечно, опять Java и уже почти 700Mb оперативы и с хинтингом шрифтов Java на Линуксе не хочет дружить, но пока плюсы перевешивают
Начальству обрисовал цель, что неплохо бы заиметь коммерческую лицензию.
Кроме того у них есть PhpStorm для PHP, WebStorm для HTML, RubyMine для Ruby и Rails, IDEA для Java (и Android из коробки) и IDEA Ultimate, где есть все осразу и дешевле чем по отдельности.
DOC / RTF / ODT / … -> HTML / PDF / DOC / ODT / RTF / …

Немного рабочих моментов и полезного кода. Может кому пригодиться.
Конвертируем все что угодно в что-то другое с помощью OpenOffice/LibreOffice. Понадобилось тут автоматизировать наконец это дело.
Первая рабочая версия. Дальше уже можно пилить по вкусу.
Принцип работы — uno. Первый раз слышу. Похоже на COM в Windows. Запускает OpenOffice в фоне и общается с ним по TCP.
# -*- coding: utf-8 -*- #!/usr/bin/env python # Copyright (C) 2011 DMZ <dmz@the-island.ru> # Licensed under the GNU LGPL v2.1 - or any later version. from ooutils import oo_properties as oop, OORunner from optparse import OptionParser, OptionValueError import sys import re import os from unohelper import systemPathToFileUrl from com.sun.star.beans import PropertyValue # http://wiki.services.openoffice.org/wiki/Framework/Article/Filter/FilterList_OOo_3_0 CONVERT = { 'html': 'HTML (StarWriter)', 'xhtml': "XHTML Writer File", 'rtf': "Rich Text Format", 'doc': "MS Word 97", 'odt': "StarOffice XML (Writer)", 'pdf': "writer_pdf_Export", } def read_format(option, opt, value, parser): value = value.lower() if value not in CONVERT: formats = ', '.join(CONVERT.keys()) raise OptionValueError( 'Формат вывода не поддерживается. Доступные форматы: %s' % formats) setattr(parser.values, option.dest, CONVERT[value]) if __name__ == '__main__': parser = OptionParser() parser.add_option('-i', '--input', dest='input') parser.add_option('-o', '--output', dest='output') parser.add_option('-f', '--format', action='callback', type='string', callback=read_format, dest='format', default=CONVERT['html']) (options, args) = parser.parse_args() if not options.input: print >>sys.stderr, u"Укажите месторасположение входящего файла (-i)" sys.exit(1) if not options.output: print >>sys.stderr, u"Укажите месторасположение итогового файла (-o)" sys.exit(1) odir = os.path.dirname(options.output) if not os.path.isdir(odir): print >>sys.stderr, u"Путь для сохранения (%s) не существует" % odir sys.exit(1) if not os.path.isfile(options.input): print >>sys.stderr, u"%s: Указанный файл не существует" % options.input sys.exit(1) oor = OORunner() desktop = oor.connect() document = desktop.loadComponentFromURL(systemPathToFileUrl(options.input), "_blank", 0, oop(ReadOnly=True, Hidden=True)) print u"Сохраняем документ в %s" % options.output document.storeToURL(systemPathToFileUrl(options.output), oop(Overwrite=True, FilterName=options.format)) document.close(True) oor.shutdown()
ooutils можно взять тут и сохранить в отдельный файл (положить или в папку со скриптом или в питоновские пути)
Фикс для нахождения LibreOffice (amd64):
# Find OpenOffice. _oopaths=( ('/usr/lib64/libreoffice/program', '/usr/lib64/libreoffice/program'), )
Пример: python o2o.py -i document.odt -o document.pdf -f pdf
Сегодня я узнал о Python PEP342. Нужно срочно найти этой фиче какое-нибудь интересное (и практическое) применение
