Нет ничего постыдного в том чтобы рассказать как у меня устроено рабочее окружение и работа с Python проектами.

Прежде всего я пользуюсь операционной системой Apple OSX, это современная и удобная операционная система семейства UNIX (они так и пишут, что UNIX у них под капотом), которая до сих пор отстает от Linux по количеству мелких недочетов, и очень сильно уступает Windows по количеству "WTF" и "чезапиздец" в минуту.

Все знания которые описаны в этой статье невозможно применить на операционной системе Windows, основная причина в том, что под Windows нет и быть не может программистов, а те кто пытаются себя такими называть являются клиническими идиотами. Иногда такие люди ходят по чужим блогам чтобы получить немного унижения.

Установка python'а

Тут все просто, раньше использовал macports, теперь перешел на homebrew. Установка нужных версий выглядит всегда одинаково и удобно:

$ brew install python

После завершения установки выполнить инструкции. Если забыли что было в инструкциях, то можно прочитать еще раз:

$ brew info python

Если нужны другие версии:

$ brew install pypy python3

Если стоит несколько версий, то до того как начнете работать внутри виртуального окружения, то лучше всего работать с командами которые имеют версии в названии:

$ python2.7

Системные библиотеки

Большой грех для python программиста ставить в системную область какие-то библиотеки. Я слежу за тем чтобы системный каталог site-packages имел только самое необходимое:

  • pip
  • virtualenv
  • С недавних пор wheel

Эти пакеты надо ставить для каждой версии интерпретатора который используете.

По идее можно сделать отдельное окружение для вспомогательных утилит, но поскольку все и так под контролем, то ставлю еще pylint, ipython и httpie. Этими проектами часто удобно пользоваться из командной строки отдельно.

Некоторые пакеты могут ставить свои python биндинги в системный site-packages, тут уж ничего не поделать. Как с этим жить позже.

Защищает от соблазна следующая настройка в .profile:

export PIP_REQUIRE_VIRTUALENV=true

Она запрещает пользоваться pip вне виртуального окружения. Добавьте этот ключик и никогда не убирайте, а если понадобится обновить pylint до версии 1.0 (что случается приблизительно раз в 10 лет), то можно временно отменить эту настройку:

$ PIP_REQUIRE_VIRTUALENV= pip freeze

Никогда не делайте export PIP_REQUIRE_VIRTUALENV= потому что можно забыть что окружение уже подпорчено и установить что-то системно.

Ускорение загрузки

Даже после введения в строй всех замечательных CDN'ов и оптимизаций сделать моментальным закачку пакетов из интернета невозможно. Поэтому был придуман кэш. Работает он несколько кривовато, но прирост скорости дает приличный.

Первый шаг — это сделать папку для данных:

$ mkdir -p ~/.pip/cache

Второй, добавить нужную настройку. Делается это несколькими способами самый простой это добавить очередную переменную в .profile (либо конфиг и тогда эта переменная не нужна, но об этом позже):

export PIP_DOWNLOAD_CACHE=$HOME/.pip/cache

После этого когда pip будет пытаться скачать файл пакета, то первым делом он будет проверять есть ли такой файл локально и если да, то не будет его скачивать заново, PROFIT. Существенная проблема состоит в том, что имя файла (ключ кэша) совпадает с полным URL'ом файла скачивания, а значит если файл будет запрашиваться с другого зеркала, то он все таки будет качаться полностью. Но зато теперь когда PyPI лежит вы можете продолжать работать.

Ускорение установки

Даже если локальный кэш позволяет сэкономить драгоценное время на скачивании, то развертка проекта с десятком прямых и со зависимых библиотек представляет из себя унылое зрелище. Какие-нибудь pyyaml, pysqlite не просто копируют файлики, но еще и (ужас-ужас!) конпелируются, что приумножает скорбь многократно. Каждый раз приходится тратить минуты на развертку виртуального окружения.

Переможить это можно с помощью нового прогрессивного формата python пакетов wheel. Он более новый чем тот старый и даже сами авторы пакета утверджают, что старый не такой новый как этот новый. Этот формат бинарный (читай zip архив), поэтому старая бинарность (был zip архив) менее бинарная чем новая, а как мы все знаем бинарный всегда лучше текстового (не взирая на то что старый формат тоже не текстовый). Можете сами убедиться прочитав PEP 427, я это делать не стал, потому что концентрация переизобретения колес в этом абзаце зашкаливает, а все колеса (wheel) уже переизобретены настолько, что авторы формата пост- пост-хипстерно пост-постмодернистически назвали его колесом. Питон теперь с яйцами на колесах, летающий цирк просто какой-то.

В отличии от простой установки пакетов конвертация их в колеса требует дополнительной локальной работы, так что примеров с переменными окружения я больше давать не буду. Они актуальны для включения в сопровождающую документацию если вы ее отправляете заказчику, а для полноценной локальной работы лучше всего сделать правильный конфиг.

Положите это в файл ~/.pip/pip.conf. Обратите внимание, что предыдущие настройки уже учтены. Заодно обратите внимание на те команды у которых пути даются не относительно магической переменной ~, а полной записью, wheel настолько новая технология, что пока не умеет раскрыть путь колеса. Не забудьте создать папку:

$ mkdir -p ~/.pip/wheels

Теперь надо провести еще один ритуал для тех пакетов которые хотите ускорить — сделать колеса, автоматом пока это кажется не делается:

$ pip wheel tornado Flask ipython #... и т.д.

Установка пакетов внутри виртуальных окружений будет занимать секунды.

Есть один нюанс, если вы не указываете конкретные версии в requirements.txt, то pip все же будет ходить в интернет и проверять какая версия пакета последняя. Это значит еще по одному запросу к PyPI на пакет, если вы полностью укажете версию пакета и он окажется в кэше и к тому же еще и переупакованный как колесо, то он установится моментально.

virtualenv

Теперь работа с любым проектом выглядит так:

$ virtualenv-2.7 venv
$ source venv/bin/activate
(venv)$ pip install -r requirements.txt

Если понадобились системные пакеты:

$ virtualenv-2.7 --system-site-packages venv
$ source venv/bin/activate
(venv)$ pip install -r requirements.txt

Возможно кому-то интересно будет знать, что есть virtualenvwrapper. У меня он не прижился потому что мой стиль управления проектами не совпадает с авторскими, но возможно кто-то захочет поковырять и этот кусочек документации.

Pylint

Не могу представить себе жизнь без pylint, этот инструмент экономит безумное количество времени. Поскольку этот пост ограничивается темой настройки python окружения, то не буду описывать особенности интеграции в редактор (я пользуюсь Sublime Text 3). Основная сила этого пакета раскрывается при интеграции в редактор. Просто скажу, что когда в 4 утра вы допускаете какую-то минимальную ошибку в коде, а редактор вам ее тут же подсвечивает, то иногда это может сэкономить десятки минут времени.

Для тех кто решит потратить немного времени и установить pylint будет неожиданностью, что он достает по самым незначительным поводам. Иногда даже удивляешься, ну зачем проверять на это? Это решается отключением некоторых сообщений, рекомендую погуглить каждое исключение:

disable=W0142,W0403,R0201,W0212,W0613,W0232,R0903,W0614,C0111,C0301,R0913,C0103,F0401,W0402,R0914,I0011

Вот полный листинг файла ~/.pylintrc, в нем отредактирована одна строка, остальные настройки не существенны, поскольку все равно результат парсится скриптом интеграции в редактор.

Pylint это статический анализатор, поэтому если вы пользуетесь несколькими версиями python, то не обязательно ставить pylint в каждую версию, достаточно в одну.

Некоторые проверки могут раздражать в конкретных местах, но в целом не являются реальными проблемами. Например, если вы используете SQLAlchemy, то метод .query не виден у модели pylint'ом, обходится это добавлением локального исключения:

# Представьте себе что этот код использует модель Project 
@project.route('/<int:project_id>/setup', methods=['GET', 'POST'])
@login_required
def setup(project_id):
    # Вот оно исключение моей мечты
    # pylint:disable-msg=E1101
    p = Project.query.filter_by(login=g.user.login, id=project_id).first_or_404()

Комментарии

Оставляйте комментарии.



blog comments powered by Disqus

Support

If you like my posts, please support me on Gittip

Published

25 August 2013

In tags we trust

Fork me on GitHub